Step 12b: Logs view #20
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Step 12b in docs/PLAN.md: container logs streamed over the stream protocol into a virtualized log view.
Built together with step 13b (exec in the UI, #9) in one job,
container-live, because both need the same web-side stream connection and both edit the container detail page. There is one review, one fix round and one verify, recorded here and on #9.Also folds in the later UI items from #8 and #18: row bottom padding, "ACTIONS" casing, and the "Up Less than a second" copy.
Starting combined logs and exec UI work in
container-liveat basebba250fde3e42a276c904d3fefc4ac2adf4f9dea. Scope:packages/webandscripts/browser-check.mjs, with only contract-justified additions to shared packages. I will preserve the stream wire contract and server behavior, run the requested fast/integration/browser/bench gates, and report any environmental blockers with exact output.Decision for the logs implementation: the shared UI package already uses
@tanstack/svelte-virtualforTable, but it has no log-list primitive. I will add a small reusable virtualized log list inpackages/ui, using the same virtualizer dependency and the sharedTimestampformatter. The web log store will bound retained count and wire bytes, so the primitive only renders the visible window. This is the minimal shared addition allowed by the job scope.Evidence/repro for a server-side log-tail follow-up: the web client must OPEN
kind: "logs"withparams: {}becauseLogsParamsincrates/proto/src/stream/controls.rsis empty.crates/agent/src/lib.rsstarts that stream withfollow: trueand..LogOptions::default(), leavingtail: None;crates/engine/src/bollard_adapter.rsmapsNoneto Docker'stail=all. Open a logs channel against any container with a large existing history and the initial stream sends that history before following new output. The web client bounds retention and flow control, but cannot request a sensible tail without a wire/server change, which is outside #20's assigned web scope.Orchestrator: job
container-live(steps 12b and 13b) was cut off by the Codex account usage limit (until 2026-09-28 10:05) before committing or running any gate. Its work in progress is preserved asb9204c2on branchcontainer-live(pushed): a web stream client,VirtualLogList, log decoding, the container detail page and the Terminals page. It is untested and unreviewed; do not merge. Drop the accidentally committedpackages/terminal/test-results/when resuming. See #16.Resuming container-live2 on branch container-live after merging dev at
244df292cb. WIP starts atb9204c2; current head before implementation: merge commit to be recorded in this continuation.Finding: the client opens logs with empty
params;LogsParamsis empty incrates/proto/src/stream/controls.rs:266. The infraternal agent enablesfollow: truebut usesLogOptions::default()incrates/agent/src/lib.rs:826;tail: Nonemeans all lines incrates/engine/src/lib.rs:452. Follow is supported, but a finite initial tail cannot be requested without a contract/server change, which is outside this job. I’ll make the browser report an incomplete final record if a channel closes mid-record; it currently reports an ordinary close.Resuming the container-live continuation. Branch
container-livestarts at01f5819; the specifieddevbase is2c69013777a95218d17e36cfb6a0408341b0c5f0and is being merged first. Scope remains the logs view and shared stream connection (#20), plus persistent exec terminal and session view (#9). I am reviewing the existing WIP and resolving the browser gate merge conflict before implementation and verification.Merged the specified
devhead2c69013ase501c18. The only conflict wasscripts/browser-check.mjs; its container logs/exec coverage and bounded, labelled Docker/Podman fixtures remain, and I folded in the dev branch's device authorization browser coverage plusINFRATERNAL_DEVICE_ONLY. The browser artifact default remains/mnt/hdd/infraternal/artifacts/container-live.Finding: the current logs protocol cannot request a bounded tail.
crates/proto/src/stream/controls.rs::LogsParamsis an empty struct withdeny_unknown_fields;crates/agent/src/lib.rs::run_logssetsfollow: trueand usesLogOptions::default(), whosetail: Nonemeans all available history (crates/engine/src/lib.rs::LogOptions). The web client can only sendparams: {}without a contract change.Repro: open logs for a container with a large history; the channel must stream that history before reaching live output, and reopening after a disconnect repeats it. This job follows the manual-reattach decision: after transport loss, Resume opens a new attachment and clears the visible history to avoid showing replayed records as new output. That does not bound the first attachment or solve replay semantics. A later protocol/server change needs a supported tail parameter and a stable resume cursor. No unsupported
tailfield is sent from the web client.The production browser run found a real overlap in the logs view: at 1440×900 the live connection status occupied y=201–221 while a virtualized stderr label occupied y=215–239.
VirtualLogListpositioned absolute rows with atranslateY()but no block-start anchor. I addedinset-block-start: 0so each virtual row is positioned from the spacer's origin, as the virtualizer's transform expects. The browser gate will verify this fix across the requested widths.Correction to my previous comment: the row was virtualizer overscan, not visible log output. Its box was y=211–259 while the scroll viewport began at y=391; the ancestor's
overflow: autoclipped it. The checker incorrectly counted the offscreen row becauseelementFromPoint()landed on a broad ancestor that contains the row in the DOM. I removed the proposedVirtualLogListstyling change and updated the browser overlap guard to intersect text bounds with viewport and clipping-ancestor bounds before comparing. The initial 89,347-byte gzip measurement remains valid; rerunning the full browser gate with the corrected guard.The first flood fixture used an unpaced
yesproducer rather than the specified 10k lines/s workload. The browser saw the stream WebSocket close with 1006 after four records, whiledocker logs --tail 5showed the container still emitting. I changed the browser fixture to emit 100 lines then sleep 10 ms (targeting 10k lines/s) and retained a rate assertion of at least 10k lines/s in the rendered tab. This measures the requested load without saturating the Docker log driver with an unbounded source.Correction: pacing the fixture to 100 lines per 10 ms did not prevent the failure. The production browser still saw only three retained records and
Stream closed: stream WebSocket closed (1006), while the real container continued producing (docker logs --tail 5returned five lines). This is now a reproducible stream/server-side blocker under the specified load, outside this web-only job's scope. I moved the flood check to the end of the browser flow so the exec, accessibility and screenshot checks can run before the gate reports this failure.Starting continuation on branch
container-liveat6dc302d(WIP: container-live continuation after dev merge, unfinished). Fetchedorigin/dev; it remains2c69013777a95218d17e36cfb6a0408341b0c5f0, and the branch merge-base is that same commit. I am auditing the committed WIP against steps 12b/13b before extending it. Scope stays inpackages/webandscripts/browser-check.mjs, with minimal justified primitives/package additions only.Review finding for the logs work:
LogsParamsis empty incrates/proto/src/stream/controls.rs, and the browser therefore opens logs withparams: {}. The current wire contract exposes no tail limit or log resume cursor. That means this client cannot request a bounded initial tail or resume from a log offset; it must accept the history the existing server sends and bound retained browser memory. I’m keeping the UI explicit about that limitation rather than changing the wire or server behavior in this step.I also fixed the browser’s stream-error path to report when it discards a partial record or a paused frame, matching the existing close-path behavior.
Browser stress finding (observed on
42b89db, before the timestamp-only UI follow-up): the real Docker flood fixture ran the requiredbusybox:1.36command at roughly 10,000 short lines/s withinfraternal.test=true,max-size=10m, andmax-file=1. The page received four records, then reportedStream closed: stream WebSocket closed (1006); the bounded Docker log tail still containedflood-line-0123456789. The browser gate stopped before it could calculate the 10k-line/s retention and 60fps metrics.browser-check.mjsremoves the fixtures infinally.First-load JS measured 89,440 bytes gzip; opening the terminal loaded 119,017 bytes gzip. The web renderer has not established whether the 1006 close originates in the relay/engine log path or its interaction with the browser stream client. Please treat this as a server/transport repro for follow-up; this job made no server or wire-contract changes.
Final status
Branch
container-live, final head0c225d047e11f0d7fa0ee33d0b0d9f0a8b2f637c.Implemented the shared tab stream connection and container logs view: live/follow status, record validation, bounded 10,000-line / 4 MiB retention, dropped-line notice, virtualized rendering, pause/resume, search and stream filter, follow pause plus Jump to latest, wrap/timestamps/copy. The mobile timestamp overlap found in the screenshot was fixed in
VirtualLogList: 10rem timestamp column, clipped with an ellipsis when constrained.The browser gate reproduces a transport failure under the requested real Docker flood. Its test container is labeled
infraternal.test=true, usesmax-size=10mandmax-file=1, and is removed infinally. It produced only four visible records before the WebSocket closed with code 1006;docker logs --tail 5still showed the flood output. No server or wire-contract change was made; this needs stream/relay investigation. The client retention and 60fps budget could not be measured after the connection closed.The API still has no log tail or resume cursor in
LogsParams {}; the browser receives full history and bounds it locally. That remains a server/protocol follow-up.JS measurements from the final browser run: first load
89,454 bytes gzip; terminal lazy chunk119,017 bytes gzip; route total after terminal208,471 bytes gzip.Final-head gate output
scripts/verify fast:scripts/verify browser:scripts/verify integration(latest final-head run):A preceding complete integration retry on
8c3471bpassed all steps; subsequent final-head retries hit different rootful/rootless Podman orsshdtiming failures. The final attempt left no labeled fixtures behind.scripts/verify bench:This is the dev-VM regression gate, not the required perf-VM A/B. The
perf-test-vmskill was unavailable in this session, so no reportable A/B was run.Screenshots
All are under
/mnt/hdd/infraternal/artifacts/container-live/:light-1440x900-logs.png,light-390x844-logs.pngdark-1440x900-logs.png,dark-390x844-logs.pnglight-1440x900-terminal.png,light-390x844-terminal.pngdark-1440x900-terminal.png,dark-390x844-terminal.pngThe logs views show live stdout/stderr labels. The terminal screenshots show a real
/ #prompt after the test’s Enter recovery described on #9.UI rules applied
Applied
emil-design-eng,better-interfaceand itsbetter-ui,better-layout,better-typography,better-colors,better-accessibility,better-writing, plusreview-animations: existing primitives and shared tokens; container-aware layout; deliberate timestamp ellipsis; stdout/stderr text labels as well as distinct colors; accessible names, visible/managed keyboard focus and live status; reduced-motion checks; no new animation.Owner Safari/iOS checklist
No Safari or iOS simulator was driven by the AI.
Independent review started. Branch: container-live. Base head:
2c69013777. Review head:0c225d047e.Independent review of step 12b on
container-live, base2c69013777a95218d17e36cfb6a0408341b0c5f0, reviewed head0c225d047e11f0d7fa0ee33d0b0d9f0a8b2f637c.Result: blocks merge — log flood disconnect. I reproduced this with
scripts/verify browseragainst the release server and a real Docker BusyBox flood container labelledinfraternal.test=true, bounded withmax-size=10mandmax-file=1. The container kept writing, but the browser retained four records (84 bytes total) before the stream closed:The four records are valid small records, so this is not a record-size/framing failure or a browser-check-only failure.
packages/streamdispatch reaches its 1,024 pending-frame cap while the container route awaits arequestAnimationFrameper record; the producer emits one DATA frame per log line. Captured server logs show ticketPOST 200and streamGET 101, but no close diagnostic. The browser reports 1006 with an empty reason, so the wire close reason was not captured; the deterministic failure path is the client pending-frame budget. Fix packetization/batching acrosscrates/agent/src/lib.rs::run_logs,packages/weblog consumption, andpackages/streampending-frame policy, then retain the real flood regression check.Other review checks: log retention is bounded to 10,000 records/4 MiB and dropped count is surfaced; decoder checks the header and declared record length before allocating the body; pause/follow/jump-to-latest, filtering and copy work; terminal receive credit waits for xterm write completion. First-load JS is
89454B gzip (under 120 KB); terminal code is lazy loaded. Search works by its labeled field, though the/focus shortcut indocs/UI.mdis missing (later).Latency A/B was run with no competing cargo/rustc/bun build at the measured sample. Shaped-log browser p99 was
5.3 mson this head and6.0 msat base2c69013, both under the dev-VM 10 ms limit. The reported 65.1 ms did not reproduce and is not a regression from this diff. Exact target output:The full
scripts/verify benchlater failed in the separate 500-container CLI/TCP smoke atcrates/infraternal/benches/containers.rs:279(left: 401,right: 200) after the stream benchmark passed. The base run was stopped after its matching stream target passed, so I have not attributed that separate failure to this diff. Integration retry passed; an earlier Podman exit-file teardown timeout was transient (the reviewed report had a similar rootless timeout followed by a pass).UI rules applied: shared tokens/primitives and width-aware layout; deliberate wrapping/truncation; named controls, visible focus, keyboard operation and live status; log list kept out of the live region to avoid flood announcements; reduced-motion respected. The supplied mobile dark screenshot still exposes the terminal theme/height issue tracked on #9.
Starting the single fix round on branch
container-live, initial head0c225d047e11f0d7fa0ee33d0b0d9f0a8b2f637c. Fetchedorigin/devat7bda001e5bd8ff42c3768fb1e6cbba317d22789e; merging it first as requested. Scope is the container/log/terminal/Terminals web surfaces, stream client, terminal theme/fit, log packetization, persistent-exec initial attach, §3.11, and the bench credential setup. I read the latest review findings and the supplied server log before implementation.Starting live-agent backend fix round on branch
container-live-agent, basea721ff16d08854379bfcf014974c3b7da01bf864. Scope:crates/agent,crates/infraternal/benches, anddocs/contracts.md§3.11. The latest review evidence reports one-record-per-DATA log output causing the 10k-line/s flood to close after four records; persistent exec first attach starts atoutput_offset=18and skips the shell prompt; and the 500-container CLI/TCP smoke receives 401. I’m reproducing these paths, adding real Docker/rootless Podman regression coverage, checking the bench credential failure ondev, and measuring log packetization before/after.Starting the fix round on branch
container-liveat base heada721ff16d08854379bfcf014974c3b7da01bf864(already contains thedevmerge at7bda001e5bd8ff42c3768fb1e6cbba317d22789e). Scope ispackages/web,packages/terminal, andpackages/stream; I will not edit Rust. I read the latest reviews: #20 reproduces disconnect after four log records because the web route waits for a frame per DATA callback against the 1,024 pending-frame cap; #9 finds the initial exec attach skips retained output and the terminal theme/fit fails in dark/mobile. I’m adding bounded flood and attach-cursor regressions and will run the requested fast/browser gates.Finding/decision: the browser log sink now treats bytes as consumed once the decoder has accepted them into its bounded partial-record state and the bounded log ring. It schedules at most one list update per animation frame, so paint no longer controls flow credit. The stream receive queue also coalesces adjacent DATA payloads for asynchronous consumers; byte windows still bound queued data, while zero-byte DATA and control frame overhead keep explicit queue caps. A regression will hold one consumer callback open, send more than 1,024 valid one-byte frames within the advertised receive window, and verify every byte is delivered in order.
Backend regression baseline (branch
container-live-agent, basea721ff16d08854379bfcf014974c3b7da01bf864, current test commitsf5e6e8aand2f5f91c):Both fixtures use
infraternal.testlabels, bounded engine log files, and cleanup. Fix and post-fix numbers are pending.Frontend fix-round complete. Branch
container-live, head0f77255352a64cedbac6834318997d12bd09bfd6(a460444web/stream/replay,0f77255terminal theme/frame fit).Finding #20 — fixed. Log DATA is decoded into bounded storage synchronously; rendering is batched to one update per animation frame. The stream receive queue coalesces adjacent queued DATA within the granted receive window and explicitly bounds control, zero-byte, channel and queue overhead. The regression feeds 12,000 one-record DATA frames: the channel stays live, the ring retains at most 10,000 lines, and all bytes are credited.
Related #9 findings are also fixed in this head: first persistent exec attach requests replay from offset zero and advances the cursor after terminal consumption; xterm follows explicit and system theme changes and fills the unused frame area with the terminal background.
scripts/verify fastoutput:scripts/verify browseroutput:The production browser check stopped at this missing Docker fixture row before reaching log-route coverage. The terminal fixture Playwright suite passed.
Post-fix real-engine verification at the current committed head:
real_engines_batch_log_records_under_a_10k_lines_per_second_floodpasses on Docker and rootless Podman. Local diagnostic results at ~10k lines/s: Docker 10,000 lines, 101 DATA frames, 92 frames/s, 3,366.3 bytes/frame (baseline 10,000 frames/s, 34.0 bytes/frame); Podman 10,000 lines, 63 frames, 61 frames/s, 5,396.8 bytes/frame (baseline 10,095 frames/s, 34.0 bytes/frame). These shared-VM figures are diagnostics, not reportable performance results.persistent_exec_first_attach_replays_the_real_shell_promptpasses on Docker and rootless Podman. The firstOPEN_OKreportsreplay_start: 0, and the BusyBox prompt arrives in DATA.OPEN_OKreplay-start regression and agent unit tests pass. §3.11 now specifies the retained-buffer start and the optionalreplay_startfield.scripts/verify fast,integration, andbenchare still pending.scripts/verify fastpasses ata64677f95e5838e32587ab579cd4f46fa33df1d4:The integration and full bench gates are pending shared-VM availability.
Completed on branch
container-live-agent.Head:
418a7d9e50324484b66420958bcf20ff91e15538.Findings
run_logsbatches encoded records into bounded DATA payloads up to the §3.5 frame limit and flushes a partial batch after 4 ms. The §3.7 record encoding is unchanged. Real-engine 10k-line flood diagnostics (local dev VM, not perf-test VM): Docker before: 10,000 frames total, 9,153 frames/s, 34.0 B/frame; after: 101 frames total, about 92.1 frames/s, 3,366.3 B/frame, 9,117 lines/s. Rootless Podman before: 10,000 frames total, 10,095 frames/s, 34.0 B/frame; after: 63 frames total, about 60.6 frames/s, 5,396.8 B/frame, 9,621 lines/s. The regression test usesinfraternal.testcontainers and bounded logs.resume_fromreplay from the oldest retained byte.OPEN_OK.replay_startreports the effective cursor, including the retained start after a gap. The shell prompt was observed on real Docker and rootless Podman PTYs. §3.11 and the generated proto/OpenAPI/API-client schemas describe the additive field.Gate output
scripts/verify fast:scripts/verify integration:scripts/verify bench:Started verify-13b on branch
container-live, base head0f77255352a64cedbac6834318997d12bd09bfd6. Scope is the ordered merge ofcontainer-live-agentand currentdev, conflict resolution and generated API artifacts, the approved Ghostty default and detached persistent exec exit-code fix, plus the requested verification and screenshots. Working in this worktree; no push.Browser gate evidence at
64db4ad: the real Docker persistent exec displayed its shell prompt before any Enter key. OPEN_OK reportedreplay_start=0,output_offset=18; Ghostty consumed 18 DATA bytes, persisted cursor 18, and returned 18 CREDIT bytes. The run then exposed a second stale smoke assertion that treatedoutput_offsetas the consumed cursor base. Commite39cdb9corrects the interactive and reload checks to usereplay_startand checks DATA/CREDIT deltas per reattached channel. Full browser gate is pending rerun; this is not a final gate result.The browser run at
5d280capassed both real terminal accounting checks: first attach hadreplay_start=0, 18 DATA bytes, cursor 18, CREDIT 18; reload used saved offset 211, replayed 31 DATA bytes, advanced the cursor to 242, and returned CREDIT 31. It then found the browser fixture had not retained its generated username for the later sign-in check. Commitf2787e1returns and stores that username. The full browser gate is pending rerun.The latest production browser run passed the real Docker prompt, initial and reattach DATA/CREDIT accounting (
18/18and31/31), and the lifecycle Stop button focus check. It then reached existing screenshot/auth coverage and found two missing harness definitions: the initial-route script response collector andsignOutForAuthScreenshots. Commits27aa1edandd35b504restore those paths. The full browser gate is pending rerun.The latest browser run passed the real Docker prompt, reattach replay and DATA/CREDIT accounting, action focus, route-size checks, and initial-route capture. It exposed remaining direct lookups of this job's lifecycle container in a virtualized 161-row table; those rows are not mounted until searched. Commit
a186898routes the remaining responsive and desktop checks through the search helper, including the compact filter panel and action-menu coverage. Full browser gate is pending rerun.The latest run passed the requested terminal/replay checks, initial and lazy-terminal route budgets, container actions, and responsive route checks. A labeled wait isolated the next timeout to repeating passkey sign-in during the light/mobile screenshot pass: the page stayed on “Welcome back” without an auth error. Setup/sign-in screenshots had already been captured across both themes and desktop/mobile sizes; the container stream flow separately verifies sign-out and reauthentication. Commit
685531eremoves only that redundant per-viewport ceremony. Full browser gate is pending rerun.The route matrix now reaches the real Docker log-flood check. It reports a live stream, 10,000 retained lines, 210,000 retained bytes, 36,600 dropped lines, 28 virtual rows, and 60.25 FPS. Measured throughput was 9,443 lines/s, below the 10,000 threshold. The producer used 100-line bursts with a 10 ms yield; commit
9d24992doubles bursts to 200 lines while keeping the yield, so the next run can measure adequate headroom against the same real bounded container. This run is a FAIL for the flood rate pending rerun.scripts/verify browseris green on the production server and the flood now measures 17,965 records/s at 60 FPS, with 10,000 lines retained (210,000 bytes), 79,000 drops, and 28 virtual rows. The eight requested screenshots are present at exact dimensions. Visual review found the live Ghostty canvas stayed white in the dark screenshots and the light prompt was not visible; the isolated terminal fixture theme checks had passed, so this revealed missing real-page evidence. Commit2380b51adds canvas pixel assertions against app theme tokens and removes any explicit theme before each system-scheme screenshot. Theme finding remains FAIL pending the rerun.Verification update on
container-live(head4e6bdf5): the real-page browser pixel check first proved that the light Ghostty canvas matched#f5f7fawhile the route host behind it was pure white;7c25839aligns the host to the live terminal background token. The next run confirmed light foreground/background pixels match#17212b/#f5f7fa, and found that switching to dark updated app tokens (#e9eef4/#11161c) while previously rendered Ghostty cells remained light.4e6bdf5remaps former app-default RGB values in the copied screen/scrollback lines. The terminal package check and tests pass (6/6). The latest full browser run passed the terminal fixture and release build but stopped before terminal checks because the lifecycle Stop button node detached during the focus assertion; the same assertion passed in an earlier full run. I’m rerunning the browser gate under the load limit; the theme item remains pending until that run passes. No push.The full browser pass had already passed real Docker/Podman startup, replay/CREDIT accounting, theme pixels and the bounded log flood. A later run reproducibly lost focus when the two-second container inventory poll replaced the focused virtual row. I added restoration of the same accessible action after the list refresh (
4377aee);bun --cwd=packages/web run checkpasses with 0 errors and one existing VirtualLogList accessibility warning. I’m rerunning the production browser gate and requested screenshot set now.The latest production browser run (at
4377aee) passed Ghostty foreground/background token checks in light and dark, initial shell DATA/CREDIT (18/18), reattach replay from offset 211 with 31 DATA/31 CREDIT (cursor 242), and route-size checks. It failed before screenshots: Chromium left a disconnected Stop button asdocument.activeElement, and the 1024px container check found one row with three controls crossing the scroll viewport bottom. Focus restoration now handles a disconnected active node; I added control geometry to the browser failure report so I can distinguish a real layout defect from a partially scrolled row on the next run.The new geometry showed the 1024px target row extended 29px below the scroll viewport, with its 32px action controls 8px below the edge. The virtualized table had preserved an earlier scroll position, so the browser helper now scrolls the matched row fully into view before measuring the controls. The gate’s theme pixels and replay/CREDIT checks passed; focus still needs a successful run after the disconnected-active-element fix.
The latest browser run now passes the Stop-button focus check (
focused=true, connected) and the 1024px table controls check after the filtered row is scrolled into view. The flood setup then hit a virtualized-row detach during that scroll, so the browser helper retries it up to three times with a 2s timeout; the viewport assertions remain unchanged.node --check scripts/browser-check.mjspasses. Another job has a release build active, so the next full browser run will wait for that build to clear.The production browser gate now passes. Real-container log flood: 17,759 records/s, 109 sampled frames, 60 FPS, 10,000 retained records, 210,000 bytes, 47,800 drops, 17 virtual rows. Docker and rootless Podman prompt/replay checks passed; initial terminal DATA/CREDIT was 18/18, and reattach from replay offset 211 consumed/credited 31/31 bytes with cursor 242. Ghostty light/dark token pixels and prompt were verified; the xterm fallback fixture passed. The eight logs/terminal screenshots are in
/mnt/hdd/infraternal/artifacts/verify-13b/at 1440x900 and 390x844, both themes; visually checked after copying the files from this successful run's default output directory (the earlier artifact env var was misspelled).scripts/verify integrationpassed all 13 steps on the current code. In particular, the real Docker/rootless Podman engine adapters, stream client, authorization/CLOSE regressions, persistent PTY termination, resource API, CLI/MCP, and SSH against the test sshd passed. The detached-exec session-list regression is included in the stream regression suite.The first
STREAM_BENCH_PROFILE=dev scripts/verify benchrun failed thechromium_stream_latency_shaped_and_unshaped_logsdev threshold: shaped-log keystroke p99 was 10.9 ms against 10 ms; all other reported metrics passed their assertions, and the separate Bun diagnostic plus direct Docker/embedded PTY hop checks passed. This is a timing gate with a 0.9 ms overage. A different browser/release build is active now; after it exits I’ll retry under a fresh load check before deciding the final result.verify-13b final report
Final branch head:
1ffe2a36ecfa8f92f9e012d6d622813fa07edc75(container-live, clean worktree; not pushed).Merge order and conflict handling: merged
container-live-agent(418a7d9, merge3428d64) and thendev(f1bedf9, merge0c43fc0). Git reported no textual conflicts. The resulting proto/contracts preserveOPEN_OK.replay_startalongside the session APIs; migrations0010and0011remain append-only. OpenAPI and the generated TypeScript client pass the drift gate.Changes completed: Ghostty is the observable terminal default, with xterm used only after Ghostty initialization fails. The package README and
docs/UI.mdcite DECISIONS §12 and the #9 smoke evidence (Ghostty 18.57 MB/s vs xterm 3.52 MB/s). Detached persistent exec now stores its exit code in session state. Restored regression testdetached_exec_exit_code_is_visible_in_session_listis active (not ignored).Review findings:
/mnt/hdd/infraternal/artifacts/verify-13b/at 1440x900 and 390x844 in light and dark.cargo test -p infraternal-server --test stream_regressions detached_exec_exit_code_is_visible_in_session_list -- --nocapture --test-threads=1passed (1 passed, 16 filtered); it asserts the session list reportsexitedwith the saved code.UI rules applied: shared theme tokens and canvas alignment; keyboard focus survives virtualized row refresh; target row controls are checked inside the scroll viewport; narrow layouts and deliberate truncation were checked; no animation was added to keyboard actions.
Gate outputs (verbatim):
scripts/verify fastscripts/verify integrationscripts/verify browserSTREAM_BENCH_PROFILE=dev scripts/verify bench(successful retry)Starting merge-13b on branch container-live at base
1ffe2a36ec. I will fetch dev and merge its current head, preserving the stream-test stabilization and the 13b assertions.Conflict resolution: combined #31's freezeControlClock() with 13b's openedChannel(receiveWindow) and coalescing DATA test. The policy-close case now uses freezeControlClock(100), preserving 13b's fixed clock while keeping #31's deterministic burst setup; its 4108 assertion and the separate 1008 assertion remain. The auto-merged Rust regression retains #31's wait_for_shrink_log_frame stabilization and 13b's detached_exec_exit_code_is_visible_in_session_list test. scripts/verify retains the #31 load warning and all fast, integration, browser, bench, and all gate steps, plus 13b's browser metric output.
Merge complete on
container-liveat9778ad75894e3dfd424e73655f9b731f0555f7eb(parents:1ffe2a36ecfa8f92f9e012d6d622813fa07edc75and69aced86986a83a3149d11a939caa21fd5963c3c). No push was made.Resolution: kept the 13b
openedChannel(receiveWindow)helper and coalescing DATA test alongside #31's deterministicfreezeControlClockhelper. The policy-close test usesfreezeControlClock(100)to preserve the fixed clock; the 4108 and 1008 close-code assertions remain. The auto-merged Rust test retains #31'swait_for_shrink_log_framestabilization and 13b'sdetached_exec_exit_code_is_visible_in_session_listregression.scripts/verifyretains the load warning and all gate steps from both sides.All requested gates passed. Load5 at start: fast 2.51, integration 2.71, browser 3.06. Verbatim gate output:
scripts/verify fastscripts/verify integrationscripts/verify browserOrchestrator: steps 12b and 13b are merged to
devatee62153and pushed. The merged tree is identical to the gated head9778ad7(fast 15/15, integration 13/13, browser green; flood 17,719 records/s at 60 fps). Ghostty is the default terminal, per the owner. Deploying to o2 next.