Files
cthulhu/docs/tentacle-remote-speech.md

582 lines
38 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Remote speech transport prerequisite
Typed speech IPC now includes an explicit reader-owned incoming mailbox and
limited production observation of accessibility-event and document-reading speech. The
external coordinator connects this IPC to relay speech. Production software
sessions now attach an isolated incoming owner with lease, focus and local-output
policy. Atomic assembly of split incoming utterances precedes owner admission.
Private tests establish protocol delivery; audible acceptance remains pending.
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.
## 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 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, `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
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.
## Limited production output observation
The Tentacle runtime now attaches its manager to the existing speech worker.
`Manager.CaptureRemoteSpeechOutput` returns a reader-only ticket for an opened,
live controlled lease with `output-observe`. The worker captures this ticket
when it admits explicitly local speech. Work queued before consent gets no
ticket; delivery never captures a replacement. The original lease, deadline and
context are checked again when publishing. Production admission also holds the
core availability policy lock, so lock/handoff cannot admit new output after
policy cancellation, including across unlock/return. Already accepted IPC or
relay writes cannot be recalled.
The zero speech origin is private. The main accessibility event presenter and
reviewed document-reading producers mark requests local. Forms, preferences, connection/status messages,
incoming remote text, command-result Tentacle messages and other unclassified
sources stay private. The presenter classifies the original source and ancestors
before context filtering/reset, so a discarded password ancestor still excludes
its descendant's output. Password roles/ancestors, history exclusion, forced mode
announcements, confirmations and protected messages are independently denied.
Document caret movement, document navigation and assembled caret lines inspect
their original source snapshots and unfiltered ancestors. Every content object
in an assembled line must have a known role and no password ancestry. Say All
classifies all spoken lines before admission; a sensitive or unclassified line
keeps the entire batch private, including sentence-mode continuations. Local
navigation failures stay private. Derived phonetic hints retain their parent's
origin and original observation ticket. Separate key-name echo and notification paths
still need explicit source and sensitivity review.
Visual-line assembly now retains each contributing object's complete captured
ancestry in `DocumentLine.SourceContexts`, independently of the caret object's
presentation context. Caret-line speech checks these sources, and Say All keeps
them when flattening fragments into a single spoken string. A password source,
password ancestor, unknown role or failed context lookup keeps the whole line
private; a sensitive Say All line keeps its entire batch private. Missing source
metadata does not prevent local reading.
Object review now exports successful destination presentations only with complete
captured ancestry. Flat review retains the window's original snapshots and outer
ancestry alongside its layout. Each line checks every contributing zone; word
and character reports check their own source. Password sources/ancestors, unknown
or invalid roles, defunct sources and missing/stale context keep the report local.
An ancestor outside a captured menu/dialog still participates in that check.
Dirty snapshot metadata conservatively keeps the captured flat window private
without changing its local text. Layout text and privacy context remain from the
same capture across tree replacement. Boundaries and errors remain private.
Existing role chunks, pronunciation, spelling, phonetic expansion and character
delivery retain their normal ordering and original lease/generation admission.
Where Am I at a document position now exports only when that position retains
complete captured source ancestry. The event loop stores classification with
the current snapshot, document focus and epoch; it stores no lease authority.
Every snapshot replacement clears classification, including same-object native
updates and Say All position updates without ancestry. Focus/epoch replacement,
missing or mismatched ancestry, password/unknown/invalid roles and defunct
sources keep the report local. Foreground synchronization runs before this
check. Lock and terminal handoff suppress the command. Missing-location status
stays private. Native focus reports use the separate fresh-verification path below;
other unreviewed producers remain private.
Existing text, role chunks, formula reporting, pronunciation, focus, caret and
Braille behavior are preserved; the speech worker captures the current lease
and generation when the explicit command enters its queue.
Browse-mode current-line reporting, spelling and phonetic spelling now export
only with the command's captured source ancestry. The review worker retains
that ancestry from the tree producing the final movement, including after
recapture. Every source role must be known; password sources/ancestors, missing
or stale ancestry and sensitive neighboring fragments keep the report private.
Classification does not add context announcements or change local reading,
caret position, focus or Braille. Spelling retains repeated letters, character
state and phonetic expansion through the existing speech owner, with its original
lease/generation ticket and pronunciation policy. Errors remain private.
Native focused-line reports now capture the focused source and every parent
through its application on the GLib owner, without scanning children or changing
the caret. Capture refreshes role/state metadata and detects cycles, missing
parents, invalid identities, provider errors and truncated walks. It has a
64-object bound and checks a 100-millisecond context between provider calls;
an individual synchronous AT-SPI call still has its existing provider timeout.
Failure leaves privacy metadata empty while preserving successful local text.
Export requires the original focus/epoch, matching source identities and complete
application ancestry; the shared classifier rejects password, unknown/invalid
and defunct sources or ancestors. Spelling, phonetics, pronunciation and blank
line handling use the existing speech owner and original lease/generation.
Lock/handoff are rechecked after foreground synchronization and before presenting
a completed report. Other unreviewed producers stay private.
Native Where Am I now requests a fresh focused snapshot and complete ancestry on
the review/GLib owners, only while enabled speech has a live output observer.
Idle/disabled Remote retains the immediate cached local path. Capture does not
move focus or caret. The existing 64-object/100-millisecond ancestry limits apply;
individual synchronous provider calls retain their existing timeout. Unsupported
providers or a full request queue fall back to the original private local report.
The cached local report is preserved. Export additionally requires matching source
identities and roles, complete known nonprivate ancestry, and exact equality of
the freshly rendered and cached text, formula and speech chunks. Fresh ancestry
alone cannot authorize cached text. Missing/truncated ancestry, provider failure,
password/unknown/invalid/defunct sources and changed reports keep local output
private. A snapshot replacement (even of the same object), focus/epoch change,
lock or handoff retires a pending result. Verification stores no reusable native
classification or lease. The speech worker captures its ordinary lease/generation
ticket only when the verified report enters its queue. Pronunciation, role chunks,
local speech, focus, caret and Braille retain their existing presentation paths.
Private GTK checks exercise the new snapshot operation, fresh private ancestor
roles, password text exclusion, unchanged caret and truncated ancestry. Worker,
application and actual source-command/private-relay tests cover fresh capture,
cached/fresh mismatch, stale-result exclusion and resolved output. Physical
keyboard, audible speech and real NVDA/Orca acceptance remain pending.
Say All exports each resolved chunk immediately before its completion-paced
backend call. Sentence boundaries, pronunciation and the original request's
lease/generation are retained. A lease replacement during reading cannot export
later chunks to the new helper; local reading continues.
Reading-context entry and exit announcements now export only for an admitted,
exportable local request whose retained contexts and their ancestry have known,
nonprivate roles and are not defunct. Classification of the original source
still precedes presentation filtering. This includes navigation, named article
context, spelling and Say All, under their existing context settings, counts,
deduplication and utterance order. Context labels retain the exact text submitted
to the local backend; that existing path does not apply pronunciation replacement.
The change adds no new source classification or backend/voice metadata.
The serialized speech delivery owner retains an observation ticket alongside
its current context labels. Every known context replacement replaces this ticket;
context reset clears both. Cached exit labels use the previous context's original
ticket, while still requiring an eligible current request and current admission.
Labels read before consent, under private/unclassified requests or under a retired
lease cannot acquire later consent on exit. Nil/unknown context retains existing
local state without granting new authority. Policy, expiry and speech generation
are rechecked by the normal observation path. Local labels, system voice, focus,
caret and Braille are unchanged; private labels remain readable locally.
Observation runs after speech-mode suppression, line/indentation processing,
pronunciation, spelling expansion and backend character-path selection. It
records resolved backend **attempts**, before backend I/O, not accepted audio or
audible completion. Character mode is exported only for a single valid CHAR
character; other text uses normal speech. Remote language is the default and
priority is normal; voice, language/profile fidelity and pause/resume remain
unimplemented. No sound cue or backend configuration is sent.
One local backend chunk becomes an observed utterance. Long UTF-8 text splits
conservatively into at most 64 events, each within the encoded speech limit;
only the last ends the utterance. The complete set of IPC frames must fit the
shared session queue and byte budget, including in-flight bytes, before any
prefix is queued. Invalid/oversized output or overflow retires the process
session, matching existing output-event overflow behavior. Local speech proceeds
independently. This atomic IPC admission is not atomic relay or NVDA delivery.
User/input interruption and mode/enable changes publish cancel through the same
speech-owner mutex as observed utterances. An older delivery generation cannot
publish behind that cancel. Remote publication never performs pipe, relay or
backend I/O in the input loop. Incoming cancellation uses the isolated owner
described below.
The source command now offers an explicit Return to desktop action after its
reader lease opens. It closes status and releases local input capture while the
original lease and heartbeat worker remain active. The Remote shortcut reopens
status/Disconnect. Lock/handoff, expiry and process loss still revoke the lease.
See [the terminal interaction contract](tentacle-sessions.md#reader-owned-consent-interactions).
Production incoming software ownership is described below; experimental-speech
warnings remain in place pending live acceptance.
## Verification and remaining work
### Isolated synthesis prerequisite
The configured software backend now has an internal `open_remote_voice`
primitive. It lazily creates one independent Speech Dispatcher speaking/control
pair using the last successfully committed default voice settings. Ordinary
reader startup creates no additional connections. Hardware and unconnected or
closed backends reject acquisition; another acquisition is rejected until the
previous handle has finished closing. This is not a lease authorizer and is not
attached to the production incoming mailbox.
The handle offers plain-text `SpeakAndWait`, scoped `Cancel`, and idempotent
`Close`. Speech remains outstanding through END/CANCEL, rather than just queue
acknowledgement. Caller cancellation affects only the isolated client. Acquisition
context cancellation after a successful open does not retire that handle: a
future lease owner must explicitly close it on revoke, policy loss and shutdown.
Core user interruption cancels both local output and this separate client.
A successful settings commit retires the old handle; it never silently adopts
the replacement configuration. Failed preparation preserves it. Closing an old
handle cannot cancel its replacement. Configuration updates now also retain the
committed settings snapshot when reusing a software backend, so subsequent
acquisition uses the current module and default voice rather than startup values.
Private Unix-socket SSIP tests keep local status and custom echo queued while
remote cancellation, caller cancellation and handle closure run. They check
independent client identities, END/CANCEL pacing, connection reuse, exclusive
ownership, configuration success/failure and stale cleanup. These model protocol
ownership; they do not establish real Speech Dispatcher scheduling, audible
cancellation, or priority arbitration. The original plain-text primitive retains
ordinary normalization. The typed renderer below adds whitespace and
character/language handling; pause and NVDA priority still need stream policy.
No command invokes this primitive yet. The rendering prerequisite below adds
typed utterances; binding them to the bounded reader mailbox still requires
delivery-time lease/focus checks and local priority. Keep mailbox budgets until
delivery/discard and retire queued work on cancellation. No live Remote speech
acceptance test is available from these prerequisites alone.
### Literal utterance rendering prerequisite
`prepare_remote_utterance` now validates a complete speak assembly, retaining its
single priority for a future stream owner. It rejects non-speak effects, mixed
priorities and assemblies beyond the existing 64-frame/256-KiB limits. It joins
adjacent text with the same language/spelling state across IPC fragment
boundaries without adding separators. An end marker or metadata change creates
a synthesis boundary; repeated empty end markers produce no speech. It neither
owns nor releases mailbox budget and cannot authorize presentation.
The isolated handle's `SpeakUtteranceAndWait` renders that prepared sequence
through a new bounded `speech.Client.SpeakFragmentsAndWait` path. Every literal
fragment is checked before backend I/O. Invalid UTF-8, NUL, C0 controls other than
tab/CR/LF, DEL and invalid language tokens reject the whole sequence without a
spoken prefix. Spaces and tabs remain intact; CR, LF and CRLF become SSIP CRLF
line boundaries. Every dot-prefixed line is escaped, including a lone dot.
`SSML_MODE off` makes markup and command-looking text literal data. This changes
no ordinary local-text normalization.
Each fragment uses `SPELLING on/off` and its resolved language. Before rendering,
the client reads its effective default language, output module and symbolic voice
category; unsupported/malformed defaults fail closed. It restores the original
module after every language change, because Speech Dispatcher language mappings
may change modules. Remote language overrides clear a configured named voice and
use the captured symbolic category. If a named voice has no category, explicit
remote languages use SSIP category MALE1; default-language parts restore the
configured voice name. Unknown categories without a configured named voice are
rejected. The accepted module/default-language tokens are limited to 64 ASCII
letters, digits, hyphens or underscores. Backend acceptance of a language request
does not establish that the module can synthesize that language.
The speaking connection remains owned through each END/CANCEL and the complete
sequence. Success restores default voice/language and spelling off. A backend
failure or cancellation discards the remaining suffix and retires the isolated
handle, cancelling only its client. A replacement requires explicit acquisition;
there is no automatic retry or replay. Atomic IPC assembly does not make several
backend fragments atomic: a later backend rejection can follow an already-spoken
earlier fragment.
Only one typed assembly can render at a time. Scoped cancellation cancels its
context as well as outstanding synthesis, so a cancel during a stalled metadata
query cannot be lost before the first SPEAK. It never waits for metadata I/O in
the caller. The renderer completes cleanup before returning ownership.
This implementation follows the [SSIP speech, spelling and language
contract](https://github.com/brailcom/speechd/blob/master/doc/ssip.texi) and checks
default-query/module-switch behavior against the upstream
[parser](https://github.com/brailcom/speechd/blob/master/src/server/parse.c) and
[settings implementation](https://github.com/brailcom/speechd/blob/master/src/server/set.c).
The renderer itself makes no priority or pause decision. The stream prerequisite
below now applies those decisions and retains mailbox budget, but a production
owner still needs original-lease/focus/mode policy and arbitration with local
output. The source Remote command remains relay-only for incoming speech;
no active or installed reader was replaced.
### Incoming stream prerequisite
`run_remote_speech_playback` now joins the isolated renderer to an explicit
delivery channel. It is not registered with production sessions and provides
no default authorization callback. Its caller must supply the reader's
original-lease/focus/output check, bind policy loss to the delivery lifetime,
and retire the session on owner failure. Policy is checked at admission, before
dispatch and after backend acquisition. These callbacks are not a substitute
for production local-output arbitration, which remains pending.
One owner receives complete assemblies and control effects while a separate
renderer performs backend I/O. It retains the original delivery's `Release`
until completion or discard, including through cancelled-renderer cleanup.
Pending work is bounded independently to the existing 64 frames and 256 KiB,
including the active assembly. Invalid assemblies, exceeded budgets and backend
failure end the owner; errors omit speech and backend diagnostics. The future
session caller must revoke/drain remaining ingress on failure or shutdown.
Normal speech is FIFO. NEXT moves ahead of pending normal assemblies but waits
for the active assembly, including its internal end boundaries. NOW interrupts
an active lower-priority assembly and precedes pending lower-priority work;
equal priorities remain FIFO. Interrupted speech is discarded, without replay
or suffix retry. This is deliberately limited priority support: NVDA can resume
interrupted speech and preempt at utterance boundaries; this renderer does not
track a backend speech position. It does not change Speech Dispatcher priority
or establish scheduling parity with NVDA.
Cancel discards pending speech and cancels only the active remote renderer.
Pause true does the same; it does not mute future utterances. NVDA clears its
pause state on cancellation or fresh speech without requiring a separate resume
message. Pause false never replays discarded text. A replacement lease discards
old pending work and waits for old renderer cleanup before starting new output. Stale/cancelled
deliveries are released without rendering. Lease cancellation and owner EOF or
shutdown also cancel active work and release retained pending budget.
The software handle is reused within its lease after successful rendering. A
cancelled rendering retires it; the next accepted assembly acquires a fresh
handle after cleanup. Even an idle handle closes asynchronously on cancellation
of its original lease. Replacement waits for that closure and acquires its own
client; repeated old cleanup cannot cancel the replacement or local status.
Remote synthesis remains outside local history and observation paths.
This prerequisite changes no Xorg capture, keyboard focus, installed reader or
production session routing. Private SSIP fixtures establish scoped protocol
ownership and cancellation, without audible speech or real server scheduling.
Production mailbox attachment, local output priority, physical input and live
NVDA/Orca acceptance remain pending.
### Production incoming owner and local priority
Both local-launch and managed-session startup now attach one incoming owner when
`remote-present`, the reader availability policy, focus gate and configured
software speaker are present. Its lifecycle watcher joins cleanup on session
revocation or reader shutdown. It creates no synthesis connection until accepted
speech needs one. Hardware acquisition fails closed and retires the original
lease; no hardware device is opened by the incoming owner.
Every delivery and synthesis handoff rechecks the original process-owned lease
with `remote-present`, its deadline/context, lock/handoff, internal-form capture,
speech enable and speech mode. Denied work is discarded. Local pending/active
requests and the interruption barrier also deny new speech admission. Incoming
text bypasses local history and observation entirely; remote cancel/pause affects
only its isolated speaking client. Backend failures retire only the failing
lease epoch. Cleanup completes before the renderer starts speech under fresh
consent; a stale failure cannot revoke a replacement approval.
Local speech admission or interruption synchronously retires incoming admission
tickets. Active remote rendering cancels; older queued work is discarded without
replay. The first frame of an IPC assembly receives a reader-owned monotonic
admission timestamp. Local output records a cutoff, so an assembly or mailbox
item accepted before that output cannot acquire a fresh ticket when dequeued
later. The local-generation check is synchronous even before its asynchronous
cancellation callback runs. Mailbox budget remains retained through cleanup.
Speech accepted after the cutoff may proceed once local queue policy permits.
Ordinary software speech returns at queue acknowledgement, not audio completion.
The isolated client therefore sets SSIP `TEXT` before speaking; local reader
clients retain `MESSAGE`. Under the [SSIP priority contract](https://github.com/brailcom/speechd/blob/master/doc/ssip.texi),
TEXT waits behind MESSAGE, and a new MESSAGE cancels older TEXT output. The
relay's normal/NEXT/NOW values only order remote work and cannot raise its SSIP
priority. A server cancellation discards the current assembly and its suffix;
it does not itself revoke consent. Failed priority setup closes the candidate.
This establishes the requested protocol policy, not real-server scheduling or
audible priority acceptance. Other applications using TEXT priority can also
cancel remote output. Pause and priority retain the limited discard semantics
of the stream prerequisite; there is no replay or resume parity.
Private source-command/TLS/SSIP checks exercise complete multilingual spelling
and language output after Return to desktop, and cancel active synthesis on
Disconnect, lock, handoff and disable. Focused tests cover local announcements,
interruption, speech modes, disable/secure input, old mailbox/assembly cutoffs,
rejected local results, backend priority rejection and server cancellation.
Physical local approval, audible output, real Speech Dispatcher scheduling,
Braille and NVDA/Orca interoperability remain separate acceptance gates.
### Automated evidence
For the isolated synthesis prerequisite, focused application/backend race checks
passed, including ten repetitions of the new cases. Existing speech regression
checks, affected-package vet, a separate reader build and Tentacles `make check`
also passed. No installed or active reader was replaced, and no audible or
physical-input acceptance was performed.
The literal rendering increment passed the complete speech-backend race suite
and ten repetitions of the isolated-client/rendering race cases. Private SSIP
fixtures cover exact whitespace, mixed CR/LF, dot-only/command-looking lines,
markup as literal text, repeated-character spelling, language/module/default
restoration, named-voice fallback, long split text, end boundaries, assembly
limits, invalid later fragments, unavailable defaults, rejected settings and
remote/caller/configuration cancellation with local status/echo retained. The
stalled-metadata cancellation case also rejects overlapping typed assemblies
and verifies that neither a prefix nor suffix reaches synthesis. The
existing speech regression harness, affected-package vet, separate reader build
and Tentacles `make check` passed. These are protocol fixtures, without real
Speech Dispatcher, audio, physical input or Braille acceptance.
The incoming-stream increment passed ten repetitions of its focused race cases
and the existing application Remote speech and echo race
checks. Deterministic fixtures cover NEXT/NOW ordering, equal-priority FIFO,
cancel/pause while rendering, no replay, queued revocation, replacement leases,
policy rejection, frame/byte overflow, backend failure and EOF cleanup. Private
SSIP checks retain local status across stream cancellation, reject policy loss
during acquisition, close idle voices on revoke and protect replacement voices
from old cleanup. The existing speech regression harness, application vet,
separate reader build and Tentacles `make check` passed. No live acceptance
or full reader suite was performed for this unwired increment.
Run from this checkout:
```sh
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, 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.
The observation increment adds Go/Python SDK tests for captured authority,
UTF-8/escaped splitting, cancel order and stale tickets; isolated host tests for
all-or-none queue admission, in-flight bytes, expired/pending leases and policy
round trips; and speech-worker tests for resolved pronunciation/characters,
chunks/spelling, private origins, modes, generation and lock/handoff retirement.
The source-command/private-relay fixture also exercises production observation
attachment, transformed long output, private exclusion and cancel order with a
test speech backend. It does not drive physical input or audible synthesis.
Queue-level regressions additionally hold the backend across reconnection:
output admitted under old consent or before fresh consent cannot acquire the
replacement lease. An oversized observed utterance retires Remote while both
that local utterance and subsequent local reading still reach the test backend.
Ten repetitions of the observation race cases passed, along with the complete
host/wire/both-SDK race suites (host: about 127 seconds), focused application
speech/Remote/Tentacle race checks, affected-package vet, a separate reader
build, the existing speech regression harness and Tentacles `make check`.
The production incoming-owner increment passed ten repetitions of its focused
Remote speech/source-command race cases, the complete speech-backend and
host/wire/both-SDK race suites (host: about 128 seconds), shared application
speech/Tentacle race regressions, the existing speech regression harness,
affected-package vet, a separate reader build and Tentacles `make check`.
Backend failure coverage also verifies explicit status close and a fresh setup
workflow without restarting the process. No full reader suite or live acceptance
was performed.
The subsequent fragment-privacy review adds a real accessibility-tree regression
with an ordinary caret and a neighboring password descendant on the same visual
row. Running that regression against the previous classifier with a Go source
overlay reproduced export admission; the corrected classifier denies it.
Presentation/SDK tests cover password sources, password ancestry, unknown roles,
missing contexts and unchanged local reading. Review tests retain every source
through Say All flattening and preserve local text after ancestry becomes stale.
The source-command/private-relay fixture also checks private joined caret/Say All
output never reaches relay speech frames.
Verification for this review passed: the complete AT-SPI/review race suites,
focused application Remote/speech/document/caret/current-line/flat/object-review
race regressions, ten repetitions of the document privacy race cases,
source-command/private-relay race checks, the speech regression harness, vet for
the affected packages, a separate reader build in `/tmp`, and Tentacles
`make check`. The repository check now includes document/Say All observation
regressions. Native/hardware checks and the full reader suite were not run for
this review. Physical input, audible speech, physical Braille and real
NVDA/Orca interoperability remain unverified.
The browse current-line increment passed focused application/input reading and
Remote race regressions, the complete review and external Remote race suites,
the existing speech regression harness, affected-package vet, a separate reader
build and Tentacles `make check`. The new tests cover source/neighbor privacy,
native and error exclusion, recaptured ancestry, unchanged local text after
context invalidation, pronunciation, repeated-letter character spelling, phonetic
spelling and blank lines. The source-command/private-relay fixture exports an
ordinary report and rejects a private joined neighbor. No full reader suite,
native desktop, hardware or audible acceptance was performed for this increment.
See [the live test steps](../../cthulhu-tentacles/remote/command.md#physical-keyboard-acceptance-still-pending).
The object/flat-review increment passed complete AT-SPI/review race suites,
focused application reading/speech/Remote race regressions, affected-package vet,
the existing speech regression harness, a separate reader build and Tentacles
`make check`. Source-tree cases check private and unknown ancestors, every joined
zone, outer menu ancestry, stale metadata and unchanged local reading. Worker
tests compare resolved local and exported speech, including spelling/phonetics.
The actual source command/private relay verifies ordinary exports, private/stale
exclusion and separate role utterance boundaries. An overlay restoring the
previous unclassified producers reproduces missing ordinary export. No full
reader suite, native desktop, hardware or audible checks were performed.
The document Where Am I increment passed focused application reading/focus/
speech/Remote race regressions, complete input/review/AT-SPI and external Remote
race suites, ten repetitions of the new source/privacy cases, the speech
regression harness, application vet, a separate reader build and Tentacles
`make check`. The ordinary-source regression failed before implementation.
Owned-tree cases check private/missing/stale ancestry, same-object native updates,
Say All position replacement, focus/epoch retirement and lock/handoff, including
handoff discovered by foreground synchronization. The source-command/private-relay
fixture verifies ordinary exports, private exclusion and separate role boundaries.
The full application race suite timed out after 180 seconds in package-upgrade
tests; it is not a pass. The source-command race run needed approval for local
fixture sockets; its approved rerun passed. No native desktop, hardware or audible
checks were performed. See the [live Where Am I steps](../../cthulhu-tentacles/remote/command.md#physical-keyboard-acceptance-still-pending).
The reading-context increment reproduced missing ordinary export before the
implementation. Focused application Remote, speech, reading, context-settings,
Say All, spelling and interruption race regressions passed, including ten
repetitions of context privacy, reconnect and source-command/private-relay cases.
The external Remote race suite, existing speech regression harness, application
vet, a separate reader build and Tentacles `make check` passed. The relay fixture
now supplies reading settings and verifies ordinary context entry/exit output
while private labels and their cached exits stay local. No full reader suite,
native desktop, hardware or audible acceptance was performed. See the
[live context steps](../../cthulhu-tentacles/remote/command.md#physical-keyboard-acceptance-still-pending).
Next: verify real Speech Dispatcher scheduling and audible local/remote
arbitration. Physical input capture/release and ordinary reading while connected
still need acceptance.
Review the remaining output producers before assigning exportable origins.
Atomic IPC assembly is implemented; it does not establish backend
priority/cancel behavior or audible delivery.
The stream prerequisite implements cancel-on-pause and limited priority as
documented above; full NVDA priority/resumption fidelity is not established.
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.