Tentacle enhancements.

This commit is contained in:
Storm Dragon committed 2026-11-04 13:44:13 -05:00
1 parent 4f9b89e38b
commit 9e15f8652d
12 files changed
+619 -22

No files matched your search

+71
View File
@@ -0,0 +1,71 @@
# Remote speech transport prerequisite
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`
on `testing`; matching Tentacles base: `0c74038` on `master`, plus the pending
connection-command changes. No active or installed reader was replaced.
## Wire data and ownership
`RemoteSpeech` has `kind` (`speak`, `cancel`, `pause`), optional `priority`
(normal=0, next=1, now=2), `parts`, and optional `paused` boolean. Speak requires
1–128 parts and forbids paused. Cancel forbids parts, nonzero priority and paused.
Pause requires paused and forbids parts and nonzero priority. Unknown fields,
nulls and malformed types are rejected by both SDKs.
Each part is either text with resolved `characters` and `language` state, or
`end: true` alone. Whitespace is significant. Language is empty for the configured
default, or up to 64 ASCII letters, digits, hyphens and underscores. No voice
path, backend command, sound file, object identity or arbitrary method is accepted.
The canonical Go JSON representation is limited to 6144 bytes including escaping;
the enclosing call retains its existing 8192-byte parameter and 64 KiB frame
bounds. Python validates the same canonical byte bound.
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 owner receives `RemoteSpeechDelivery` containing a cancellation context,
lease and validated speech. 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
pending mailbox items. A context may be cancelled after dequeue: dequeue is not
authorization to speak later.
For export, core calls `PublishRemoteSpeech` with a live controlled lease,
`output-observe`, and trusted origin `local`. Other origins are rejected. Core
must exclude password/secret output and supply only policy-resolved local output;
there is no child RPC that publishes an observed event. The method queues
`remote.output` with lease, epoch and speech using the existing ordered sequence.
Full IPC queues fail the process session, cancelling its lease. A receiving
Tentacle must recheck lease/epoch and peer readiness before sending over a relay.
## Verification and remaining work
Run from this checkout:
```sh
GOCACHE=/tmp/cthulhu-cache GOPROXY=off go test -race ./internal/tentaclewire ./internal/tentacle ./sdk/... -count=1
```
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.
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.
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
status while connected; lock/handoff and disconnect must discard remote work.
Physical consent, audible speech and real NVDA/Orca acceptance remain pending.
+8 -5
View File
@@ -141,9 +141,10 @@ abandoned work. Go also respects a shorter caller context; Python accepts a
shorter explicit timeout. Shutdown/EOF wakes pending calls and event consumers.
The process supervisor still enforces cleanup for a child ignoring cancellation.
These are lifecycle queues only. Separate key/speech queues, latest-frame Braille
coalescing, typed effect validation, and their delivery-time owner checks remain
unimplemented. Do not send those payloads through lifecycle events.
Typed speech IPC now extends this transport; see
[the speech contract](tentacle-remote-speech.md). It uses the same ordered event
queue for exported speech and a separate 64-item incoming mailbox. No production
output owner is connected. Keyboard/Braille/clipboard effects remain unsupported.
## Implemented lifecycle operations
@@ -164,6 +165,7 @@ Child calls:
| `remote.open` | `action`, `epoch`, `role`, `grants` | `lease`, `epoch` |
| `remote.heartbeat` | `lease`, `epoch`, `sequence` | `{}` |
| `remote.close` | `lease`, `epoch`, `sequence` | `{}` |
| `remote.present` | `lease`, `epoch`, `sequence`, typed `speech` | `{}` after mailbox admission; unavailable without reader owner |
The action token must match the unconsumed core approval. Role must match exactly,
and grants must be a nonempty subset of the approved install grants. Controller
@@ -187,8 +189,9 @@ does not implement all effect-owner policies. No production effects currently us
Errors are generic and contain no parameters: `-32001` permission denied,
`-32602` invalid parameters, `-32601` unsupported operation, `-32603` unavailable.
State/focus/presentation/key/Braille/clipboard methods deliberately return
unsupported-operation errors. Malformed envelopes, replayed IDs or frame/queue
State/focus/key/Braille/clipboard methods deliberately return
unsupported-operation errors. Speech mailbox overflow returns `-32002` and
revokes its lease. Malformed envelopes, replayed IDs or frame/queue
violations terminate the process session instead of attempting recovery.
## Verification