Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ to follow [Semantic Versioning](https://semver.org/) as the public API matures.

## [Unreleased]

## [0.19.0] - 2026-08-06

### Added

- Immutable renderer-neutral application configuration values with validated
Expand Down Expand Up @@ -143,6 +145,13 @@ to follow [Semantic Versioning](https://semver.org/) as the public API matures.
Quitting the TUI left scanner, PSI, RTSP/RTP audio, router, and daemon
ownership running. Controlled `SIGTERM` then removed all three sockets.

- A daemon deployment and upgrade guide covering preserved naming
compatibility, dedicated service accounts, systemd supervision, private socket
access, destination manifests, transactional reload, migration, clean
installation, upgrades, and rollback.
- Validated the repository's existing GitHub CodeQL default setup for Actions
and Python against the release pull-request head with no analysis errors.

### Changed

- `sdsctl` now resolves application settings from built-in defaults,
Expand Down Expand Up @@ -701,7 +710,8 @@ First planned GitHub prerelease.
- Added serial discovery, transport, packet framing, core responses, CLI tools,
examples, tests, and CI.

[Unreleased]: https://github.com/stevenboyd78/sds200-python/compare/v0.18.0...HEAD
[Unreleased]: https://github.com/stevenboyd78/sds200-python/compare/v0.19.0...HEAD
[0.19.0]: https://github.com/stevenboyd78/sds200-python/compare/v0.18.0...v0.19.0
[0.18.0]: https://github.com/stevenboyd78/sds200-python/compare/v0.17.0...v0.18.0
[0.17.0]: https://github.com/stevenboyd78/sds200-python/compare/v0.16.1...v0.17.0
[0.16.1]: https://github.com/stevenboyd78/sds200-python/compare/v0.16.0...v0.16.1
Expand Down
15 changes: 11 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ subscription is created. Frames preserve RTP sequence, timestamp, SSRC,
continuity estimates, observation time, endpoint, raw payload bytes, and
cumulative loss caused by that client's bounded queue.

Stop the process with `Ctrl+C` or `SIGTERM`. Shutdown first closes API clients,
Stop the process with `Ctrl+C` or `SIGTERM`. Shutdown first closes API clients, then stops daemon-owned destinations,
then stops scanner, PSI, audio, and router ownership, closes PCMU clients, and
finally closes event clients after final lifecycle transitions. All three owned
sockets are removed.
Expand Down Expand Up @@ -355,9 +355,15 @@ a valid 53.120-second 8 kHz mono WAV with an adjacent metadata sidecar. Quitting
the TUI left scanner, PSI, audio, router, and daemon ownership healthy. A later
controlled `SIGTERM` removed `daemon.sock`, `events.sock`, and `pcmu.sock`.

Decoded-PCM subscriptions, automatic daemon selection, and destination
activation remain follow-on work. The initial daemon router has no attached
destinations. See the
The daemon loads the explicit `--destination-config` path or
`${XDG_CONFIG_HOME:-~/.config}/sdsctl/daemon-destinations.toml` before opening
scanner hardware. Saved playback, recording, and remote-profile destinations are
activated under daemon ownership. `SIGHUP` transactionally reloads that exact
manifest while preserving the previous committed set on failure.

Decoded-PCM subscriptions and automatic daemon selection remain follow-on work.
See the
[daemon deployment and upgrade guide](docs/daemon-deployment.md),
[daemon runtime and process guide](docs/daemon-runtime.md),
[local daemon API guide](docs/daemon-api.md),
[local daemon event stream guide](docs/daemon-events.md),
Expand Down Expand Up @@ -707,6 +713,7 @@ See [SECURITY.md](SECURITY.md) for vulnerability reporting and
- [Reliability and observability](docs/reliability.md)
- [Operational logging](docs/logging.md)
- [Textual TUI](docs/tui.md)
- [Daemon deployment and upgrades](docs/daemon-deployment.md)
- [Foreground daemon and ownership runtime](docs/daemon-runtime.md)
- [Local daemon API](docs/daemon-api.md)
- [Local daemon event stream](docs/daemon-events.md)
Expand Down
121 changes: 43 additions & 78 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,50 +9,38 @@ The broader product direction, architectural constraints, deferred capabilities,
and ideas that are not ready for scheduling are recorded in
[the project vision](docs/project-vision.md).

## Recently completed milestone
## Active milestone

### Milestone 19.8Safe daemon controls
### Milestone 19.12v0.19.0 release

- **Capability-checked control operations — implemented**
- Added explicit version 1 daemon operations for hold, next, previous, and
reconnect without unrestricted raw scanner-command passthrough.
- Reused typed scanner navigation contracts, model capability checks, strict
targets, bounded counts, and structured scanner acknowledgements.
- Preserved every read-only operation and standalone CLI/TUI behavior.
- Did not add resume because no documented or verified resume/unhold scanner
wire contract exists.
- **Serialized execution and authoritative completion — implemented**
- Added one nonblocking daemon mutation slot so conflicting clients receive
`control_busy` instead of interleaving or building a queue.
- Successful responses follow scanner acknowledgement and include an ordered
`DaemonControlResult` with timestamps and an authoritative runtime snapshot.
- Applied one maximum two-second request budget to runtime-lock acquisition and
scanner completion.
- Raised the default API worker shutdown deadline to three seconds and added
rejection of configurations that cannot outlast the maximum request duration.
- Limited daemon reconnect to the directly owned bounded SDS200 UDP transport;
serial, fallback, replay, and injected transports return
`unsupported_operation`.
- **Safety, isolation, and observability — implemented**
- Added structured redacted `control_busy`, `control_unavailable`,
`unsupported_operation`, `control_timeout`, `control_rejected`, and
`control_failed` responses.
- Kept resulting scanner and runtime changes observable through authoritative
snapshots and the existing ordered event stream.
- Preserved private socket permissions, bounded clients, worker isolation, and
the single-owner scanner lifecycle.
- **Regression, documentation, and hardware validation — complete**
- Added regression coverage for success, strict parameters, scanner rejection,
timeouts, unsupported transports, concurrent controls, shutdown, and
unchanged read-only behavior.
- Documented envelopes, completion semantics, deadlines, exclusions,
compatibility, and client responsibilities.
- Physically validated TGID hold, next, previous, hold release, and bounded
reconnect against an SDS200 while API, event, PSI, RTSP/RTP, decoded-audio,
and two PCMU clients remained healthy.
- Confirmed ordered control sequences, reversible hold state, reconnect
connection transitions, loss-free matching PCMU delivery, controlled
`SIGTERM`, successful process exit, and removal of all owned sockets.
- **Compatibility, migration, deployment, and systemd documentation — complete**
- Documented preserved distribution, import-package, executable, and legacy
profile compatibility.
- Documented explicit destination manifests, service accounts, private
sockets, `SIGHUP` reload, systemd operation, upgrades, and rollback.
- **Acceptance validation — complete**
- Passed adversarial regression validation for multiple, slow, malformed, and
excess clients plus shutdown fault injection.
- Passed final Ruff, MyPy for 74 source files, all 1,267 tests on Python
3.14.4, documentation checks for 34 Markdown files, version `0.19.0` source
and wheel builds, Twine checks, artifact inspection, clean installation, and
public PyPI `0.18.0` to local `0.19.0` upgrade validation.
- Passed the full Python 3.11–3.14 GitHub Actions matrix and the repository's
existing CodeQL default setup for Actions and Python with zero findings and
no analysis errors.
- Completed physical SDS200 daemon-owned CLI and TUI validation against
firmware `1.26.01`, including private sockets, simultaneous clients,
canonical `stream.snapshot` delivery, loss-free PCMU reception, valid WAV
and metadata output, daemon-owned reconnect, retained ownership after TUI
exit, and orderly shutdown with all sockets removed.
- **Publication — pending**
- Merge release preparation only after CI and CodeQL pass.
- Publish `v0.19.0` through trusted PyPI publishing and create the GitHub
release.
- Verify a clean installation from public PyPI.

Keep the existing Python distribution and import package compatible until a
separate migration plan justifies a rename.

## Deferred hardware validation

Expand All @@ -77,42 +65,6 @@ fixture-tested, not hardware-validated.
These milestone groups preserve intended future work. Their numbering and release
assignment may change before implementation begins.

### Milestone 19.9 — CLI daemon client

- Add daemon status, snapshot, event-watch, safe-control, and optional audio
client workflows.
- Preserve explicit daemon and standalone selection with clear absent,
incompatible, and disconnected daemon diagnostics.
- Use the CLI migration to validate protocol compatibility before TUI adoption.

### Milestone 19.10 — TUI daemon client

- Consume daemon snapshots, ordered events, controls, and daemon-owned audio.
- Preserve an explicit standalone mode and show daemon protocol, connection,
reconnect, and degraded-state information.
- Ensure closing or reconnecting the TUI never stops the daemon-owned scanner
session.

### Milestone 19.11 — Destination activation and reload

- Activate saved playback, recording, and remote-stream destinations under daemon
ownership.
- Define validated, previewable configuration replacement and failure-isolated
destination updates.
- Use `SIGHUP` to load, validate, and transactionally replace the selected
destination manifest while preserving the previous committed set on failure.

### Milestone 19.12 — v0.19.0 release

- Complete compatibility, migration, deployment, and systemd documentation.
- Validate multiple clients, slow and malformed clients, shutdown fault
injection, clean installation, and upgrade behavior.
- Run full Python 3.11–3.14 CI and CodeQL validation plus physical SDS200
daemon-owned CLI and TUI client testing.

Keep the existing Python import package compatible until a separate migration
plan justifies a rename.

### Milestone 20 — Web dashboard and Home Assistant

- Add a responsive browser dashboard backed by the daemon API.
Expand Down Expand Up @@ -305,3 +257,16 @@ fixtures before renderer-specific implementation.
helpers, documentation, extensive regression coverage, a reusable hardware
validator, and physical SDS200 validation with simultaneous API, event, and
dual-PCMU clients.
- Milestone 19.8: capability-checked hold, next, previous, and bounded reconnect
controls; serialized mutation ownership; scanner-acknowledged completion;
stable redacted failures; regression coverage; and physical SDS200 validation.
- Milestone 19.9: explicit daemon CLI status, snapshots, safe controls, ordered
event watching, PCMU playback and WAV recording, protocol compatibility, and
physical SDS200 validation.
- Milestone 19.10: explicit daemon-backed TUI state, events, controls, playback,
recording, and saved-recording workflows without opening scanner hardware or
stopping daemon ownership, plus physical SDS200 validation.
- Milestone 19.11: validated playback, recording, and remote-profile destination
manifests; deterministic activation resources; transactional replacement;
failure-isolated reload; daemon lifecycle ownership; `SIGHUP`; regression
coverage; and physical SDS200 validation.
16 changes: 12 additions & 4 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,11 @@ The optional application configuration files are:
- system: `/etc/sdsctl/config.toml`;
- user: `${XDG_CONFIG_HOME:-~/.config}/sdsctl/config.toml`.

Path resolution also defines these locations for future persistent services:
The default daemon destination manifest is:

- `${XDG_CONFIG_HOME:-~/.config}/sdsctl/daemon-destinations.toml`.

Path resolution also defines persistent service locations:

- state: `${XDG_STATE_HOME:-~/.local/state}/sdsctl/`;
- cache: `${XDG_CACHE_HOME:-~/.cache}/sdsctl/`.
Expand Down Expand Up @@ -154,6 +158,10 @@ The version 1 application schema contains no credential-bearing fields. Unknown
fields are reported by name and source, not by value.

Saved remote-audio destinations continue to store environment-variable secret
references rather than resolved passwords. Resolved credentials must not be
written to application configuration, logs, exceptions, traces, or serialized
output.
references rather than resolved passwords. The daemon destination manifest
selects those profiles by name and never stores resolved credentials. Resolved
credentials must not be written to application configuration, destination
configuration, logs, exceptions, traces, or serialized output.

See [Daemon deployment and upgrade guide](daemon-deployment.md) for systemd,
destination-manifest, service-account, migration, and upgrade examples.
6 changes: 4 additions & 2 deletions docs/daemon-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -436,5 +436,7 @@ Ordered events are available through their dedicated socket and
`pcmu.sock` and `sdsctl daemon-client audio`. The daemon-backed TUI obtains its
authoritative initial state and safe-control results through this API while
ordered updates and PCMU audio remain on their dedicated sockets. Decoded-PCM
CLI workflows, discovery, and destination activation remain assigned to later
Milestone 19 work.
Automatic daemon discovery and decoded-PCM client workflows remain
follow-on work. Explicit CLI and TUI daemon clients, saved destination
activation, and transactional `SIGHUP` destination reload are part of the
current daemon contract.
Loading