Skip to content

fix(tabs-sync): quality closes on continuity work + opencode terminal-signal research#521

Merged
danshapiro merged 3 commits into
mainfrom
chore/continuity-quality-closes
Jul 24, 2026
Merged

fix(tabs-sync): quality closes on continuity work + opencode terminal-signal research#521
danshapiro merged 3 commits into
mainfrom
chore/continuity-quality-closes

Conversation

@danshapiro

Copy link
Copy Markdown
Owner

Track 5 of the post-continuity quality wave: the missing independent review of e7a4add, the two known minors from that review loop, and the opencode terminal-signal research deliverable.

Task A — Independent review of e7a4add (verdict: clean beyond the known minors)

Adversarial review of e7a4addb ("fix(tabs-sync): custom CLI modes, cross-client ordering, and bounded restore marker"), the final fix round that never got re-reviewed. Reviewed as a senior engineer against the three risk areas named in the task:

Cross-client capturedAt ordering — no findings.

  • cross_client_capture_order is a total order over queue heads (capturedAt → revision → clientInstanceId → path); paths are unique, so max_by/min_by selection is fully deterministic despite HashMap queue collection order (tabs_persist.rs:152-175).
  • The k-way merge (order_generations_newest_first) compares only per-client queue HEADS, preserving within-client revision monotonicity under clock rollback — the non-transitivity trap of mixing both comparison rules in one sort is correctly avoided, and the doc comment says exactly why.
  • Retention eviction (enforce_device_file_cap) mirrors the merge with oldest-first per-client queues; file_count bookkeeping guarantees min_by always has a nonempty head; a client's higher-revision-but-older-clock file is correctly protected behind its queue head.
  • union_of_newest_per_client label tie-break is deterministic (clientInstanceId is unique per candidate by construction).

Restore-marker caps — no findings.

  • Boundary semantics are consistently inclusive-at-cap across all four caps (> MAX rejects); boundary tests cover at/over for bytes, pane count, and all three identifiers.
  • read_marker_doc TOCTOU between metadata() and read_to_string is re-checked post-read.
  • Error-before-side-effects verified: validate_restore_projection preflight runs before the pane loop, and restore_rejects_over_limit_marker_plan_before_side_effects proves no marker file and no pane on rejection.
  • Write-ahead ordering preserved: per-pane persist_marker still precedes the create/deliver (tabs_snapshots.rs:799), and write_ahead_marker_is_durable_before_tab_create_is_sent fences it.

Any-nonempty-mode acceptance — no regression.

  • Persistence-time validation now only requires a nonempty mode; actual spawning remains guarded by mode_is_known (terminal_tabs.rs:588, 400 for unregistered modes) and cli_spec_known (terminal.rs:762). pane_to_create_body passes mode through with no seven-mode enum assumption; restore of an unregistered mode fails loudly as a failed entry, never a silent shell fallback.

Non-blocking notes (recorded, deliberately not restyled):

  • MarkerSizeWriter's over-cap message reads "serialized byte limit is X (more than X)" — repeats the cap instead of the actual size. Cosmetic; the fail-loud path still identifies the file and cause.
  • validate_restore_projection sizes projected terminal ids with a 36-byte UUID placeholder; a hypothetical future id format >36 bytes would pass preflight and fail loudly post-side-effect instead. Exact today, safe-by-fail-loud tomorrow.
  • The commit found (and this review confirms) one REAL defect adjacent to its diff — confirm_delivery — fixed here as Task B1.

Task B — Known minors

  1. confirm_delivery dropped-sender bug (fixed, TDD): the ack wait matched Ok(_) on the timed-out oneshot receiver, so Ok(Err(RecvError)) — a dropped sender, e.g. the pending entry cancelled/purged before the client answered — read as delivery confirmation and marked the pane restored. Now only Ok(Ok(_)) confirms. Regression test (red first: it reproduced deliveryConfirmed:true + restored) drives the restore endpoint with a client whose ack entry is purged instead of answered and asserts the delivery-unconfirmed failure path plus the retained in-progress write-ahead marker.
  2. Retention wording (docs only): plan doc and main.rs comment claimed "last 5 generations per device"; actual (correct, tested) behavior is MAX_SNAPSHOT_GENERATIONS = 5 per (device, client), MAX_SNAPSHOT_FILES_PER_DEVICE = 40 per device. Wording fixed in both places (and the doc's embedded copy of the comment).

Task C — OpenCode terminal-signal research

docs/plans/2026-07-23-opencode-terminal-signals.md — evidence-backed findings from running the real opencode 1.18.3 CLI in a throwaway HOME (run + TUI under script), schema/row inspection, socket/lock inspection, and bounded read-only sampling of the real 4.4 GB DB. Headlines: the standalone TUI has no socket, no lock/heartbeat, and emits zero bare BELs (the claude/codex turn-complete pipeline cannot be extended to it); the durable signal is the SQLite message.data.time.completed null→set edge (with error absent for positive completion); subagent activity is separable via session.parent_id; session_input is structurally a prompt queue but its on-disk visibility while queued is honestly UNVERIFIED. Recommendation: full truly-idle support via bounded opencode.db polling keyed off the existing OpencodeLocator binding; unbound panes stay status-inert; no grace-window heuristics; effort 2-4 days.

Verification

  • cargo fmt --check: only the pre-existing directory_index.rs drift (outside this diff, already noted as pre-existing in e7a4add's own message)
  • cargo clippy --workspace --all-targets: zero warnings in files touched by this PR (background warnings pre-existing)
  • cargo test --workspace: 1524 passed, 0 failed
  • Coordinated FRESHELL_TEST_SUMMARY="track5 quality closes pre-PR" npm test: full-suite success at 51f5719 (coordinator-recorded)

🤖 Generated with Amplifier

codex and others added 3 commits July 23, 2026 23:40
confirm_delivery matched `Ok(_)` on the timed-out oneshot receiver, so a
dropped sender (`Ok(Err(RecvError))` -- the pending ack entry cancelled or
purged before the client answered) read as a confirmed delivery. The pane
was then marked restored instead of staying in-progress for a safe retry.

Match only `Ok(Ok(_))` as confirmation; a dropped sender now takes the
delivery-unconfirmed failure path. Regression test drives the restore
endpoint with a client whose ack entry is purged instead of answered and
asserts deliveryConfirmed=false, the failed reason, and the in-progress
write-ahead marker.

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
…lient)

The plan doc and the main.rs registry comment said snapshots keep the
"last 5 generations per device"; the actual behavior (correct, tested)
is MAX_SNAPSHOT_GENERATIONS = 5 per (device, client) with
MAX_SNAPSHOT_FILES_PER_DEVICE = 40 across all clients of a device.
Fix the wording where it lied; no behavior change.

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
…ndings

Research-only deliverable: what a plain opencode CLI in a terminal pane
exposes for busy-vs-idle, turn boundaries, and queued prompts. Ran the
real opencode 1.18.3 CLI in a throwaway HOME/project (run + TUI under
script), inspected its SQLite schema/rows/sockets/locks, sampled the
real DB read-only with bounded queries, and compared against the
freshopencode serve-SSE status source.

Recommendation: full truly-idle support via bounded opencode.db polling
keyed off the existing OpencodeLocator binding (time.completed edge,
positive-completion only); status-inert for unbound panes; no
grace-window heuristics. Queued-prompt detection deferred (session_input
semantics unverified without an authed long turn).

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
@danshapiro
danshapiro merged commit ca0fb73 into main Jul 24, 2026
1 check passed
danshapiro pushed a commit that referenced this pull request Jul 24, 2026
Conflict resolutions (both sides' behavior preserved everywhere):

- crates/freshell-ws/src/lib.rs, terminal.rs, opencode_association.rs
  + 12 tests/*.rs WsState constructors: kept BOTH this branch's
  `activity: None` field and #523's new `session_existence` probe
  field (trivial adjacent-field conflicts). #523's brand-new
  tests/pane_reconcile.rs gained `activity: None` too.
- crates/freshell-terminal/src/registry.rs: kept BOTH the TERM-15/16
  activity tap (ActivityEvent/ActivityObserver, tap field + init, the
  Created-tap fire in create()) and #523's reconciliation additions
  (respawn liveness/cap consts + fields, keyed_create_inflight, the
  §5.4 duplicate-live-PTY backstop — ordered before the Created tap).
  create() gained #523's create_request_id param; this branch's two
  activity-observer tests updated to pass None for it.
- crates/freshell-server/src/main.rs: kept #523's session_index block
  first (ws_state.session_existence references it), then this branch's
  activity-hub construction + registry observer install.
- docs checklist + playwright.config.ts auto-merged (both sides' notes
  and MATRIX/rust-only spec entries retained).

Cross-track integration (#524 truly-idle client): the Rust
terminal.idle emission matches shared/ws-protocol.ts's new
TerminalIdleSchema byte-for-byte ({type, terminalId, at, reason:
'grace'|'queue-empty'}), so the rust leg of
test/e2e-browser/specs/truly-idle-alerting.spec.ts is now ENABLED
(test.fixme removed) — the full production pipeline (PTY submit ->
busy blue -> BEL -> idle + turn.complete -> 2s grace -> terminal.idle
-> one alert edge + tab shade) passes against the real Rust server.

Verification: cargo test --workspace 1656 passed / 0 failed; clippy
clean on touched files; rust-chromium PW (3 activity + truly-idle
rust leg) green 2x (4 passed 1.1m, 4 passed 42.5s); coordinated
npm test full-suite success exit=0 (3982 + 4547 + 350 passed; two
earlier runs each hit one unrelated pre-existing flake — DOM-identity,
sidebar-filter, EADDRINUSE:40301 — each passes in isolation).

🤖 Generated with [Amplifier](https://github.com/microsoft/amplifier)

Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants