tests/test_capture.py builds a DirectSniffer, whose lazy import reaches
simtrace2_pysniff.device -> usb.core; the runner has no PyUSB, so two tests
failed there while passing on a workstation that already had it. The job now
installs the declared runtime dependency next to build.
The artifacts and the GitHub release were made by hand (`python -m build` plus
`gh release create`). `.github/workflows/release.yml` now does it from the
pushed tag: Python and PWA tests, the sdist/wheel build, a check that the
wheel carries the PWA, an install-and-serve smoke test of that wheel, and
`gh release create` with the generated notes (prepended by
`.github/release-notes.md`) and the three assets (wheel, sdist, udev rule).
A `workflow_dispatch` run does everything except publish, so the pipeline can
be exercised without minting a release; the artifacts land in the run. A tag
that does not match version.py/PWA_VERSION fails before anything is published.