README.md RawHistoryFolder

Remote navigation acceptance

Run make remote-acceptance with Docker, Python 3 and ssh-keygen installed.

The runner builds scripts/demo/Dockerfile from the current worktree and starts two disposable Arch containers on a private network. Per-run client and host keys authenticate SSH with host-key pinning. No host credentials, state or sockets are mounted. Containers, image, network and temporary keys are removed on success, failure or interruption.

navigation_repro.py CLIENT_CONTAINER REMOTE_CONTAINER runs the original hybrid transport regression: local A → local B → remote → local A with qualified palette labels, exactly one imported local destination, the original session lifecycle at return, and a successfully committed navigation action.

acceptance.py CLIENT_CONTAINER REMOTE_CONTAINER SCENARIO[@stdio|@quic] runs the table-driven baseline matrix. Every scenario asserts committed outcomes (action IDs, exact lifecycle/session/focus context, observed published output); sending a key is never success. Before each scenario the client container's remote host is re-registered with vev host add --transport quic|ssh remote (@stdio selects ssh; a host keeps the transport it was added with, so the script runs host rm first). Direct-remote scenarios use --remote remote --session NAME against a named fixture session, so the attached target is a named exact lifecycle rather than an ephemeral session, and never create a local home session as setup. VEV_ACCEPTANCE_TOPOLOGY=local|direct selects which daemon serves the client-picker scenario: local keeps the attachment and the picker rows in the client container, direct serves both from the remote container. The client needs a pinned remote SSH alias and vev host add remote (the script then re-registers it per scenario). Scripts create uniquely named sessions and detach their clients; the container owner handles session cleanup.

Client and daemon debug logging is on (VEV_LOG=debug); the remote accepts VEV_LOG over SSH so _broker-mux-stdio/_broker-mux-quic-proxy and the daemon they spawn log at debug too. After every run, sanitized per-run logs and scenario evidence are copied out of the containers to /tmp/vev-acceptance-artifacts-* (override with VEV_ACCEPTANCE_ARTIFACTS_DIR). Only structured vev state logs and committed contexts are captured: no host state, sockets, or key material.

Scenario Modes
local-palette-cycle M1 local IPC: palette open/action/close, committed output, stable lifecycle
direct-remote-named@quic M2 direct named remote QUIC: exact fixture lifecycle, committed output, stable lifecycle
direct-remote-named@stdio M3 direct named remote explicit stdio: same semantics over SSH stdio
warm-reuse@quic Warm hybrid QUIC: local→named remote→local→same remote in one client, same remote lifecycle, retained and new committed output, no second broker dial
warm-reuse@stdio Warm hybrid stdio: same shape across the broker's retained SSH process
hybrid-exact-return@quic M4 hybrid QUIC: local→remote→exact local return with committed action
hybrid-exact-return@stdio M5 hybrid stdio: same shape across close/dial
client-picker-navigate-local@quic M1: client-owned picker presented by the client, searched commit, cancel without a route change
client-picker-navigate-direct@quic M2: same over the remote serving daemon, no local daemon involved
client-picker-navigate-direct@stdio M3: same across stdio

Warm reuse is owned by the connection broker, which replaced the client's suspended-attachment cache (remote.attachment-cache*). Leaving a remote ends its logical attachment; the broker keeps the physical SSH/QUIC transport warm (warmTransports and warmIdleTimeout in broker.json, see configuration), and the return attaches afresh over it. The scenario asserts deterministic no-redial evidence rather than timing: the client container's broker log (~/.local/state/vev/broker/log/vev-daemon.log) must carry zero broker_remote_dial events from the first remote commit to the end of the journey, so a second bootstrap by the attach or by an observation probe fails the scenario. The remote daemon's client attached count is recorded in the evidence, not asserted: each visit is a new logical attachment. The remote committed lifecycle and the retained pane output before and after the round trip are compared directly.

A failed assertion fails the command. This is a targeted regression, not an exhaustive transport or geometry matrix. For a focused run, set VEV_ACCEPTANCE_SCENARIOS to a space-separated subset of the scenario names above (for example warm-reuse@quic warm-reuse@stdio); the containers, keys and artifacts still come from the same setup.

Remote scenarios wait for the fixture session to reach the broker's committed publication (vev ls remote in the client container) before they search the palette: the broker owns remote observation and re-probes each host on its own cadence. A driver request refused with input_busy (not accepted) is resent for up to three seconds; accepted actions are never retried.

client-picker-navigate opens the client-owned picker over the live attachment with SSP, searches the target session by name, and commits it. Every step must settle as processed: the opener on its daemon receipt, the search keys at the client's event-loop boundary, and the commit on the destination's first committed publication.

source
1# Remote navigation acceptance
2
3Run `make remote-acceptance` with Docker, Python 3 and `ssh-keygen` installed.
4
5The runner builds `scripts/demo/Dockerfile` from the current worktree and starts
6two disposable Arch containers on a private network. Per-run client and host
7keys authenticate SSH with host-key pinning. No host credentials, state or
8sockets are mounted. Containers, image, network and temporary keys are removed
9on success, failure or interruption.
10
11`navigation_repro.py CLIENT_CONTAINER REMOTE_CONTAINER` runs the original
12hybrid transport regression: local A → local B → remote → local A with qualified
13palette labels, exactly one imported local destination, the original session
14lifecycle at return, and a successfully committed navigation action.
15
16`acceptance.py CLIENT_CONTAINER REMOTE_CONTAINER SCENARIO[@stdio|@quic]` runs
17the table-driven baseline matrix. Every scenario asserts committed outcomes
18(action IDs, exact lifecycle/session/focus context, observed published
19output); sending a key is never success. Before each scenario the
20client container's `remote` host is re-registered with
21`vev host add --transport quic|ssh remote` (`@stdio` selects `ssh`; a host
22keeps the transport it was added with, so the script runs `host rm` first).
23Direct-remote scenarios use `--remote remote --session NAME`
24against a named fixture session, so the attached target is a named exact
25lifecycle rather than an ephemeral session, and never create a local home
26session as setup. `VEV_ACCEPTANCE_TOPOLOGY=local|direct` selects which daemon
27serves the client-picker scenario: `local` keeps the attachment and the
28picker rows in the client container, `direct` serves both from the remote
29container. The client needs a pinned `remote` SSH alias and
30`vev host add remote` (the script then re-registers it per scenario). Scripts create uniquely named sessions and detach
31their clients; the container owner handles session cleanup.
32
33Client and daemon debug logging is on (`VEV_LOG=debug`); the remote accepts
34`VEV_LOG` over SSH so `_broker-mux-stdio`/`_broker-mux-quic-proxy` and the daemon they spawn log at
35debug too. After every run, sanitized per-run logs and scenario evidence are
36copied out of the containers to `/tmp/vev-acceptance-artifacts-*` (override
37with `VEV_ACCEPTANCE_ARTIFACTS_DIR`). Only structured vev state logs and
38committed contexts are captured: no host state, sockets, or key material.
39
40| Scenario | Modes |
41|---|---|
42| `local-palette-cycle` | M1 local IPC: palette open/action/close, committed output, stable lifecycle |
43| `direct-remote-named@quic` | M2 direct named remote QUIC: exact fixture lifecycle, committed output, stable lifecycle |
44| `direct-remote-named@stdio` | M3 direct named remote explicit stdio: same semantics over SSH stdio |
45| `warm-reuse@quic` | Warm hybrid QUIC: local→named remote→local→same remote in one client, same remote lifecycle, retained and new committed output, no second broker dial |
46| `warm-reuse@stdio` | Warm hybrid stdio: same shape across the broker's retained SSH process |
47| `hybrid-exact-return@quic` | M4 hybrid QUIC: local→remote→exact local return with committed action |
48| `hybrid-exact-return@stdio` | M5 hybrid stdio: same shape across close/dial |
49| `client-picker-navigate-local@quic` | M1: client-owned picker presented by the client, searched commit, cancel without a route change |
50| `client-picker-navigate-direct@quic` | M2: same over the remote serving daemon, no local daemon involved |
51| `client-picker-navigate-direct@stdio` | M3: same across stdio |
52
53Warm reuse is owned by the connection broker, which replaced the client's
54suspended-attachment cache (`remote.attachment-cache*`). Leaving a remote ends
55its logical attachment; the broker keeps the physical SSH/QUIC transport warm
56(`warmTransports` and `warmIdleTimeout` in `broker.json`, see
57[configuration](../../docs/configuration.md#warm-remote-transports)), and the
58return attaches afresh over it. The scenario asserts deterministic no-redial
59evidence rather than timing: the client container's broker log
60(`~/.local/state/vev/broker/log/vev-daemon.log`) must carry zero
61`broker_remote_dial` events from the first remote commit to the end of the
62journey, so a second bootstrap by the attach or by an observation probe fails
63the scenario. The remote daemon's `client attached` count is recorded in the
64evidence, not asserted: each visit is a new logical attachment. The remote
65committed lifecycle and the retained pane output before and after the round
66trip are compared directly.
67
68A failed assertion fails the command. This is a targeted regression, not an
69exhaustive transport or geometry matrix. For a focused run, set
70`VEV_ACCEPTANCE_SCENARIOS` to a space-separated subset of the scenario names
71above (for example `warm-reuse@quic warm-reuse@stdio`); the containers, keys
72and artifacts still come from the same setup.
73
74Remote scenarios wait for the fixture session to reach the broker's
75committed publication (`vev ls remote` in the client container) before they
76search the palette: the broker owns remote observation and re-probes each host
77on its own cadence. A driver request refused with `input_busy` (not accepted)
78is resent for up to three seconds; accepted actions are never retried.
79
80`client-picker-navigate` opens the client-owned picker over the live
81attachment with `SSP`, searches the target session by name, and commits it.
82Every step must settle as `processed`: the opener on its daemon receipt, the
83search keys at the client's event-loop boundary, and the commit on the
84destination's first committed publication.

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 12

Tags 11

↑↓ moveenter openesc close