582 lines
38 KiB
Markdown
582 lines
38 KiB
Markdown
# 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.
|