Assemble Remote speech before reader delivery

This commit is contained in:
ak47 committed 2026-11-04 14:33:54 -05:00
1 parent f23e89ed93
commit 205cb27483
9 files changed
+492 -33

No files matched your search

+44 -13
View File
@@ -2,7 +2,10 @@
This increment adds typed speech IPC and an explicit reader-owned mailbox. It
does not connect the speech worker, observe local output, or make Remote speak.
The external source command remains relay-only. Base reader revision: `4f9b89e`
The external coordinator now connects this IPC to relay speech; the production
reader still has no presentation owner or output observer. The current increment
adds atomic assembly of split incoming utterances before owner admission.
Original base reader revision: `4f9b89e`
on `testing`; matching Tentacles base: `0c74038` on `master`, plus the pending
connection-command changes. No active or installed reader was replaced.
@@ -26,13 +29,35 @@ Child `remote.present` takes `RemotePresentation`: lease, epoch, monotonically
increasing operation sequence and speech. The sequence is shared with heartbeat
and close. Admission requires a live controller lease with `remote-present`.
Without a reader owner calling `Session.EnableRemoteSpeech`, it returns `-32601`.
The queue holds at most 64 items, never blocks the IPC reader, and preserves FIFO
speech/cancel/pause order. Overflow revokes the entire lease and returns `-32002`;
it cannot drop a cancel while admitting newer speech. Speech does not refresh
the heartbeat deadline.
The queue never blocks the IPC reader and preserves FIFO speech/cancel/pause
order. Across incomplete assemblies, queued deliveries and work in flight, each
lease retains at most 64 speech frames and 256 KiB of canonical speech JSON.
Overflow revokes the entire lease and returns `-32002`; it cannot drop a cancel
while admitting newer speech. Speech does not refresh the heartbeat deadline.
For split speech, `RemotePresentation` also accepts `utterance` and `final`.
Omitting both retains the single-call contract. A nonzero utterance identifies
one assembly and equals the first fragment's operation sequence. Later fragments
carry that same identifier and a strictly increasing operation sequence; the
last sets `final: true`. Only speak can be grouped, and every fragment must have
the same priority. Heartbeats may advance the shared sequence between fragments.
Only one assembly may be pending; interleaved effects, changed identifiers or
priorities return `-32602` without committing a prefix or consuming the sequence.
Replay still returns `-32001`. Null/unknown fields and invalid grouping metadata
are rejected; both SDKs expose matching presentation validators.
No fragment reaches the owner before the final call succeeds. Finalization
queues one delivery containing every frame, in order. An unfinished assembly
stays bounded until completed or its lease ends; it has no independent renewal
or retry. Revocation, replacement, close, policy cancellation, process loss and
heartbeat expiry discard it. No relay protocol extension is involved.
The owner receives `RemoteSpeechDelivery` containing a cancellation context,
lease and validated speech. It must select session shutdown, check the context
lease, `Speeches` slice and idempotent `Release` callback. The slice is one
complete effect/utterance; apply priority once, preserving all fragment states
and boundaries. The owner must call Release after delivery or discard and drop
its references. Dequeue alone does not return budget; stale releases cannot
debit a replacement lease. It must select session shutdown, check the context
and `RemoteContext` at delivery, apply focus/secure-input/speech policy, keep
remote cancellation separate from local status, and mark remote origins so they
cannot be observed again. Revocation immediately cancels contexts and drains
@@ -52,18 +77,24 @@ Tentacle must recheck lease/epoch and peer readiness before sending over a relay
Run from this checkout:
```sh
GOCACHE=/tmp/cthulhu-cache GOPROXY=off go test -race ./internal/tentaclewire ./internal/tentacle ./sdk/... -count=1
GOCACHE=/tmp/cthulhu-cache GOPROXY=off go test -race ./internal/tentaclewire ./internal/tentacle ./sdk/... -count=1 -timeout=240s
```
Real Go/Python child processes cover typed speech and observed events, absent
owners, role/grant denial, replay, ordering, revocation and queue overflow.
Shared validation cases cover null/type/unknown-field rejection and escaped
byte bounds. Existing lifecycle/SDK tests exercise old 1.0 behavior, process
failure, timeout, event overflow and installation contracts.
Shared validation cases cover null/type/unknown-field rejection, grouping
metadata and escaped byte bounds. Assembly tests cover no-prefix admission,
interleaving, replay, priority consistency, heartbeats, in-flight accounting,
idempotent/stale release, byte/frame overflow and retirement. A private TLS
fixture in `TestRemoteConnectionCommandPrivateRelay` also passes long escaped
multilingual speech through the actual source command and reader host to one
complete test-owner delivery. Existing lifecycle/SDK tests exercise old 1.0
behavior, process failure, timeout, event overflow and installation contracts.
Next: connect the policy-resolved speech worker and the external coordinator,
with origin ownership, secure/secret exclusion, delivery-time policy, local
priority, cancellation generations and atomic treatment of split utterances.
Next: connect the policy-resolved speech worker with origin ownership,
secure/secret exclusion, delivery-time policy, local
priority and cancellation generations. Atomic IPC assembly is implemented;
it does not establish backend priority/cancel behavior or audible delivery.
Pause support or cancel-on-pause behavior and NVDA priority fidelity must be
resolved there. The codec transports metadata without claiming backend behavior.
Then verify normal reading, key echo, read-all, spelling, speech modes and local