An operation that no longer exists
Every claim in this section reduces to one fact: the voice worker's dispatch has five branches and
subscribe_ambient is not among them. Sending it produces
{"ok": false, "error": "unknown op: subscribe_ambient"} and the connection closes.
| Location | What it says | Reality |
|---|---|---|
README.md:68, 108, 118 | “New: dedicated reader thread + subscribe_ambient op”; the gateway “opens a long-lived subscribe_ambient connection per WebSocket” | No reader thread, no op. A separate AmbientListener connects straight to the agent. |
ARCHITECTURE.md §3.2, §3.3, glossary | a full code listing of the subscribe_ambient handler, an _ambient_pump with a 1.2 s idle readline, and a _route_event fan-out function | None of those functions exist in the tree. |
gateway/server.py:2810–2835 | a 25-line comment block titled AMBIENT PUMP describing steps 1–4 of the removed design | Sits directly above _make_ambient_callback, which implements the replacement. |
voice-daemon/jcode_voice_worker.py:78–87 | “Event types forwarded by the subscribe_ambient handler” and the AMBIENT_FORWARDED set | The set is defined and referenced nowhere in the file. |
gateway/server.py:3004–3010 | _start_ambient_pump — the docstring itself admits “Name kept for backwards compatibility with call sites” | correctly labelled |
The last row is the exception that proves the rule: where the author touched the code, the comment was fixed. The drift is concentrated in the two documents nobody has to open in order to change behaviour.
The one test written for this feature cannot pass
scripts/test_ambient_drain.py is a four-step end-to-end smoke test: create a session,
open a second socket and subscribe, drive a background subagent through
jcode debug, then assert that at least three text_delta events arrive
containing the expected phrase. Step two sends op=subscribe_ambient at line 82. It also
waits for a "subscribed" acknowledgement event that no code path in the repository
emits, and hard-codes /home/user/ paths for the worker socket, the agent socket
and the jcode binary — while every other path in the tree uses
/home/user/. The script prints FAIL.
Separately, ambient_listener.py:27 cites
scripts/test_passive_subscriber.py as the empirical evidence for the design's central
assumption. scripts/ contains one file, and that is not it.
What an installed wheel would not contain
pyproject.toml declares a console script, eight dependencies and a package-discovery
rule. The rule includes always_assistant* and gateway*. It does not include
voice-daemon — which cannot be a package anyway, because a hyphen is not a legal Python
identifier. The gateway imports from it at runtime by mutating sys.path.
uvicorn gateway.server:app with a
WorkingDirectory pointing at a checkout, and the README's deploy procedure is six
rsync and systemctl restart invocations over SSH. The two views were never
reconciled because only one of them is ever used.Code that is present and unreachable
A working personal system accumulates strata. Naming the layers is the difference between reading this repository quickly and reading it twice.
| Item | Where | Evidence it is dead |
|---|---|---|
AMBIENT_FORWARDED | jcode_voice_worker.py:81–87 | defined; zero other references in the file |
_AMBIENT_IDLE_FLUSH_S = 1.2 | gateway/server.py:2847 | five-line explanatory comment; one occurrence in the tree, the definition |
--toolsets, --max-turns | jcode_voice_worker.py:969–970 | parsed by argparse, never read afterwards |
src/message_notifications.rs | jcode root src/ | 207 lines, its own copy of the notification formatter without the subagent branch; no mod declares it |
src/protocol/notifications.rs | jcode | src/protocol.rs is a single pub use line and never declares the module |
| Injection point “A” | crates/jcode-protocol/src/lib.rs:865 | documented in a doc comment as “after stream”; the string is never emitted by any code path |
reasoning_delta forwarding | worker + listener event sets | no such variant exists in ServerEvent |
memory_worker.py | voice-daemon/ | 77 lines, no systemd unit, no importer, no CLI reference |
pi_voice_worker.py | voice-daemon/ | the Pi Agent RPC predecessor; zero references repository-wide |
hermes_voice_worker.py | voice-daemon/ | the Hermes CLI predecessor; referenced only by a dead path string |
bin/hermes-voice | bin/ | drives hermes-voice-daemon.service; the shipped unit is pi-voice-daemon.service |
worker --socket default | jcode_voice_worker.py:968 | defaults to pi-worker.sock; systemd and the gateway both use jcode-worker.sock |
Two smaller numeric discrepancies, for completeness. ARCHITECTURE.md puts Kokoro on
:8881 in two places; the shipped unit and the configuration default are both
:8880. And both documents install the patched binary into a directory named
0.12.3-dev-always-features, while jcode/Cargo.toml declares
version = "0.12.2". The architecture document also cites the injection banner at
turn_streaming_mpsc.rs:1044; it is on line 1045.
What actually works
None of the above means the system does not run. It means the map is older than the territory. Judged only from the tree, this is the state of each subsystem:
| Subsystem | State | Basis |
|---|---|---|
| Capture, VAD, filter cascade | implemented | complete path; the VAD gate has a documented fail-closed default; three unit tests cover audio utilities |
| Foreground turn + streaming TTS | implemented | the bulk of the 74 tests in test_gateway.py exercise this path, including cancellation and replay |
| Ambient narration (Python) | implemented | AmbientListener is wired in and covered by tests using a FakeAmbientListener double |
| Background subagent (Rust) | implemented, untested | no test constructs SubagentOutputMode::Background; the 256,000-byte inline branch has no coverage |
| End-to-end ambient proof | broken | scripts/test_ambient_drain.py targets a removed op and a foreign host's paths |
| Barge-in arbitration | implemented | symmetric WebSocket and WebRTC handlers; both outcomes are explicit frames in the replay allow-list |
| Authentication | implemented | bearer, per-device and signed-ticket paths all live in gateway/server.py |
| WebRTC transport | partial | a single one-shot offer endpoint with the full control vocabulary; no ICE trickle endpoint |
| Device registry / multi-device | partial | records, tokens, staleness expiry and a watchdog exist; one agent process serves all of them |
| Observability | absent | seven per-turn floats and [STAGE] log lines; no exporter, no aggregation |
| Desktop delegate | standalone | a complete EvoCUA computer-use CLI; grep finds no reference to it from the gateway, the worker or the assistant package |
| Level / waveform display | absent | one RMS scalar written to a <span>; no AnalyserNode or canvas anywhere |
“The earlier attempt merged ambient listening INTO the chat client's connection pool … That hung because…”voice-daemon/ambient_listener.py, line 29 — the only place in the repository where a rejected design is written down and explained
That docstring is the single most valuable artefact in the tree, and the reason the drift is
recoverable at all. A reader who opens the two Markdown documents first will build an accurate mental
model of a system that was deleted. A reader who opens ambient_listener.py first is told,
in the first forty-five lines, what the problem was, what was tried, why it failed, and what replaced
it. The documentation is stale; the code is not silent about it.