Add Remote session foundations and feasibility checks
Add opt-in Tentacle protocol 1.1, explicit remote grants, lifecycle IPC and expiring core leases in both SDKs. Revoke access before update preparation, including failed updates. Add transient secret entries, shared Braille cell export and isolated Xorg recovery experiments with focused tests and documented limitations. Production consent, desktop services and live interoperability remain pending.
This commit is contained in:
1 parent
a47253d697
commit
573d15d7b4
45 files changed
+3634
-80
No files matched your search
@@ -0,0 +1,122 @@
|
||||
# Remote Braille rendering feasibility
|
||||
|
||||
Recorded 2026-11-03 against reader `testing` base
|
||||
`a47253d697c1aa44dea80646cad99a4fe163c7f1` plus the working-tree changes;
|
||||
liblouis 3.39.0. This is a Phase A prerequisite, not an available Remote feature.
|
||||
|
||||
## Result and implementation
|
||||
|
||||
The existing helper viewport can translate, pan and route a separate virtual
|
||||
display without opening BrlAPI or requiring a controlled-side physical display.
|
||||
`internal/braille/cells.go` adds an internal cell-export operation which shares
|
||||
the physical writer's Unicode Braille and attribute-mask conversion. The
|
||||
existing physical writer now calls that shared conversion with the same inputs
|
||||
and masks as before. There is no new helper mode, reader command, session API,
|
||||
network connection or installed binary in this increment.
|
||||
|
||||
The native tests use real liblouis translation, the existing `viewport.setFrame`,
|
||||
`pan` and `route` methods, and the new `rawCells` method. They never construct or
|
||||
open a BrlAPI backend. Each viewport has its own width, offset, pan history,
|
||||
cursor, frame identity and source-position map. One owner must serialize access
|
||||
to each viewport; these tests do not establish concurrent liblouis safety.
|
||||
|
||||
The eight new tests establish:
|
||||
|
||||
- Exact mask conversion for all 256 dot patterns, including eight-dot cells;
|
||||
attribute bits are ORed in without allowing BRLTTY to translate the raw cell.
|
||||
- Existing ordinary text retains its BRLTTY translation masks. Invalid UTF-8
|
||||
and mismatched indicator lengths are rejected.
|
||||
- A separate four-cell virtual viewport and eight-cell local viewport can share
|
||||
source text while keeping independent wrapping, panning, routing and width.
|
||||
- Real contracted output for `the cat`, source routing through the contraction,
|
||||
partial selection attributes, rejection of routing on wrapped padding, and
|
||||
pan-left restoration of the earlier page.
|
||||
- Cursor mapping after contraction, cursor exclusion off the visible page,
|
||||
and a routable synthetic end-of-line cell. Cursor shape in this test is an
|
||||
explicitly supplied static `0xc0` mask.
|
||||
- Replacement width/frame state does not modify the local viewport. Returned
|
||||
cells are independent snapshots; replacement and clearing leave no old routes
|
||||
in the viewport. This is not host rejection of a queued stale routing event.
|
||||
- An explicitly selected computer-Braille table can use the same liblouis path.
|
||||
Missing tables fail without replacing the existing viewport.
|
||||
- Raw export rejects untranslated nonblank text and widths outside 1–4,096.
|
||||
A peer advertising zero must disable its viewport in the future session owner;
|
||||
zero is not replaced with an invented display width here.
|
||||
|
||||
## Remaining boundaries and proposed helper approach
|
||||
|
||||
Ordinary uncontracted output currently goes to BRLTTY as text. Its configured
|
||||
translation table is not reproduced by this increment. The feasibility test sets
|
||||
`Frame.Contract` to select the existing liblouis path and explicitly supplies
|
||||
`en-us-comp8.ctb`; that flag does not itself make the chosen table contract.
|
||||
Production integration needs an explicit virtual translation-table policy and
|
||||
schema. Silently treating ordinary characters as dots, or assuming this table
|
||||
matches a user's BRLTTY configuration, would be incorrect.
|
||||
|
||||
Likewise, physical cursor shape and blinking are currently rendered by BRLTTY.
|
||||
The virtual cell operation can apply an explicit cursor mask, but does not
|
||||
discover or reproduce BRLTTY's cursor preferences. Resolve the virtual cursor
|
||||
policy before describing these bytes as identical to a user's physical output.
|
||||
|
||||
Keep translation and its native failure boundary in the disposable Braille
|
||||
helper. The next proposed step is an explicit virtual-only helper mode which
|
||||
does not call `openWithRetry`, with bounded typed requests for width, frame,
|
||||
panning and routing, and bounded final-cell responses. A separately supervised
|
||||
virtual helper would avoid coupling remote rendering to physical display
|
||||
availability or blocking native calls; process overhead and lifecycle behavior
|
||||
still need testing. No second translator or ASCII lookup table is needed.
|
||||
|
||||
Before exposing this through a Tentacle, complete helper protocol/version
|
||||
validation, cancellation and backpressure; independent physical/virtual helper
|
||||
supervision; host-issued lease/epoch checks; lock/secure-input/handoff exclusion;
|
||||
output arbitration; raw-cell receiving/restoration; and stale routing rejection
|
||||
at delivery. Native AT-SPI routes must remain in the reader. The cell-export
|
||||
operation alone provides none of those authorization or lifecycle guarantees.
|
||||
|
||||
Actual physical displays, non-Latin translation behavior, cursor blinking,
|
||||
unplug/replug, NVDA display negotiation and Braille input remain unverified.
|
||||
Phase A and all release gates remain incomplete.
|
||||
|
||||
## Automated verification
|
||||
|
||||
From the reader checkout:
|
||||
|
||||
```sh
|
||||
GOCACHE=/tmp/cthulhu-go-cache GOPROXY=off go test -race ./internal/braille -count=1 -timeout=60s
|
||||
GOCACHE=/tmp/cthulhu-go-cache GOPROXY=off go test -race -tags brlapi ./internal/braille -count=1 -timeout=60s
|
||||
GOCACHE=/tmp/cthulhu-go-cache GOPROXY=off go vet -tags brlapi ./internal/braille
|
||||
GOCACHE=/tmp/cthulhu-go-cache GOPROXY=off go build -tags brlapi -o /tmp/cthulhu-remote-braille-check ./cmd/cthulhu-braille
|
||||
```
|
||||
|
||||
Both package suites passed, including existing viewport, helper lifecycle,
|
||||
translation, routing and table checks. Vet and the helper build passed. These
|
||||
checks neither launch the helper nor connect to the active reader or display.
|
||||
The adjacent Tentacles repository's `make check` also passed, including its
|
||||
existing command-host fixtures. Its unchanged Go tests used cached results.
|
||||
|
||||
## Pending local Braille regression check
|
||||
|
||||
The only changed active path is mask construction in the physical writer.
|
||||
Human diff review and this physical check remain necessary before submission.
|
||||
There is no live Remote workflow to test yet. When a display is available:
|
||||
|
||||
1. Quit Cthulhu with Cthulhu+Q.
|
||||
2. Press Ctrl+Escape to enter i3 personal mode. Then press Shift+G to rebuild
|
||||
and launch the reader and Braille helper. Ctrl+Escape and Shift+G are separate
|
||||
key presses. The launcher opens a test terminal.
|
||||
3. In an accessible editor, enter a harmless line longer than the display.
|
||||
Confirm ordinary uncontracted Braille matches the previous behavior. Pan
|
||||
right and left; expect the same text pages and no change to keyboard focus.
|
||||
4. Move the caret, including to the end of the line, and select a few characters.
|
||||
Expect the usual physical cursor and selection dots, with no extra or missing
|
||||
dots. Route to a visible character and expect the editor caret at that source
|
||||
character. Ordinary keyboard editing and speech should remain unchanged.
|
||||
5. If contraction is normally used, repeat with `the cat` in the usual English
|
||||
table and then a longer line. Expect the existing contracted cells, cursor
|
||||
positioning, panning and routing behavior. Restore any test preference.
|
||||
6. Report the table, display width, exact affected cells/indicator dots, caret
|
||||
and focus position, speech, and keys that differed from those expectations.
|
||||
For unexpected results, inspect `~/devel/cthulhu-go.log` before restarting.
|
||||
|
||||
These steps check the shared physical writer only; they cannot establish remote
|
||||
Braille acceptance before the session/helper integration exists.
|
||||
@@ -0,0 +1,104 @@
|
||||
# Remote Xorg input feasibility
|
||||
|
||||
This is an isolated prototype and a record of limitations, not a Remote input
|
||||
implementation. No reader input behavior or installed executable changes.
|
||||
The source baseline is `a47253d697c1aa44dea80646cad99a4fe163c7f1` on `testing`,
|
||||
with the existing secret-entry work preserved. The branch was checked against
|
||||
its upstream on 2026-11-03 before these tests were added.
|
||||
|
||||
## Run the private checks
|
||||
|
||||
From the reader checkout:
|
||||
|
||||
```sh
|
||||
python3 -B tests/native_remote_input.py
|
||||
```
|
||||
|
||||
Requirements are Python 3, Xvfb/xvfb-run, D-Bus/dbus-run-session, Xlib, XTEST,
|
||||
xdotool, xev, Go and the reader's usual native build dependencies. Missing tools
|
||||
or failed checks fail the command; they do not count as skipped acceptance.
|
||||
The launcher starts a 24-bit Xvfb display before private D-Bus, with disposable
|
||||
runtime/config directories. It never connects the fixture to the desktop
|
||||
display or the active reader. Invoke it without private fixture arguments.
|
||||
|
||||
The Python tests create a focused X window, a capture process and independent
|
||||
writer/helper processes. Only the writer retains the private control pipe's
|
||||
write end. The harness kills or stops that writer to simulate a dead or hung
|
||||
reader, while retaining the ability to reap both fixture children. This models
|
||||
descriptor ownership; it does not test the real reader's process launch tree.
|
||||
The prototype helper uses fixed two-byte records, a held-key set and a
|
||||
three-second monotonic watchdog renewed only by explicit heartbeats. It releases
|
||||
owned keys on EOF, timeout, malformed input or an already-held-key collision.
|
||||
|
||||
The same private session runs three Go race tests against the real Xorg owners:
|
||||
the new injected-key observation check and the existing internal-form capture
|
||||
and learn-mode application-isolation tests.
|
||||
|
||||
## Evidence recorded on 2026-11-03
|
||||
|
||||
All ten private Python experiments and the three native Go race tests passed.
|
||||
The adjacent Tentacles repository's `make check` also passed, including existing
|
||||
command-host checks; its unchanged Go package tests used cached results.
|
||||
|
||||
- An exclusive `XGrabKeyboard` consumed the test press and release. The focused
|
||||
application received neither. Killing the grab owner made the grab available
|
||||
again, and a fresh key reached the application.
|
||||
- The existing internal-form and learn-mode tests retained their capture and
|
||||
restoration behavior with the race detector enabled. This does not establish
|
||||
coexistence with a new Remote mode or a desktop window manager.
|
||||
- Closing an XTEST client's X connection left its injected Shift down. X
|
||||
connection lifetime alone is therefore insufficient for injected-key cleanup
|
||||
on this server.
|
||||
- Killing the writer released the helper's Shift and Control keys and restored
|
||||
application input. The initial passing run observed EOF cleanup in about
|
||||
0.010 seconds. Stopping the writer without closing its descriptor triggered
|
||||
cleanup in about 3.019 seconds. These are observations from a private Xvfb
|
||||
run, not hard real-time or physical-desktop recovery guarantees; each run
|
||||
prints its own timings and enforces a four-second test bound.
|
||||
- Heartbeats extended the watchdog. Duplicate downs, unmatched ups, fragmented
|
||||
input ending at EOF and invalid records did not leave fixture-owned keys held.
|
||||
- A key already down through another client was not adopted or released. A
|
||||
collision revoked the prototype and released its other owned keys.
|
||||
- A second XTEST client pressing the same code **after** the helper's down was
|
||||
not separately represented by the global key bitmap: helper cleanup cleared
|
||||
that code. The corresponding test records this limitation, not safe collision
|
||||
handling. No physical key device participates in this test.
|
||||
- Injected events had `send_event == False`, and the reader's current XRecord
|
||||
listener delivered them through the ordinary input event stream. Neither that
|
||||
flag nor the existing event representation proves local physical origin.
|
||||
|
||||
## Decisions and remaining gates
|
||||
|
||||
An independent reader-owned helper with an exclusive inherited control
|
||||
descriptor is a viable cleanup direction for the tested failures. It must not
|
||||
be a child of the network Tentacle or be killed with that Tentacle's process
|
||||
group before releasing keys. Reader shutdown must close/revoke the helper and
|
||||
allow bounded cleanup before forced termination. Prevent inherited write ends
|
||||
in unrelated descendants; otherwise reader death will not produce EOF.
|
||||
|
||||
Do not promote this Python fixture to a production helper. It uses synchronous
|
||||
Xlib calls and blocking test acknowledgements, and has no lease, epoch, sequence,
|
||||
input-origin or reader-owner integration. A production Go/native helper needs
|
||||
bounded IPC and X-server failure handling, stale-work invalidation, explicit
|
||||
error reporting, restart policy and lifecycle tests. Simultaneous helper death
|
||||
or a blocked X server is not recovered by this experiment.
|
||||
|
||||
Trusted input origin remains a release blocker. The existing reader event
|
||||
schema contains keycode, transition and timestamp but no source device or
|
||||
core-owned injection identity. Do not grant local consent based on an XRecord
|
||||
event, `send_event`, or a timing-only match. Investigate device-aware events and
|
||||
core-owned injection routing, including exact-once target reader commands,
|
||||
echo suppression and exclusion from consent/clipboard/trust actions.
|
||||
|
||||
Physical/injected same-key collisions also remain a blocker. Checking the
|
||||
global bitmap before a down only handles an already-visible collision, with
|
||||
a check/inject race; it does not resolve a physical press arriving while a
|
||||
remote key is held. Do not clear all modifiers or assume the synthetic
|
||||
two-client result establishes physical-device behavior.
|
||||
|
||||
Still pending: Remote capture within the command owner; local escape and
|
||||
balanced bypass chords; remapping, learn/UI/lock/handoff arbitration; production
|
||||
helper parent-death and blocked-pipe tests; held-key collisions with actual
|
||||
devices; Wayland capability behavior; virtual Braille feasibility; and all live
|
||||
NVDA/Orca, audible-speech and physical-Braille acceptance. Phase A remains open.
|
||||
There is no live Remote command to launch or user desktop test for this increment.
|
||||
Reference in new issue
Block a user