Step 21 (S2): persistent SSH sessions and reattach #39

Open
opened 2026-09-25 05:16:50 +00:00 by kayg · 38 comments
Owner

PLAN step 21: SSH sessions survive a closed client or a dropped tunnel, and any authorized web, CLI or MCP client can reattach by session id and output offset, under the owner, target and bounded-replay rules of contracts §3.11. This is a security surface, so it runs on Sol.

PLAN step 21: SSH sessions survive a closed client or a dropped tunnel, and any authorized web, CLI or MCP client can reattach by session id and output offset, under the owner, target and bounded-replay rules of contracts §3.11. This is a security surface, so it runs on Sol.
Author
Owner

Step 21 start: branch ssh-reattach, base dbd66850f8a5d6190e65b4bd364e075950033425. Contract-first commit records the remaining client behavior and detached-session authorization in §3.11.

Gap analysis against §3.11:

  • Exists: crates/ssh/src/session.rs keeps persistent PTYs after attachment drop, has 1 MiB per-session replay and 64 MiB aggregate budget, idle reaper, 64 total / 16 per-user / 16 per-host limits, open-key dedupe, owner-kind-target binding and one-writer takeover. crates/server/src/stream.rs validates a reattach against durable stream_sessions; stream OPEN uses session_id/resume_from and returns output_offset/replay_start/gap. The existing real-sshd product test covers close then reattach and attached-token revocation. The sessions API lists SSH rows and closes them. CLI already has ssh --attach with a required host, and sessions listing.
  • Missing: ssh --attach <id> without a host, CLI resume-offset option, and all four MCP session tools. No real-sshd tests explicitly kill a CLI process, drop its network transport mid-output, or cross between web-style stream, CLI and MCP.
  • Revocation gap: the detached SSH sweep checks the owner's role grants but does not check the creating token's current grants/revoked/expired state. Attached channels have a separate watcher; detached ones have no such watcher. I will add that check and a real-sshd test.
  • Existing replay-gap, quota and takeover mechanisms need targeted integration evidence, with honest resource_exhausted/not_found errors. Contract is explicit on one writer and takeover, so no decision is needed.

Contract commit: see branch head after this comment. I will build only the gaps above; no web files.

Step 21 start: branch `ssh-reattach`, base `dbd66850f8a5d6190e65b4bd364e075950033425`. Contract-first commit records the remaining client behavior and detached-session authorization in §3.11. Gap analysis against §3.11: - Exists: `crates/ssh/src/session.rs` keeps persistent PTYs after attachment drop, has 1 MiB per-session replay and 64 MiB aggregate budget, idle reaper, 64 total / 16 per-user / 16 per-host limits, open-key dedupe, owner-kind-target binding and one-writer takeover. `crates/server/src/stream.rs` validates a reattach against durable `stream_sessions`; stream OPEN uses `session_id`/`resume_from` and returns `output_offset`/`replay_start`/`gap`. The existing real-sshd product test covers close then reattach and attached-token revocation. The sessions API lists SSH rows and closes them. CLI already has `ssh --attach` with a required host, and `sessions` listing. - Missing: `ssh --attach <id>` without a host, CLI resume-offset option, and all four MCP session tools. No real-sshd tests explicitly kill a CLI process, drop its network transport mid-output, or cross between web-style stream, CLI and MCP. - Revocation gap: the detached SSH sweep checks the owner's role grants but does not check the creating token's current grants/revoked/expired state. Attached channels have a separate watcher; detached ones have no such watcher. I will add that check and a real-sshd test. - Existing replay-gap, quota and takeover mechanisms need targeted integration evidence, with honest `resource_exhausted`/`not_found` errors. Contract is explicit on one writer and takeover, so no decision is needed. Contract commit: see branch head after this comment. I will build only the gaps above; no web files.
Author
Owner

Finding: refresh_session revokes the old access-token id and issues a new one in the same refresh family. A detached-session check against only the original token id would end ordinary long-lived SSH sessions at credential refresh, despite unchanged grants. The implementation resolves the latest active token in that family for the detached sweep, then checks both current role and token grants. A revoked/expired family has no live successor and ends the session. §3.11 now states this explicitly.

Finding: `refresh_session` revokes the old access-token id and issues a new one in the same refresh family. A detached-session check against only the original token id would end ordinary long-lived SSH sessions at credential refresh, despite unchanged grants. The implementation resolves the latest active token in that family for the detached sweep, then checks both current role and token grants. A revoked/expired family has no live successor and ends the session. §3.11 now states this explicitly.
Author
Owner

Dependency finding: at base dbd6685, crates/agent/src/lib.rs still describes its framed tunnel OPEN path as used by a future network tunnel; the current server stream routes through the embedded infraternal agent. Step 19 owns remote tunnel transport in parallel. I added a real-sshd test that drops the entire client WebSocket while output is pending and reconnects by session id/offset. A real remote-tunnel-drop test needs step 19 integrated and belongs in the step-26 combined end-to-end gate; this branch cannot truthfully claim that network hop was exercised.

Dependency finding: at base `dbd6685`, `crates/agent/src/lib.rs` still describes its framed tunnel OPEN path as used by a future network tunnel; the current server stream routes through the embedded infraternal agent. Step 19 owns remote tunnel transport in parallel. I added a real-sshd test that drops the entire client WebSocket while output is pending and reconnects by session id/offset. A real remote-tunnel-drop test needs step 19 integrated and belongs in the step-26 combined end-to-end gate; this branch cannot truthfully claim that network hop was exercised.
Author
Owner

Verification so far (branch head e56f582): scripts/verify fast passed after the four clippy findings were fixed. Verbatim gate lines:

PASS fast: migrations are append-only
PASS fast: workspace package dependencies
PASS fast: JavaScript dependencies
PASS fast: build web app
PASS fast: cargo fmt --check
PASS fast: cargo clippy
PASS fast: cargo test
PASS fast: svelte-check
PASS fast: UI package svelte-check
PASS fast: stream package typecheck
PASS fast: Vitest
PASS fast: UI package Vitest
PASS fast: stream package Vitest
PASS fast: OpenAPI and TypeScript client drift
PASS fast: terminal TypeScript
PASS fast: terminal Vitest

Focused real-sshd product test (includes the new transport-drop and detached-token-revocation cases) passed: test host_trust_stream_replay_resize_close_and_changed_key ... SSH_STREAM_ROUND_TRIP samples=40 p50_ms=1.256 p99_ms=2.124, then 1 passed; 0 failed. CLI/MCP real integration and full integration gate are next; load5 must fall below 8 before the full gate.

Verification so far (branch head `e56f582`): `scripts/verify fast` passed after the four clippy findings were fixed. Verbatim gate lines: ``` PASS fast: migrations are append-only PASS fast: workspace package dependencies PASS fast: JavaScript dependencies PASS fast: build web app PASS fast: cargo fmt --check PASS fast: cargo clippy PASS fast: cargo test PASS fast: svelte-check PASS fast: UI package svelte-check PASS fast: stream package typecheck PASS fast: Vitest PASS fast: UI package Vitest PASS fast: stream package Vitest PASS fast: OpenAPI and TypeScript client drift PASS fast: terminal TypeScript PASS fast: terminal Vitest ``` Focused real-sshd product test (includes the new transport-drop and detached-token-revocation cases) passed: `test host_trust_stream_replay_resize_close_and_changed_key ... SSH_STREAM_ROUND_TRIP samples=40 p50_ms=1.256 p99_ms=2.124`, then `1 passed; 0 failed`. CLI/MCP real integration and full integration gate are next; load5 must fall below 8 before the full gate.
Author
Owner

Focused compiled CLI/MCP integration first run failed before reaching the new SSH cases, in the existing container exec PTY timing assertion at crates/infraternal/tests/cli_mcp.rs:2332. It expected initial 24 80 output but observed only 47 123 twice after SIGWINCH; load5 was about 9 during the run. This is the load-sensitive timing class tracked by #31, not an SSH assertion. Per the job rule I will rerun this single test directly once when load5 is below 8 and quote both outcomes. I have not changed the unrelated exec test.

Focused compiled CLI/MCP integration first run failed before reaching the new SSH cases, in the existing container exec PTY timing assertion at `crates/infraternal/tests/cli_mcp.rs:2332`. It expected initial `24 80` output but observed only `47 123` twice after SIGWINCH; load5 was about 9 during the run. This is the load-sensitive timing class tracked by #31, not an SSH assertion. Per the job rule I will rerun this single test directly once when load5 is below 8 and quote both outcomes. I have not changed the unrelated exec test.
Author
Owner

Required single direct retry of cli_and_mcp_use_the_public_http_contract also failed at the existing container exec PTY resize assertion, after exercise_cli_ssh had returned successfully (that SSH helper runs near the start of this test, before the failing exec section). First run: line 2332 expected 24 80, observed only 47 123 twice; second run: line 2336 expected 47 123, observed only 24 80 twice. The opposite observations under concurrent VM load show the test's current timing sensitivity (#31). I did not rerun it again or modify the unrelated exec path. The focused real-sshd ssh_product test passed independently.

Required single direct retry of `cli_and_mcp_use_the_public_http_contract` also failed at the existing container exec PTY resize assertion, after `exercise_cli_ssh` had returned successfully (that SSH helper runs near the start of this test, before the failing exec section). First run: line 2332 expected `24 80`, observed only `47 123` twice; second run: line 2336 expected `47 123`, observed only `24 80` twice. The opposite observations under concurrent VM load show the test's current timing sensitivity (#31). I did not rerun it again or modify the unrelated exec path. The focused real-sshd `ssh_product` test passed independently.
Author
Owner

Final-head verification (b11e0d8): scripts/verify fast passed again after fixture run IDs and MCP read annotations. Verbatim output:

PASS fast: migrations are append-only
PASS fast: workspace package dependencies
PASS fast: JavaScript dependencies
PASS fast: build web app
PASS fast: cargo fmt --check
PASS fast: cargo clippy
PASS fast: cargo test
PASS fast: svelte-check
PASS fast: UI package svelte-check
PASS fast: stream package typecheck
PASS fast: Vitest
PASS fast: UI package Vitest
PASS fast: stream package Vitest
PASS fast: OpenAPI and TypeScript client drift
PASS fast: terminal TypeScript
PASS fast: terminal Vitest

Full scripts/verify integration started after load5 fell below 8 and the other release build finished.

Final-head verification (`b11e0d8`): `scripts/verify fast` passed again after fixture run IDs and MCP read annotations. Verbatim output: ``` PASS fast: migrations are append-only PASS fast: workspace package dependencies PASS fast: JavaScript dependencies PASS fast: build web app PASS fast: cargo fmt --check PASS fast: cargo clippy PASS fast: cargo test PASS fast: svelte-check PASS fast: UI package svelte-check PASS fast: stream package typecheck PASS fast: Vitest PASS fast: UI package Vitest PASS fast: stream package Vitest PASS fast: OpenAPI and TypeScript client drift PASS fast: terminal TypeScript PASS fast: terminal Vitest ``` Full `scripts/verify integration` started after load5 fell below 8 and the other release build finished.
Author
Owner

Full scripts/verify integration was started with load5 below 8 after the previous release build ended. It passed release build, real HTTP, and Docker/rootless Podman socket checks, then stopped at an existing engine PTY cleanup assertion before CLI/SSH steps. Verbatim gate lines:

PASS integration: JavaScript dependencies
PASS integration: build web app
PASS integration: build release binary
PASS integration: real HTTP behavior
PASS integration: Docker socket _ping
PASS integration: rootless Podman socket _ping
FAIL integration: engine adapters against Docker and Podman

The failed case was pty_session_drop_and_close_terminate_exec_processes_on_all_real_engines; at crates/engine/tests/integration.rs:875, a Podman shell PID remained in the process table after drop. The test suite result was 10 passed; 1 failed; 0 ignored, under load5 above 10 after other jobs started concurrently. This is outside step 21's owned files. I will run that single case directly once below load5=8 and quote the result; I will not change the engine adapter from this branch.

Full `scripts/verify integration` was started with load5 below 8 after the previous release build ended. It passed release build, real HTTP, and Docker/rootless Podman socket checks, then stopped at an existing engine PTY cleanup assertion before CLI/SSH steps. Verbatim gate lines: ``` PASS integration: JavaScript dependencies PASS integration: build web app PASS integration: build release binary PASS integration: real HTTP behavior PASS integration: Docker socket _ping PASS integration: rootless Podman socket _ping FAIL integration: engine adapters against Docker and Podman ``` The failed case was `pty_session_drop_and_close_terminate_exec_processes_on_all_real_engines`; at `crates/engine/tests/integration.rs:875`, a Podman shell PID remained in the process table after drop. The test suite result was `10 passed; 1 failed; 0 ignored`, under load5 above 10 after other jobs started concurrently. This is outside step 21's owned files. I will run that single case directly once below load5=8 and quote the result; I will not change the engine adapter from this branch.
Author
Owner

Required single direct retry of the failed engine cleanup case started at load5=7.84 and failed independently in the same unrelated engine test, at an earlier cleanup assertion. Verbatim result:

test pty_session_drop_and_close_terminate_exec_processes_on_all_real_engines ... FAILED
pty close: EngineError { code: Conflict, message: "marker scan failed and no host PID namespace was captured", kind: "exec", engine_code: Some("exec_termination_unconfirmed"), retryable: false, outcome_unknown: true }
test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 10 filtered out

First full integration run had 10 passed; 1 failed and found a Podman shell still in the process table at line 875. This direct retry failed at line 743 with unconfirmed exec cleanup even at low load. It is an engine cleanup defect outside this job's owned SSH/server/CLI/MCP files, so I am not changing it here. The full integration gate cannot reach its later SSH steps until that upstream gate is green; focused real-sshd SSH tests are being run separately.

Required single direct retry of the failed engine cleanup case started at load5=7.84 and failed independently in the same unrelated engine test, at an earlier cleanup assertion. Verbatim result: ``` test pty_session_drop_and_close_terminate_exec_processes_on_all_real_engines ... FAILED pty close: EngineError { code: Conflict, message: "marker scan failed and no host PID namespace was captured", kind: "exec", engine_code: Some("exec_termination_unconfirmed"), retryable: false, outcome_unknown: true } test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 10 filtered out ``` First full integration run had `10 passed; 1 failed` and found a Podman shell still in the process table at line 875. This direct retry failed at line 743 with unconfirmed exec cleanup even at low load. It is an engine cleanup defect outside this job's owned SSH/server/CLI/MCP files, so I am not changing it here. The full integration gate cannot reach its later SSH steps until that upstream gate is green; focused real-sshd SSH tests are being run separately.
Author
Owner

Step 21 branch work finished at b11e0d896e1953ff910504178193872a312ee3ce (ssh-reattach, base dbd6685). No push; worktree clean. The contract, detached-session creator authorization across normal token refresh, CLI attach-by-id/offset, bounded MCP list/attach/send/read, and real-sshd cases for SIGKILL, client socket drop, MCP cross-client reattach, and detached revocation are committed. No web files changed; no screenshots apply.

Final scripts/verify fast output, verbatim:

PASS fast: migrations are append-only
PASS fast: workspace package dependencies
PASS fast: JavaScript dependencies
PASS fast: build web app
PASS fast: cargo fmt --check
PASS fast: cargo clippy
PASS fast: cargo test
PASS fast: svelte-check
PASS fast: UI package svelte-check
PASS fast: stream package typecheck
PASS fast: Vitest
PASS fast: UI package Vitest
PASS fast: stream package Vitest
PASS fast: OpenAPI and TypeScript client drift
PASS fast: terminal TypeScript
PASS fast: terminal Vitest

Focused real-sshd gates, verbatim result lines:

test result: ok. 18 passed; 0 failed; 0 ignored; 0 measured; 2 filtered out; finished in 24.16s
test result: ok. 7 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out; finished in 16.78s

The compiled CLI/MCP test executed and returned from the new SSH helper on both runs, then failed later in existing exec PTY dimension assertions (first missing initial size, direct retry missing resized size). Both outputs are quoted in earlier comments.

Full scripts/verify integration output until its stop, verbatim:

PASS integration: JavaScript dependencies
PASS integration: build web app
PASS integration: build release binary
PASS integration: real HTTP behavior
PASS integration: Docker socket _ping
PASS integration: rootless Podman socket _ping
FAIL integration: engine adapters against Docker and Podman

The engine test suite was 10 passed; 1 failed; the failed Podman PTY cleanup assertion is quoted above. Its required single direct retry at load5=7.84 failed with exec_termination_unconfirmed, also quoted above. This is outside this branch's owned engine files, and the integration script never reached later SSH steps. A real remote-tunnel-drop test remains dependent on step 19's network tunnel transport and should run in step 26 after integration; the current branch tested full client-WebSocket loss against a real sshd. No issues were closed.

Step 21 branch work finished at `b11e0d896e1953ff910504178193872a312ee3ce` (`ssh-reattach`, base `dbd6685`). No push; worktree clean. The contract, detached-session creator authorization across normal token refresh, CLI attach-by-id/offset, bounded MCP list/attach/send/read, and real-sshd cases for SIGKILL, client socket drop, MCP cross-client reattach, and detached revocation are committed. No web files changed; no screenshots apply. Final `scripts/verify fast` output, verbatim: ``` PASS fast: migrations are append-only PASS fast: workspace package dependencies PASS fast: JavaScript dependencies PASS fast: build web app PASS fast: cargo fmt --check PASS fast: cargo clippy PASS fast: cargo test PASS fast: svelte-check PASS fast: UI package svelte-check PASS fast: stream package typecheck PASS fast: Vitest PASS fast: UI package Vitest PASS fast: stream package Vitest PASS fast: OpenAPI and TypeScript client drift PASS fast: terminal TypeScript PASS fast: terminal Vitest ``` Focused real-sshd gates, verbatim result lines: ``` test result: ok. 18 passed; 0 failed; 0 ignored; 0 measured; 2 filtered out; finished in 24.16s test result: ok. 7 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out; finished in 16.78s ``` The compiled CLI/MCP test executed and returned from the new SSH helper on both runs, then failed later in existing exec PTY dimension assertions (first missing initial size, direct retry missing resized size). Both outputs are quoted in earlier comments. Full `scripts/verify integration` output until its stop, verbatim: ``` PASS integration: JavaScript dependencies PASS integration: build web app PASS integration: build release binary PASS integration: real HTTP behavior PASS integration: Docker socket _ping PASS integration: rootless Podman socket _ping FAIL integration: engine adapters against Docker and Podman ``` The engine test suite was `10 passed; 1 failed`; the failed Podman PTY cleanup assertion is quoted above. Its required single direct retry at load5=7.84 failed with `exec_termination_unconfirmed`, also quoted above. This is outside this branch's owned engine files, and the integration script never reached later SSH steps. A real remote-tunnel-drop test remains dependent on step 19's network tunnel transport and should run in step 26 after integration; the current branch tested full client-WebSocket loss against a real sshd. No issues were closed.
Author
Owner

Independent review-21 started on branch ssh-reattach at b11e0d896e1953ff910504178193872a312ee3ce, against base dbd6685. I will inspect the step 21 diff and contracts, run targeted verification in a throwaway worktree, and report findings with evidence. The review worktree remains read-only.

Independent review-21 started on branch `ssh-reattach` at `b11e0d896e1953ff910504178193872a312ee3ce`, against base `dbd6685`. I will inspect the step 21 diff and contracts, run targeted verification in a throwaway worktree, and report findings with evidence. The review worktree remains read-only.
Author
Owner

Review findings in progress:

  • list_ssh_sessions collects the full /sessions response (crates/infraternal/src/mcp.rs:712); storage selects every owned row without LIMIT (crates/server/src/storage/mod.rs:1733). Exited rows persist, so the MCP list has unbounded result size despite the 64 live-session cap. I am treating this as a bounded-output contract defect.
  • The new ssh_product test failed on a clean branch run at crates/server/tests/ssh_product.rs:648: immediately after receiving channel CLOSE, the database still reported Attached instead of Detached. I am checking whether this is an async state-observation race and will record the final conclusion in findings.md.
  • The refresh-lineage test passed unchanged, then failed at its new line 344 when its lineage lookup was disabled in the throwaway worktree (NotFound). This confirms that test detects the intended regression.
Review findings in progress: - `list_ssh_sessions` collects the full `/sessions` response (`crates/infraternal/src/mcp.rs:712`); storage selects every owned row without `LIMIT` (`crates/server/src/storage/mod.rs:1733`). Exited rows persist, so the MCP list has unbounded result size despite the 64 live-session cap. I am treating this as a bounded-output contract defect. - The new `ssh_product` test failed on a clean branch run at `crates/server/tests/ssh_product.rs:648`: immediately after receiving channel CLOSE, the database still reported `Attached` instead of `Detached`. I am checking whether this is an async state-observation race and will record the final conclusion in findings.md. - The refresh-lineage test passed unchanged, then failed at its new line 344 when its lineage lookup was disabled in the throwaway worktree (`NotFound`). This confirms that test detects the intended regression.
Author
Owner

Independent review-21 verdict: request changes. Full findings with severity, file:line, scenario and fix are in /mnt/hdd/infraternal/jobs/review-21/findings.md.

Blocking findings: list_ssh_sessions is unbounded because /sessions fetches every owned row, including retained exited rows (mcp.rs:712, storage/mod.rs:1733); ordinary attach/detach lacks a session-specific audit record (stream.rs:1232, :2348, :2369). The new real-sshd test also has an immediate Detached assertion race at ssh_product.rs:648: it failed on the clean branch, then passed in the throwaway checkout with a bounded wait.

Confirmed: CLI attach-by-id/offset and MCP attach/send/read code paths, refresh lineage and fail-closed revocation/role checks, same-owner/kind/target authorization on server and infraternal agent, one-writer takeover, bounded replay/read/send, session quotas and idle expiry. A same-owner AI agent token needs explicit hosts:read and ssh:connect grants to reach a person's SSH session. Abrupt client WebSocket loss was tested against real sshd; the remote infraternal-agent tunnel hop depends on step 19. Two tests were proven sensitive to their fixes in the throwaway checkout: disabling refresh-lineage fallback failed storage.rs:344 with NotFound; disabling detached-session grant-loss termination failed ssh_product.rs:696 with the one-second revocation timeout (after a test-only wait for the state update).

Podman gate diagnosis, tagged load-flake with uncertainty: the unchanged engine test pty_session_drop_and_close_terminate_exec_processes_on_all_real_engines failed on this branch at integration.rs:875 (PID remained) and on direct retry at :743 (exec_termination_unconfirmed) per #39. On detached dbd6685, the same single test passed when started at load5 8.39: test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 10 filtered out; finished in 44.31s. The base pass excludes a deterministic branch-only engine regression; the exact load threshold is not established. Re-run the full integration gate after the step 11c cleanup path is stabilized.

Review scripts/verify fast output, verbatim:

WARN load5=9.73 exceeds online CPU count=8; timing-sensitive checks may be delayed
PASS fast: migrations are append-only
PASS fast: workspace package dependencies
PASS fast: JavaScript dependencies
PASS fast: build web app
PASS fast: cargo fmt --check
PASS fast: cargo clippy
PASS fast: cargo test
PASS fast: svelte-check
PASS fast: UI package svelte-check
PASS fast: stream package typecheck
PASS fast: Vitest
PASS fast: UI package Vitest
PASS fast: stream package Vitest
PASS fast: OpenAPI and TypeScript client drift
PASS fast: terminal TypeScript
PASS fast: terminal Vitest

Review worktree ssh-reattach was not edited. No issue closed.

Independent review-21 verdict: **request changes**. Full findings with severity, file:line, scenario and fix are in `/mnt/hdd/infraternal/jobs/review-21/findings.md`. Blocking findings: `list_ssh_sessions` is unbounded because `/sessions` fetches every owned row, including retained exited rows (`mcp.rs:712`, `storage/mod.rs:1733`); ordinary attach/detach lacks a session-specific audit record (`stream.rs:1232`, `:2348`, `:2369`). The new real-sshd test also has an immediate `Detached` assertion race at `ssh_product.rs:648`: it failed on the clean branch, then passed in the throwaway checkout with a bounded wait. Confirmed: CLI attach-by-id/offset and MCP attach/send/read code paths, refresh lineage and fail-closed revocation/role checks, same-owner/kind/target authorization on server and infraternal agent, one-writer takeover, bounded replay/read/send, session quotas and idle expiry. A same-owner AI agent token needs explicit `hosts:read` and `ssh:connect` grants to reach a person's SSH session. Abrupt client WebSocket loss was tested against real sshd; the remote infraternal-agent tunnel hop depends on step 19. Two tests were proven sensitive to their fixes in the throwaway checkout: disabling refresh-lineage fallback failed `storage.rs:344` with `NotFound`; disabling detached-session grant-loss termination failed `ssh_product.rs:696` with the one-second revocation timeout (after a test-only wait for the state update). Podman gate diagnosis, tagged **load-flake** with uncertainty: the unchanged engine test `pty_session_drop_and_close_terminate_exec_processes_on_all_real_engines` failed on this branch at `integration.rs:875` (PID remained) and on direct retry at `:743` (`exec_termination_unconfirmed`) per #39. On detached `dbd6685`, the same single test passed when started at load5 8.39: `test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 10 filtered out; finished in 44.31s`. The base pass excludes a deterministic branch-only engine regression; the exact load threshold is not established. Re-run the full integration gate after the step 11c cleanup path is stabilized. Review `scripts/verify fast` output, verbatim: ``` WARN load5=9.73 exceeds online CPU count=8; timing-sensitive checks may be delayed PASS fast: migrations are append-only PASS fast: workspace package dependencies PASS fast: JavaScript dependencies PASS fast: build web app PASS fast: cargo fmt --check PASS fast: cargo clippy PASS fast: cargo test PASS fast: svelte-check PASS fast: UI package svelte-check PASS fast: stream package typecheck PASS fast: Vitest PASS fast: UI package Vitest PASS fast: stream package Vitest PASS fast: OpenAPI and TypeScript client drift PASS fast: terminal TypeScript PASS fast: terminal Vitest ``` Review worktree `ssh-reattach` was not edited. No issue closed.
Author
Owner

fix-21 started on branch ssh-reattach at base b11e0d896e. Fetched and merged current dev; already up to date. Scope: review findings 1–3 only; crates/engine and finding 4 excluded.

fix-21 started on branch ssh-reattach at base b11e0d896e1953ff910504178193872a312ee3ce. Fetched and merged current dev; already up to date. Scope: review findings 1–3 only; crates/engine and finding 4 excluded.
Author
Owner

Finding 1: stream_sessions had an unbounded owner fetch. GET /sessions now reads at most 51 indexed rows, returns up to 50 with next_cursor, and offers exact owner/grant checked GET /sessions/{id}; CLI and MCP use exact lookup for attach. The web Terminals route is currently a placeholder with no API caller. Existing index stream_sessions_owner_created_idx matches the cursor order.
Finding 2: attach, takeover, and detach now use a transaction to commit state and actor-attributed audit together; migration 0016 retains the current attachment token id. Storage regression covers takeover, ordinary detach, and audit-failure rollback.
Finding 3: real-sshd test polls for Detached with a one-second bound before revocation.

Finding 1: stream_sessions had an unbounded owner fetch. GET /sessions now reads at most 51 indexed rows, returns up to 50 with next_cursor, and offers exact owner/grant checked GET /sessions/{id}; CLI and MCP use exact lookup for attach. The web Terminals route is currently a placeholder with no API caller. Existing index stream_sessions_owner_created_idx matches the cursor order. Finding 2: attach, takeover, and detach now use a transaction to commit state and actor-attributed audit together; migration 0016 retains the current attachment token id. Storage regression covers takeover, ordinary detach, and audit-failure rollback. Finding 3: real-sshd test polls for Detached with a one-second bound before revocation.
Author
Owner

Regression mutation proof on d90cdc7 (all mutations restored; tree clean): removing both SQL LIMIT 51 clauses made session_pages_are_bounded_and_attachment_audit_is_atomic fail at storage.rs:83 (expected [51,51,21]); changing stream.session.attach to attach_removed made the same test fail at storage.rs:108; replacing the bounded Detached poll with the original immediate assertion made host_trust_stream_replay_resize_close_and_changed_key fail on attempt 1 at ssh_product.rs:681 (Attached != Detached). The unmutilated storage test, HTTP page test, and real-sshd test passed. scripts/verify fast passed all 15 steps; integration waits for another job release build to finish and load5 below 8.

Regression mutation proof on d90cdc7 (all mutations restored; tree clean): removing both SQL LIMIT 51 clauses made session_pages_are_bounded_and_attachment_audit_is_atomic fail at storage.rs:83 (expected [51,51,21]); changing stream.session.attach to attach_removed made the same test fail at storage.rs:108; replacing the bounded Detached poll with the original immediate assertion made host_trust_stream_replay_resize_close_and_changed_key fail on attempt 1 at ssh_product.rs:681 (Attached != Detached). The unmutilated storage test, HTTP page test, and real-sshd test passed. scripts/verify fast passed all 15 steps; integration waits for another job release build to finish and load5 below 8.
Author
Owner

Integration gate on 551d063 was started at load5=5.66. It passed release build, real HTTP, Docker/rootless Podman pings, engine adapters, and bounded log snapshots, then failed at TypeScript stream client against Docker and Podman. Exact failure: stream_e2e.rs:366 stream close left an exec shell in podman; the process table showed /bin/sh still present. This is a different test from the two named known flakes. Other integration jobs were concurrent at the time; I am waiting for resource contention to clear before a direct reproduction. No crates/engine changes.

Integration gate on 551d063 was started at load5=5.66. It passed release build, real HTTP, Docker/rootless Podman pings, engine adapters, and bounded log snapshots, then failed at TypeScript stream client against Docker and Podman. Exact failure: stream_e2e.rs:366 `stream close left an exec shell in podman`; the process table showed `/bin/sh` still present. This is a different test from the two named known flakes. Other integration jobs were concurrent at the time; I am waiting for resource contention to clear before a direct reproduction. No crates/engine changes.
Author
Owner

Direct retry of the failed, non-enumerated integration test after other integration jobs ended passed verbatim:

    Finished `test` profile [unoptimized] target(s) in 0.32s
     Running tests/stream_e2e.rs (target/debug/deps/stream_e2e-0342476f9bd3402e)

running 1 test
test typescript_client_streams_logs_and_exec_for_docker_and_podman ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 4 filtered out; finished in 10.33s

The first gate failure is therefore timing-sensitive under concurrent live-engine runs, not yet proven branch-caused; it is distinct from the two named known flakes. I will rerun the full integration gate after load5 falls below 8.

Direct retry of the failed, non-enumerated integration test after other integration jobs ended passed verbatim: ``` Finished `test` profile [unoptimized] target(s) in 0.32s Running tests/stream_e2e.rs (target/debug/deps/stream_e2e-0342476f9bd3402e) running 1 test test typescript_client_streams_logs_and_exec_for_docker_and_podman ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 4 filtered out; finished in 10.33s ``` The first gate failure is therefore timing-sensitive under concurrent live-engine runs, not yet proven branch-caused; it is distinct from the two named known flakes. I will rerun the full integration gate after load5 falls below 8.
Author
Owner

Second full integration gate on 551d063 started at load5=7.47. It passed release build, HTTP, Docker/Podman pings, engine adapters, bounded log snapshots, and the previously failing TypeScript stream test. It then failed in stream_regressions.rs:755: authorization_loss_terminates_stalled_stdin_on_both_engines reported sleep did not start on docker; ps showed /bin/sh but no sleep 3600 within five seconds. Eleven other tests in that suite passed. This is another non-enumerated timing failure under concurrent browser load. No engine or test edits. I will run the failed test directly after the browser suite ends and load falls.

Second full integration gate on 551d063 started at load5=7.47. It passed release build, HTTP, Docker/Podman pings, engine adapters, bounded log snapshots, and the previously failing TypeScript stream test. It then failed in stream_regressions.rs:755: `authorization_loss_terminates_stalled_stdin_on_both_engines` reported `sleep did not start on docker`; `ps` showed `/bin/sh` but no `sleep 3600` within five seconds. Eleven other tests in that suite passed. This is another non-enumerated timing failure under concurrent browser load. No engine or test edits. I will run the failed test directly after the browser suite ends and load falls.
Author
Owner

Direct retry of the second integration failure passed verbatim:

    Finished `test` profile [unoptimized] target(s) in 0.41s
     Running tests/stream_regressions.rs (target/debug/deps/stream_regressions-53fd2437b4851c58)

running 1 test
test authorization_loss_terminates_stalled_stdin_on_both_engines ... docker stalled stdin CLOSE forbidden in 39.913569ms
podman stalled stdin CLOSE forbidden in 71.393334ms
ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 18 filtered out; finished in 15.40s

Both non-enumerated live-test failures reproduced only under concurrent load and passed direct retries; I will make one more full integration attempt when load5<8 and no other heavy suite is active.

Direct retry of the second integration failure passed verbatim: ``` Finished `test` profile [unoptimized] target(s) in 0.41s Running tests/stream_regressions.rs (target/debug/deps/stream_regressions-53fd2437b4851c58) running 1 test test authorization_loss_terminates_stalled_stdin_on_both_engines ... docker stalled stdin CLOSE forbidden in 39.913569ms podman stalled stdin CLOSE forbidden in 71.393334ms ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 18 filtered out; finished in 15.40s ``` Both non-enumerated live-test failures reproduced only under concurrent load and passed direct retries; I will make one more full integration attempt when load5<8 and no other heavy suite is active.
Author
Owner

Fix round head: 551d063562 on ssh-reattach. No push. Findings 1–3 fixed and regression mutations proved; finding 4 and crates/engine untouched. The web Terminals route had no GET /sessions caller on this branch. The commit is clean.

Verbatim scripts/verify fast output:

PASS fast: migrations are append-only
PASS fast: workspace package dependencies
PASS fast: JavaScript dependencies
PASS fast: build web app
PASS fast: cargo fmt --check
PASS fast: cargo clippy
PASS fast: cargo test
PASS fast: svelte-check
PASS fast: UI package svelte-check
PASS fast: stream package typecheck
PASS fast: Vitest
PASS fast: UI package Vitest
PASS fast: stream package Vitest
PASS fast: OpenAPI and TypeScript client drift
PASS fast: terminal TypeScript
PASS fast: terminal Vitest

Verbatim scripts/verify integration attempt 1 output (started load5=5.66):

PASS integration: JavaScript dependencies
PASS integration: build web app
PASS integration: build release binary
PASS integration: real HTTP behavior
PASS integration: Docker socket _ping
PASS integration: rootless Podman socket _ping
PASS integration: engine adapters against Docker and Podman
PASS integration: bounded follow:false log snapshots against Docker and rootless Podman
FAIL integration: TypeScript stream client against Docker and Podman
   Compiling infraternal-server v0.0.1 (/home/kayg/wt/ssh-reattach/crates/server)
    Finished `test` profile [unoptimized] target(s) in 20.71s
     Running tests/stream_e2e.rs (target/debug/deps/stream_e2e-0342476f9bd3402e)

running 1 test
test typescript_client_streams_logs_and_exec_for_docker_and_podman ... 
thread 'typescript_client_streams_logs_and_exec_for_docker_and_podman' (4080034) panicked at crates/server/tests/stream_e2e.rs:366:9:
stream close left an exec shell in podman: PID   PPID  COMMAND
    1     0 sh -c i=0; while [ "$i" -lt 8 ]; do echo infraternal-stream-log; i=$((i + 1)); done; while true; do sleep 60; done
  193     0 /bin/sh
  253     0 ps -o pid,ppid,args

note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
FAILED

failures:

failures:
    typescript_client_streams_logs_and_exec_for_docker_and_podman

test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 4 filtered out; finished in 11.44s

error: test failed, to rerun pass `-p infraternal-server --test stream_e2e`

Verbatim scripts/verify integration attempt 2 output (started load5=7.47):

PASS integration: JavaScript dependencies
PASS integration: build web app
PASS integration: build release binary
PASS integration: real HTTP behavior
PASS integration: Docker socket _ping
PASS integration: rootless Podman socket _ping
PASS integration: engine adapters against Docker and Podman
PASS integration: bounded follow:false log snapshots against Docker and rootless Podman
PASS integration: TypeScript stream client against Docker and Podman
FAIL integration: stream authorization and CLOSE regressions against Docker
   Compiling infraternal-server v0.0.1 (/home/kayg/wt/ssh-reattach/crates/server)
    Finished `test` profile [unoptimized] target(s) in 3.87s
     Running tests/stream_regressions.rs (target/debug/deps/stream_regressions-53fd2437b4851c58)

running 12 tests
test authorization_loss_terminates_detached_persistent_exec_process ... ok
test authorization_loss_terminates_persistent_exec_process ... ok
test authorization_loss_terminates_stalled_stdin_on_both_engines ... 
thread 'authorization_loss_terminates_stalled_stdin_on_both_engines' (46943) panicked at crates/server/tests/stream_regressions.rs:755:13:
sleep did not start on docker: COMMAND
sh -c while :; do sleep 60; done
/bin/sh
ps -o args

note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
FAILED
test client_data_written_after_grant_commit_never_reaches_exec ... ok
test events_channel_replies_to_client_close ... ok
test every_grant_shrink_closes_logs_and_persistent_exec_on_both_engines ... docker role_change both CLOSE forbidden in 73.842657ms
docker role_change owner process reaped in 83.28355ms
docker role_grant_removed both CLOSE forbidden in 11.292834ms
docker role_grant_removed owner process reaped in 85.006743ms
docker role_grant_removed_then_restored both CLOSE forbidden in 86.086296ms
docker transient shrink had an active log stream before mutation and delivered 2 DATA frames after commit before CLOSE
docker role_grant_removed_then_restored owner process reaped in 1.071215526s
docker token_grant_removed both CLOSE forbidden in 99.452694ms
docker token_grant_removed owner process reaped in 1.242132344s
docker tag_change both CLOSE forbidden in 25.697073ms
docker tag_change owner process reaped in 386.938857ms
docker user_disabled both CLOSE forbidden in 37.207239ms
docker user_disabled owner process reaped in 1.21072866s
docker token_revoked both CLOSE forbidden in 84.435916ms
docker token_revoked owner process reaped in 821.875523ms
docker token_expired both CLOSE forbidden in 89.941789ms
docker token_expired owner process reaped in 1.723144473s
podman role_change both CLOSE forbidden in 52.58726ms
podman role_change owner process reaped in 356.323865ms
podman role_grant_removed both CLOSE forbidden in 99.508161ms
podman role_grant_removed owner process reaped in 387.795785ms
podman role_grant_removed_then_restored both CLOSE forbidden in 76.960817ms
podman transient shrink had an active log stream before mutation and delivered 3 DATA frames after commit before CLOSE
podman role_grant_removed_then_restored owner process reaped in 1.391961564s
podman token_grant_removed both CLOSE forbidden in 43.037479ms
podman token_grant_removed owner process reaped in 1.521637363s
podman tag_change both CLOSE forbidden in 150.317101ms
podman tag_change owner process reaped in 3.211051301s
podman user_disabled both CLOSE forbidden in 60.216326ms
podman user_disabled owner process reaped in 1.208586777s
podman token_revoked both CLOSE forbidden in 87.108937ms
podman token_revoked owner process reaped in 1.391165336s
podman token_expired both CLOSE forbidden in 20.938984ms
podman token_expired owner process reaped in 1.104008071s
ok
test failed_dispatch_commit_never_leaves_a_persistent_exec ... ok
test failed_final_open_audit_terminates_new_persistent_exec ... ok
test logs_channel_replies_to_client_close ... ok
test logs_channel_replies_to_close_while_waiting_for_credit ... ok
test removing_a_host_tag_closes_an_existing_channel_with_forbidden ... ok
test session_http_lists_only_the_owner_and_closes_real_docker_and_podman_ptys ... ok

failures:

failures:
    authorization_loss_terminates_stalled_stdin_on_both_engines

test result: FAILED. 11 passed; 1 failed; 0 ignored; 0 measured; 7 filtered out; finished in 132.73s

error: test failed, to rerun pass `-p infraternal-server --test stream_regressions`

Both non-enumerated timing failures passed direct retries, quoted in preceding comments. Integration is not green; do not merge on these results alone. A third attempt was stopped during web build before live tests when its own prestart load5 reading was 8.31, above this job's cutoff. Other jobs currently have concurrent release builds and browser suites; a clean third attempt is pending.

Fix round head: 551d0635628e357dca68f7228221ff6eb35de070 on ssh-reattach. No push. Findings 1–3 fixed and regression mutations proved; finding 4 and crates/engine untouched. The web Terminals route had no GET /sessions caller on this branch. The commit is clean. Verbatim scripts/verify fast output: ``` PASS fast: migrations are append-only PASS fast: workspace package dependencies PASS fast: JavaScript dependencies PASS fast: build web app PASS fast: cargo fmt --check PASS fast: cargo clippy PASS fast: cargo test PASS fast: svelte-check PASS fast: UI package svelte-check PASS fast: stream package typecheck PASS fast: Vitest PASS fast: UI package Vitest PASS fast: stream package Vitest PASS fast: OpenAPI and TypeScript client drift PASS fast: terminal TypeScript PASS fast: terminal Vitest ``` Verbatim scripts/verify integration attempt 1 output (started load5=5.66): ``` PASS integration: JavaScript dependencies PASS integration: build web app PASS integration: build release binary PASS integration: real HTTP behavior PASS integration: Docker socket _ping PASS integration: rootless Podman socket _ping PASS integration: engine adapters against Docker and Podman PASS integration: bounded follow:false log snapshots against Docker and rootless Podman FAIL integration: TypeScript stream client against Docker and Podman Compiling infraternal-server v0.0.1 (/home/kayg/wt/ssh-reattach/crates/server) Finished `test` profile [unoptimized] target(s) in 20.71s Running tests/stream_e2e.rs (target/debug/deps/stream_e2e-0342476f9bd3402e) running 1 test test typescript_client_streams_logs_and_exec_for_docker_and_podman ... thread 'typescript_client_streams_logs_and_exec_for_docker_and_podman' (4080034) panicked at crates/server/tests/stream_e2e.rs:366:9: stream close left an exec shell in podman: PID PPID COMMAND 1 0 sh -c i=0; while [ "$i" -lt 8 ]; do echo infraternal-stream-log; i=$((i + 1)); done; while true; do sleep 60; done 193 0 /bin/sh 253 0 ps -o pid,ppid,args note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace FAILED failures: failures: typescript_client_streams_logs_and_exec_for_docker_and_podman test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 4 filtered out; finished in 11.44s error: test failed, to rerun pass `-p infraternal-server --test stream_e2e` ``` Verbatim scripts/verify integration attempt 2 output (started load5=7.47): ``` PASS integration: JavaScript dependencies PASS integration: build web app PASS integration: build release binary PASS integration: real HTTP behavior PASS integration: Docker socket _ping PASS integration: rootless Podman socket _ping PASS integration: engine adapters against Docker and Podman PASS integration: bounded follow:false log snapshots against Docker and rootless Podman PASS integration: TypeScript stream client against Docker and Podman FAIL integration: stream authorization and CLOSE regressions against Docker Compiling infraternal-server v0.0.1 (/home/kayg/wt/ssh-reattach/crates/server) Finished `test` profile [unoptimized] target(s) in 3.87s Running tests/stream_regressions.rs (target/debug/deps/stream_regressions-53fd2437b4851c58) running 12 tests test authorization_loss_terminates_detached_persistent_exec_process ... ok test authorization_loss_terminates_persistent_exec_process ... ok test authorization_loss_terminates_stalled_stdin_on_both_engines ... thread 'authorization_loss_terminates_stalled_stdin_on_both_engines' (46943) panicked at crates/server/tests/stream_regressions.rs:755:13: sleep did not start on docker: COMMAND sh -c while :; do sleep 60; done /bin/sh ps -o args note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace FAILED test client_data_written_after_grant_commit_never_reaches_exec ... ok test events_channel_replies_to_client_close ... ok test every_grant_shrink_closes_logs_and_persistent_exec_on_both_engines ... docker role_change both CLOSE forbidden in 73.842657ms docker role_change owner process reaped in 83.28355ms docker role_grant_removed both CLOSE forbidden in 11.292834ms docker role_grant_removed owner process reaped in 85.006743ms docker role_grant_removed_then_restored both CLOSE forbidden in 86.086296ms docker transient shrink had an active log stream before mutation and delivered 2 DATA frames after commit before CLOSE docker role_grant_removed_then_restored owner process reaped in 1.071215526s docker token_grant_removed both CLOSE forbidden in 99.452694ms docker token_grant_removed owner process reaped in 1.242132344s docker tag_change both CLOSE forbidden in 25.697073ms docker tag_change owner process reaped in 386.938857ms docker user_disabled both CLOSE forbidden in 37.207239ms docker user_disabled owner process reaped in 1.21072866s docker token_revoked both CLOSE forbidden in 84.435916ms docker token_revoked owner process reaped in 821.875523ms docker token_expired both CLOSE forbidden in 89.941789ms docker token_expired owner process reaped in 1.723144473s podman role_change both CLOSE forbidden in 52.58726ms podman role_change owner process reaped in 356.323865ms podman role_grant_removed both CLOSE forbidden in 99.508161ms podman role_grant_removed owner process reaped in 387.795785ms podman role_grant_removed_then_restored both CLOSE forbidden in 76.960817ms podman transient shrink had an active log stream before mutation and delivered 3 DATA frames after commit before CLOSE podman role_grant_removed_then_restored owner process reaped in 1.391961564s podman token_grant_removed both CLOSE forbidden in 43.037479ms podman token_grant_removed owner process reaped in 1.521637363s podman tag_change both CLOSE forbidden in 150.317101ms podman tag_change owner process reaped in 3.211051301s podman user_disabled both CLOSE forbidden in 60.216326ms podman user_disabled owner process reaped in 1.208586777s podman token_revoked both CLOSE forbidden in 87.108937ms podman token_revoked owner process reaped in 1.391165336s podman token_expired both CLOSE forbidden in 20.938984ms podman token_expired owner process reaped in 1.104008071s ok test failed_dispatch_commit_never_leaves_a_persistent_exec ... ok test failed_final_open_audit_terminates_new_persistent_exec ... ok test logs_channel_replies_to_client_close ... ok test logs_channel_replies_to_close_while_waiting_for_credit ... ok test removing_a_host_tag_closes_an_existing_channel_with_forbidden ... ok test session_http_lists_only_the_owner_and_closes_real_docker_and_podman_ptys ... ok failures: failures: authorization_loss_terminates_stalled_stdin_on_both_engines test result: FAILED. 11 passed; 1 failed; 0 ignored; 0 measured; 7 filtered out; finished in 132.73s error: test failed, to rerun pass `-p infraternal-server --test stream_regressions` ``` Both non-enumerated timing failures passed direct retries, quoted in preceding comments. Integration is not green; do not merge on these results alone. A third attempt was stopped during web build before live tests when its own prestart load5 reading was 8.31, above this job's cutoff. Other jobs currently have concurrent release builds and browser suites; a clean third attempt is pending.
Author
Owner

Fix-round handoff at head 551d063562, branch ssh-reattach, clean worktree; no push. The three assigned findings and regression mutations are complete. scripts/verify fast passed all 15 steps (verbatim output above). Both complete scripts/verify integration attempts failed in different non-enumerated live tests under concurrent load; each failed test passed its direct retry (verbatim output above). Neither failure is being labeled one of the two named known flakes. A third attempt was stopped during web build because its own prestart load5 was 8.31. As of this handoff, other jobs keep load5 above 8, so the required isolated full integration pass is pending. Do not merge until that gate passes or the owner accepts the documented limitation. progress.md is ignored and contains this one-page handoff. Finding 4 and crates/engine remain untouched.

Fix-round handoff at head 551d0635628e357dca68f7228221ff6eb35de070, branch ssh-reattach, clean worktree; no push. The three assigned findings and regression mutations are complete. `scripts/verify fast` passed all 15 steps (verbatim output above). Both complete `scripts/verify integration` attempts failed in different non-enumerated live tests under concurrent load; each failed test passed its direct retry (verbatim output above). Neither failure is being labeled one of the two named known flakes. A third attempt was stopped during web build because its own prestart load5 was 8.31. As of this handoff, other jobs keep load5 above 8, so the required isolated full integration pass is pending. Do not merge until that gate passes or the owner accepts the documented limitation. `progress.md` is ignored and contains this one-page handoff. Finding 4 and crates/engine remain untouched.
Author
Owner

Verification started on branch ssh-reattach at base/head 551d0635628e357dca68f7228221ff6eb35de070. I’m checking findings 1–3 from the review against the fix round, including test mutation proofs and web/audit consumers, then I’ll merge current dev and run the requested gates. Integration will wait until load5 is below 8, with two-minute polling for up to 90 minutes.

Verification started on branch `ssh-reattach` at base/head `551d0635628e357dca68f7228221ff6eb35de070`. I’m checking findings 1–3 from the review against the fix round, including test mutation proofs and web/audit consumers, then I’ll merge current `dev` and run the requested gates. Integration will wait until load5 is below 8, with two-minute polling for up to 90 minutes.
Author
Owner

Findings 1–2 verification on 551d063 (throwaway /home/kayg/wt/verify-21-tmp):

  • Finding 1 is closed. SqliteStorage::owned_stream_sessions uses LIMIT 51; the HTTP handler emits at most 50 rows and returns a cursor. The storage test seeded 121 rows. Fixed version: 1 passed; 0 failed; 21 filtered out. Removing the two LIMIT 51 clauses made that test fail: left: [121, 71, 21], right: [51, 51, 21]. The HTTP page/authorization test passed: 1 passed; 0 failed; 3 filtered out.
  • Finding 2 is closed. Attach, takeover detach, ordinary detach, and exit detach write actor-attributed audit rows inside the same SQLite transaction as the session-state update. Details contain only session_id, attachment_id, and reason; targets are session id and host/engine target. The actor helper reconstructs user/token IDs, token kind, and auth source from the token row; no bearer, SSH key, command, environment value, or terminal data is serialized. Fixed storage test: 1 passed; 0 failed; 21 filtered out. Renaming attach and ordinary-detach actions in the throwaway made it fail at the audit count (left: 1, right: 4).

The Terminals route is still a placeholder (packages/web/src/routes/terminals/+page.svelte); there is no web caller of GET /sessions to regress. MCP and CLI consume SessionListResponse, and MCP forwards next_cursor.

Findings 1–2 verification on `551d063` (throwaway `/home/kayg/wt/verify-21-tmp`): - Finding 1 is closed. `SqliteStorage::owned_stream_sessions` uses `LIMIT 51`; the HTTP handler emits at most 50 rows and returns a cursor. The storage test seeded 121 rows. Fixed version: `1 passed; 0 failed; 21 filtered out`. Removing the two `LIMIT 51` clauses made that test fail: `left: [121, 71, 21]`, `right: [51, 51, 21]`. The HTTP page/authorization test passed: `1 passed; 0 failed; 3 filtered out`. - Finding 2 is closed. Attach, takeover detach, ordinary detach, and exit detach write actor-attributed audit rows inside the same SQLite transaction as the session-state update. Details contain only `session_id`, `attachment_id`, and `reason`; targets are session id and host/engine target. The actor helper reconstructs user/token IDs, token kind, and auth source from the token row; no bearer, SSH key, command, environment value, or terminal data is serialized. Fixed storage test: `1 passed; 0 failed; 21 filtered out`. Renaming attach and ordinary-detach actions in the throwaway made it fail at the audit count (`left: 1`, `right: 4`). The Terminals route is still a placeholder (`packages/web/src/routes/terminals/+page.svelte`); there is no web caller of `GET /sessions` to regress. MCP and CLI consume `SessionListResponse`, and MCP forwards `next_cursor`.
Author
Owner

Finding 3 is closed. In ssh_product.rs, after the channel CLOSE frame is received, the test polls for Detached for up to one second before revoking the creator token; this matches the server’s order of queueing CLOSE before release_session_pair persists detach metadata. The ignored real-sshd test was run with --ignored --exact: 1 passed; 0 failed; 0 ignored; 0 measured; 7 filtered out. In the throwaway, replacing the poll with the prior immediate assertion and adding a test-only 500 ms delay after CLOSE was queued made the assertion fail with left: Attached, right: Detached. The test-owned TestSshd cleanup reaps its listener/watchdog and marked PTYs on unwind.

Finding 3 is closed. In `ssh_product.rs`, after the channel CLOSE frame is received, the test polls for `Detached` for up to one second before revoking the creator token; this matches the server’s order of queueing CLOSE before `release_session_pair` persists detach metadata. The ignored real-`sshd` test was run with `--ignored --exact`: `1 passed; 0 failed; 0 ignored; 0 measured; 7 filtered out`. In the throwaway, replacing the poll with the prior immediate assertion and adding a test-only 500 ms delay after CLOSE was queued made the assertion fail with `left: Attached`, `right: Detached`. The test-owned `TestSshd` cleanup reaps its listener/watchdog and marked PTYs on unwind.
Author
Owner

Integration attempt 1 failed at the pre-existing Podman exec cleanup test (#42); the gate stopped before server/MCP integration tests. At failure observation 11:28:49, uptime was load average: 9.55, 8.84, 9.09 (load5 8.84). The branch changes no crates/engine files.

Gate failure output:

FAIL integration: engine adapters against Docker and Podman
    Finished `test` profile [unoptimized] target(s) in 0.31s
     Running tests/integration.rs (target/debug/deps/integration-f92617287b4ea6a8)

running 11 tests
test docker_and_podman_share_the_real_engine_contract ... infraternal-engine-foreign-docker-458666-1790328259263-0
infraternal-engine-foreign-docker-458666-1790328259263-1
infraternal-engine-foreign-docker-458666-1790328259263-2
time="2026-09-25T11:25:04+02:00" level=warning msg="StopSignal SIGTERM failed to stop container infraternal-engine-foreign-podman-458666-1790328259263-0 in 10 seconds, resorting to SIGKILL"
infraternal-engine-foreign-podman-458666-1790328259263-0
time="2026-09-25T11:25:15+02:00" level=warning msg="StopSignal SIGTERM failed to stop container infraternal-engine-foreign-podman-458666-1790328259263-1 in 10 seconds, resorting to SIGKILL"
infraternal-engine-foreign-podman-458666-1790328259263-1
time="2026-09-25T11:25:26+02:00" level=warning msg="StopSignal SIGTERM failed to stop container infraternal-engine-foreign-podman-458666-1790328259263-2 in 10 seconds, resorting to SIGKILL"
infraternal-engine-foreign-podman-458666-1790328259263-2
ok
test list_preserves_health_and_pod_identity_on_all_real_engines ... ok
test missing_container_scan_tools_report_unconfirmed_when_host_proc_is_restricted ... ok
test podman_completed_containers_are_safe_for_inventory_and_mutations ... ok
test podman_model_preserves_health_and_pod_identity ... ok
test podman_mutation_response_loss_is_unknown_outcome ... ok
test pty_close_reaps_setsid_and_double_fork_descendants ... ok
test pty_close_reaps_term_ignoring_group_child_after_leader_exits ... docker same-group child reaped in 649.629068ms
podman same-group child reaped in 1.585937024s
ok
test pty_session_drop_and_close_terminate_exec_processes_on_all_real_engines ... 
thread 'pty_session_drop_and_close_terminate_exec_processes_on_all_real_engines' (479443) panicked at crates/engine/tests/integration.rs:875:5:
container shell after drop pid 18 remained in process table: PID   PPID  COMMAND
    1     0 sh -c printf 'stdout-line\\n'; printf 'stderr-line\\n' >&2; i=0; while [ $i -lt 65600 ]; do printf x; i=$((i+1)); done; printf '\\n'; i=0; while [ $i -lt 65600 ]; do printf y >&2; i=$((i+1)); done; printf '\\n' >&2; while :; do sleep 1; done
   18     0 /bin/sh -c (while :; do sleep 1; done) & helper=$!; echo pty-marker=infraternal_pty_cleanup_458666-1790328439371_podman shell=$$ helper=$helper; wait
   24    18 /bin/sh -c (while :; do sleep 1; done) & helper=$!; echo pty-marker=infraternal_pty_cleanup_458666-1790328439371_podman shell=$$ helper=$helper; wait
  453     0 ps -o pid,ppid,args

note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
FAILED
test rootful_podman_covers_inventory_and_mutations ... ok
test stalled_pty_stdin_cannot_hold_exec_termination ... docker stalled stdin + ignored SIGTERM reaped in 579.113759ms
podman stalled stdin + ignored SIGTERM reaped in 1.415095634s
ok

failures:

failures:
    pty_session_drop_and_close_terminate_exec_processes_on_all_real_engines

test result: FAILED. 10 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 255.28s

error: test failed, to rerun pass `-p infraternal-engine --test integration`

Required direct retry (one run, same real-engine test):

    Finished `test` profile [unoptimized] target(s) in 0.23s
     Running tests/integration.rs (target/debug/deps/integration-f92617287b4ea6a8)

running 1 test
test pty_session_drop_and_close_terminate_exec_processes_on_all_real_engines ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 10 filtered out; finished in 36.20s
Integration attempt 1 failed at the pre-existing Podman exec cleanup test (#42); the gate stopped before server/MCP integration tests. At failure observation 11:28:49, `uptime` was `load average: 9.55, 8.84, 9.09` (load5 8.84). The branch changes no `crates/engine` files. Gate failure output: ```text FAIL integration: engine adapters against Docker and Podman Finished `test` profile [unoptimized] target(s) in 0.31s Running tests/integration.rs (target/debug/deps/integration-f92617287b4ea6a8) running 11 tests test docker_and_podman_share_the_real_engine_contract ... infraternal-engine-foreign-docker-458666-1790328259263-0 infraternal-engine-foreign-docker-458666-1790328259263-1 infraternal-engine-foreign-docker-458666-1790328259263-2 time="2026-09-25T11:25:04+02:00" level=warning msg="StopSignal SIGTERM failed to stop container infraternal-engine-foreign-podman-458666-1790328259263-0 in 10 seconds, resorting to SIGKILL" infraternal-engine-foreign-podman-458666-1790328259263-0 time="2026-09-25T11:25:15+02:00" level=warning msg="StopSignal SIGTERM failed to stop container infraternal-engine-foreign-podman-458666-1790328259263-1 in 10 seconds, resorting to SIGKILL" infraternal-engine-foreign-podman-458666-1790328259263-1 time="2026-09-25T11:25:26+02:00" level=warning msg="StopSignal SIGTERM failed to stop container infraternal-engine-foreign-podman-458666-1790328259263-2 in 10 seconds, resorting to SIGKILL" infraternal-engine-foreign-podman-458666-1790328259263-2 ok test list_preserves_health_and_pod_identity_on_all_real_engines ... ok test missing_container_scan_tools_report_unconfirmed_when_host_proc_is_restricted ... ok test podman_completed_containers_are_safe_for_inventory_and_mutations ... ok test podman_model_preserves_health_and_pod_identity ... ok test podman_mutation_response_loss_is_unknown_outcome ... ok test pty_close_reaps_setsid_and_double_fork_descendants ... ok test pty_close_reaps_term_ignoring_group_child_after_leader_exits ... docker same-group child reaped in 649.629068ms podman same-group child reaped in 1.585937024s ok test pty_session_drop_and_close_terminate_exec_processes_on_all_real_engines ... thread 'pty_session_drop_and_close_terminate_exec_processes_on_all_real_engines' (479443) panicked at crates/engine/tests/integration.rs:875:5: container shell after drop pid 18 remained in process table: PID PPID COMMAND 1 0 sh -c printf 'stdout-line\\n'; printf 'stderr-line\\n' >&2; i=0; while [ $i -lt 65600 ]; do printf x; i=$((i+1)); done; printf '\\n'; i=0; while [ $i -lt 65600 ]; do printf y >&2; i=$((i+1)); done; printf '\\n' >&2; while :; do sleep 1; done 18 0 /bin/sh -c (while :; do sleep 1; done) & helper=$!; echo pty-marker=infraternal_pty_cleanup_458666-1790328439371_podman shell=$$ helper=$helper; wait 24 18 /bin/sh -c (while :; do sleep 1; done) & helper=$!; echo pty-marker=infraternal_pty_cleanup_458666-1790328439371_podman shell=$$ helper=$helper; wait 453 0 ps -o pid,ppid,args note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace FAILED test rootful_podman_covers_inventory_and_mutations ... ok test stalled_pty_stdin_cannot_hold_exec_termination ... docker stalled stdin + ignored SIGTERM reaped in 579.113759ms podman stalled stdin + ignored SIGTERM reaped in 1.415095634s ok failures: failures: pty_session_drop_and_close_terminate_exec_processes_on_all_real_engines test result: FAILED. 10 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 255.28s error: test failed, to rerun pass `-p infraternal-engine --test integration` ``` Required direct retry (one run, same real-engine test): ```text Finished `test` profile [unoptimized] target(s) in 0.23s Running tests/integration.rs (target/debug/deps/integration-f92617287b4ea6a8) running 1 test test pty_session_drop_and_close_terminate_exec_processes_on_all_real_engines ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 10 filtered out; finished in 36.20s ```
Author
Owner

Verdict: NOT VERIFIED. Step 21 findings 1–3 are closed, but integration has a blocker in the new CLI SSH reattach path. No fix was made because the failure is not caused by merging dev, and this job only permits merge-caused fixes.

Merge head: 551d0635628e357dca68f7228221ff6eb35de070. origin/dev was fetched at dbd66850f8a5d6190e65b4bd364e075950033425, already an ancestor; merge reported Already up to date. No push.

fast exited 0. Verbatim gate output:

PASS fast: migrations are append-only
PASS fast: workspace package dependencies
PASS fast: JavaScript dependencies
PASS fast: build web app
PASS fast: cargo fmt --check
PASS fast: cargo clippy
PASS fast: cargo test
PASS fast: svelte-check
PASS fast: UI package svelte-check
PASS fast: stream package typecheck
PASS fast: Vitest
PASS fast: UI package Vitest
PASS fast: stream package Vitest
PASS fast: OpenAPI and TypeScript client drift
PASS fast: terminal TypeScript
PASS fast: terminal Vitest

Integration attempt 1 stopped at the known Podman exec cleanup flake (#42); it reported 10 passed and 1 failed. The failure and the required direct retry (1 passed; 0 failed) are quoted in my preceding #39 comment. Load5 at failure observation was 8.84.

Integration attempt 2 started at load5 6.84 and passed through the server resource API, then failed in cli_and_mcp_use_the_public_http_contract. The gate first observed the Podman exec exit-code assertion (Some(7) instead of Some(23)) at load5 9.48. As required, I ran this test directly once. That retry reached the Step 21 CLI SIGKILL/SSH replay case and failed at cli_mcp.rs:2887 because the post-kill output marker was missing. Load5 at that failure observation was 9.06. This is the blocker; no second direct retry was run.

Verbatim output from integration attempt 2:

PASS integration: JavaScript dependencies
PASS integration: build web app
PASS integration: build release binary
PASS integration: real HTTP behavior
PASS integration: Docker socket _ping
PASS integration: rootless Podman socket _ping
PASS integration: engine adapters against Docker and Podman
PASS integration: bounded follow:false log snapshots against Docker and rootless Podman
PASS integration: TypeScript stream client against Docker and Podman
PASS integration: stream authorization and CLOSE regressions against Docker
PASS integration: persistent PTY termination preempts blocked send
PASS integration: resource HTTP API against Docker and rootless Podman
FAIL integration: compiled CLI and MCP against real server and engines
   Compiling infraternal-server v0.0.1 (/home/kayg/wt/ssh-reattach/crates/server)
   Compiling infraternal v0.0.1 (/home/kayg/wt/ssh-reattach/crates/infraternal)
    Finished `test` profile [unoptimized] target(s) in 17.27s
     Running tests/cli_mcp.rs (target/debug/deps/cli_mcp-94557349a527577f)

running 1 test
test cli_and_mcp_use_the_public_http_contract ... Warning: the OS keychain is unavailable; using a permission-restricted credential file.
CLI_MCP_SLOW_COMMAND command=logs elapsed_ms=10085
STREAM_EXEC_RTT_MS runtime=docker elapsed_ms=411
CLI_MCP_SLOW_COMMAND command=logs elapsed_ms=10009

thread 'cli_and_mcp_use_the_public_http_contract' (620355) panicked at crates/infraternal/tests/cli_mcp.rs:599:9:
assertion `left == right` failed: podman exec must return the remote exit code: Warning: the OS keychain is unavailable; using a permission-restricted credential file.
error: could not write command output: Broken pipe (os error 32)

  left: Some(7)
 right: Some(23)
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
FAILED

failures:

failures:
    cli_and_mcp_use_the_public_http_contract

test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 91.96s

error: test failed, to rerun pass `-p infraternal --test cli_mcp`

Verbatim direct retry output:

    Finished `test` profile [unoptimized] target(s) in 0.42s
     Running tests/cli_mcp.rs (target/debug/deps/cli_mcp-94557349a527577f)

running 1 test
test cli_and_mcp_use_the_public_http_contract ...

thread 'cli_and_mcp_use_the_public_http_contract' (626779) panicked at crates/infraternal/tests/cli_mcp.rs:2887:5:
assertion failed: after_kill.output.contains("__CLI_SSH_REPLAY_AFTER__")
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
FAILED

failures:

failures:
    cli_and_mcp_use_the_public_http_contract

test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 27.68s

error: test failed, to rerun pass `-p infraternal --test cli_mcp`
**Verdict: NOT VERIFIED.** Step 21 findings 1–3 are closed, but integration has a blocker in the new CLI SSH reattach path. No fix was made because the failure is not caused by merging `dev`, and this job only permits merge-caused fixes. **Merge head:** `551d0635628e357dca68f7228221ff6eb35de070`. `origin/dev` was fetched at `dbd66850f8a5d6190e65b4bd364e075950033425`, already an ancestor; merge reported `Already up to date.` No push. `fast` exited 0. Verbatim gate output: ```text PASS fast: migrations are append-only PASS fast: workspace package dependencies PASS fast: JavaScript dependencies PASS fast: build web app PASS fast: cargo fmt --check PASS fast: cargo clippy PASS fast: cargo test PASS fast: svelte-check PASS fast: UI package svelte-check PASS fast: stream package typecheck PASS fast: Vitest PASS fast: UI package Vitest PASS fast: stream package Vitest PASS fast: OpenAPI and TypeScript client drift PASS fast: terminal TypeScript PASS fast: terminal Vitest ``` Integration attempt 1 stopped at the known Podman exec cleanup flake (#42); it reported 10 passed and 1 failed. The failure and the required direct retry (`1 passed; 0 failed`) are quoted in my preceding #39 comment. Load5 at failure observation was 8.84. Integration attempt 2 started at load5 6.84 and passed through the server resource API, then failed in `cli_and_mcp_use_the_public_http_contract`. The gate first observed the Podman exec exit-code assertion (`Some(7)` instead of `Some(23)`) at load5 9.48. As required, I ran this test directly once. That retry reached the Step 21 CLI SIGKILL/SSH replay case and failed at `cli_mcp.rs:2887` because the post-kill output marker was missing. Load5 at that failure observation was 9.06. This is the blocker; no second direct retry was run. Verbatim output from integration attempt 2: ```text PASS integration: JavaScript dependencies PASS integration: build web app PASS integration: build release binary PASS integration: real HTTP behavior PASS integration: Docker socket _ping PASS integration: rootless Podman socket _ping PASS integration: engine adapters against Docker and Podman PASS integration: bounded follow:false log snapshots against Docker and rootless Podman PASS integration: TypeScript stream client against Docker and Podman PASS integration: stream authorization and CLOSE regressions against Docker PASS integration: persistent PTY termination preempts blocked send PASS integration: resource HTTP API against Docker and rootless Podman FAIL integration: compiled CLI and MCP against real server and engines Compiling infraternal-server v0.0.1 (/home/kayg/wt/ssh-reattach/crates/server) Compiling infraternal v0.0.1 (/home/kayg/wt/ssh-reattach/crates/infraternal) Finished `test` profile [unoptimized] target(s) in 17.27s Running tests/cli_mcp.rs (target/debug/deps/cli_mcp-94557349a527577f) running 1 test test cli_and_mcp_use_the_public_http_contract ... Warning: the OS keychain is unavailable; using a permission-restricted credential file. CLI_MCP_SLOW_COMMAND command=logs elapsed_ms=10085 STREAM_EXEC_RTT_MS runtime=docker elapsed_ms=411 CLI_MCP_SLOW_COMMAND command=logs elapsed_ms=10009 thread 'cli_and_mcp_use_the_public_http_contract' (620355) panicked at crates/infraternal/tests/cli_mcp.rs:599:9: assertion `left == right` failed: podman exec must return the remote exit code: Warning: the OS keychain is unavailable; using a permission-restricted credential file. error: could not write command output: Broken pipe (os error 32) left: Some(7) right: Some(23) note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace FAILED failures: failures: cli_and_mcp_use_the_public_http_contract test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 91.96s error: test failed, to rerun pass `-p infraternal --test cli_mcp` ``` Verbatim direct retry output: ```text Finished `test` profile [unoptimized] target(s) in 0.42s Running tests/cli_mcp.rs (target/debug/deps/cli_mcp-94557349a527577f) running 1 test test cli_and_mcp_use_the_public_http_contract ... thread 'cli_and_mcp_use_the_public_http_contract' (626779) panicked at crates/infraternal/tests/cli_mcp.rs:2887:5: assertion failed: after_kill.output.contains("__CLI_SSH_REPLAY_AFTER__") note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace FAILED failures: failures: cli_and_mcp_use_the_public_http_contract test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 27.68s error: test failed, to rerun pass `-p infraternal --test cli_mcp` ```
Author
Owner

Starting fix-21b on branch ssh-reattach, base head 551d0635628e357dca68f7228221ff6eb35de070. I am tracing the replay-marker scenario, then will measure the requested 20-run branch loop and 10-run dev dbd6685 loop before choosing a product fix or deterministic test correction.

Starting fix-21b on branch `ssh-reattach`, base head `551d0635628e357dca68f7228221ff6eb35de070`. I am tracing the replay-marker scenario, then will measure the requested 20-run branch loop and 10-run dev `dbd6685` loop before choosing a product fix or deterministic test correction.
Author
Owner

Starting fix-21b on branch ssh-reattach, base head 551d0635628e357dca68f7228221ff6eb35de070. I am tracing the replay-marker scenario, then will measure the requested 20-run branch loop and 10-run dev dbd6685 loop before choosing a product fix or deterministic test correction.

Starting fix-21b on branch `ssh-reattach`, base head `551d0635628e357dca68f7228221ff6eb35de070`. I am tracing the replay-marker scenario, then will measure the requested 20-run branch loop and 10-run dev `dbd6685` loop before choosing a product fix or deterministic test correction.
Author
Owner

Reproduction evidence before the deterministic test change: one full current-branch run failed at the reported __CLI_SSH_REPLAY_AFTER__ assertion. The focused SIGKILL loop passed 20/20 (0/20 failures; load averages at start 8.21/6.29/6.94 and end 9.91/9.08/8.11). On dev dbd6685, the SIGHUP loop passed 9/10; the single failure timed out waiting for the CLI to exit after captured output already contained AFTER, so it was not a marker assertion failure (load start 8.34/9.24/8.46, end 7.59/7.86/8.04). In crates/ssh/src/session.rs, output is appended to the replay buffer before it is fanned out. The test reattached immediately after killing the CLI, five seconds before the remote command wrote AFTER; I am treating this as a test race and verifying with an observable-state wait.

Reproduction evidence before the deterministic test change: one full current-branch run failed at the reported `__CLI_SSH_REPLAY_AFTER__` assertion. The focused SIGKILL loop passed 20/20 (0/20 failures; load averages at start 8.21/6.29/6.94 and end 9.91/9.08/8.11). On `dev` dbd6685, the SIGHUP loop passed 9/10; the single failure timed out waiting for the CLI to exit after captured output already contained `AFTER`, so it was not a marker assertion failure (load start 8.34/9.24/8.46, end 7.59/7.86/8.04). In `crates/ssh/src/session.rs`, output is appended to the replay buffer before it is fanned out. The test reattached immediately after killing the CLI, five seconds before the remote command wrote `AFTER`; I am treating this as a test race and verifying with an observable-state wait.
Author
Owner

Root cause: (b), a test race. The CLI test killed its client after BEFORE appeared, then reattached immediately while the remote shell was still in sleep 5; it did not wait for AFTER to be produced. The PTY harness also stopped draining shortly after client exit. crates/ssh/src/session.rs appends each output chunk to the replay buffer before fan-out (record_output, lines 790–805). The deterministic test now waits for detached state, waits for a unique remote progress file written after AFTER, confirms the actual bytes with bounded MCP reads, and then requires the CLI reattach to replay them before the shell exits.

Reproduction evidence (load averages shown as 1/5/15 minutes):

  • One full run before isolation reproduced the reported assertion once, at line 2887; load was 7.73, 8.12, 8.74.
  • Requested pre-fix current-branch SIGKILL loop: 0/20 marker failures; load started 8.21, 6.29, 6.94 and ended 9.91, 9.08, 8.11.
  • Requested pre-fix dev dbd6685 SIGHUP loop: 0/10 marker failures; 9/10 completed, and the other run hit the PTY harness's CLI-exit timeout after captured output already contained AFTER. Load started 8.34, 9.24, 8.46 and ended 7.59, 7.86, 8.04.
  • After the test change, the current-branch SIGKILL loop passed 20/20; load started 2.01, 3.25, 5.06 and ended 7.25, 5.28, 5.42.

Head: fed23a4818ed53a78872b61143ddacccbd5a649d on ssh-reattach (not pushed). Both gates passed; output quoted verbatim:

PASS fast: migrations are append-only
PASS fast: workspace package dependencies
PASS fast: JavaScript dependencies
PASS fast: build web app
PASS fast: cargo fmt --check
PASS fast: cargo clippy
PASS fast: cargo test
PASS fast: svelte-check
PASS fast: UI package svelte-check
PASS fast: stream package typecheck
PASS fast: Vitest
PASS fast: UI package Vitest
PASS fast: stream package Vitest
PASS fast: OpenAPI and TypeScript client drift
PASS fast: terminal TypeScript
PASS fast: terminal Vitest
PASS integration: JavaScript dependencies
PASS integration: build web app
PASS integration: build release binary
PASS integration: real HTTP behavior
PASS integration: Docker socket _ping
PASS integration: rootless Podman socket _ping
PASS integration: engine adapters against Docker and Podman
PASS integration: bounded follow:false log snapshots against Docker and rootless Podman
PASS integration: TypeScript stream client against Docker and Podman
PASS integration: stream authorization and CLOSE regressions against Docker
PASS integration: persistent PTY termination preempts blocked send
PASS integration: resource HTTP API against Docker and rootless Podman
PASS integration: compiled CLI and MCP against real server and engines
PASS integration: SSH contract against isolated real sshd
PASS integration: SSH product API and stream against isolated real sshd
Root cause: **(b), a test race.** The CLI test killed its client after `BEFORE` appeared, then reattached immediately while the remote shell was still in `sleep 5`; it did not wait for `AFTER` to be produced. The PTY harness also stopped draining shortly after client exit. `crates/ssh/src/session.rs` appends each output chunk to the replay buffer before fan-out (`record_output`, lines 790–805). The deterministic test now waits for detached state, waits for a unique remote progress file written after `AFTER`, confirms the actual bytes with bounded MCP reads, and then requires the CLI reattach to replay them before the shell exits. Reproduction evidence (load averages shown as 1/5/15 minutes): - One full run before isolation reproduced the reported assertion once, at line 2887; load was `7.73, 8.12, 8.74`. - Requested pre-fix current-branch SIGKILL loop: **0/20 marker failures**; load started `8.21, 6.29, 6.94` and ended `9.91, 9.08, 8.11`. - Requested pre-fix `dev` `dbd6685` SIGHUP loop: **0/10 marker failures**; 9/10 completed, and the other run hit the PTY harness's CLI-exit timeout after captured output already contained `AFTER`. Load started `8.34, 9.24, 8.46` and ended `7.59, 7.86, 8.04`. - After the test change, the current-branch SIGKILL loop passed **20/20**; load started `2.01, 3.25, 5.06` and ended `7.25, 5.28, 5.42`. Head: `fed23a4818ed53a78872b61143ddacccbd5a649d` on `ssh-reattach` (not pushed). Both gates passed; output quoted verbatim: ```text PASS fast: migrations are append-only PASS fast: workspace package dependencies PASS fast: JavaScript dependencies PASS fast: build web app PASS fast: cargo fmt --check PASS fast: cargo clippy PASS fast: cargo test PASS fast: svelte-check PASS fast: UI package svelte-check PASS fast: stream package typecheck PASS fast: Vitest PASS fast: UI package Vitest PASS fast: stream package Vitest PASS fast: OpenAPI and TypeScript client drift PASS fast: terminal TypeScript PASS fast: terminal Vitest ``` ```text PASS integration: JavaScript dependencies PASS integration: build web app PASS integration: build release binary PASS integration: real HTTP behavior PASS integration: Docker socket _ping PASS integration: rootless Podman socket _ping PASS integration: engine adapters against Docker and Podman PASS integration: bounded follow:false log snapshots against Docker and rootless Podman PASS integration: TypeScript stream client against Docker and Podman PASS integration: stream authorization and CLOSE regressions against Docker PASS integration: persistent PTY termination preempts blocked send PASS integration: resource HTTP API against Docker and rootless Podman PASS integration: compiled CLI and MCP against real server and engines PASS integration: SSH contract against isolated real sshd PASS integration: SSH product API and stream against isolated real sshd ```
Author
Owner

Starting merge job on branch ssh-reattach, based at fed23a4818ed53a78872b61143ddacccbd5a649d.

I will integrate the current dev head into step 21, regenerate OpenAPI and the API client if needed, verify that remote SSH remains unsupported while reattach and attachment audit semantics remain intact, then run the requested gates. No push.

Starting merge job on branch `ssh-reattach`, based at `fed23a4818ed53a78872b61143ddacccbd5a649d`. I will integrate the current `dev` head into step 21, regenerate OpenAPI and the API client if needed, verify that remote SSH remains unsupported while reattach and attachment audit semantics remain intact, then run the requested gates. No push.
Author
Owner

Merge finding: crates/server/tests/migrations.rs was the only content conflict. The merged migration history includes remote agents at 0015 and session attachment audit at step 21's 0016; the migration test helper now expects the contiguous sequence 1..=16. scripts/verify fast contains the append-only migration gate and will be run on the merge result.

Merge finding: `crates/server/tests/migrations.rs` was the only content conflict. The merged migration history includes remote agents at `0015` and session attachment audit at step 21's `0016`; the migration test helper now expects the contiguous sequence `1..=16`. `scripts/verify fast` contains the append-only migration gate and will be run on the merge result.
Author
Owner

Fast gate passed on the merge result before commit. Verbatim scripts/verify fast output:

WARN load5=8.73 exceeds online CPU count=8; timing-sensitive checks may be delayed
PASS fast: migrations are append-only
PASS fast: workspace package dependencies
PASS fast: JavaScript dependencies
PASS fast: build web app
PASS fast: cargo fmt --check
PASS fast: cargo clippy
PASS fast: cargo test
PASS fast: svelte-check
PASS fast: UI package svelte-check
PASS fast: stream package typecheck
PASS fast: Vitest
PASS fast: UI package Vitest
PASS fast: stream package Vitest
PASS fast: OpenAPI and TypeScript client drift
PASS fast: terminal TypeScript
PASS fast: terminal Vitest
Fast gate passed on the merge result before commit. Verbatim `scripts/verify fast` output: ```text WARN load5=8.73 exceeds online CPU count=8; timing-sensitive checks may be delayed PASS fast: migrations are append-only PASS fast: workspace package dependencies PASS fast: JavaScript dependencies PASS fast: build web app PASS fast: cargo fmt --check PASS fast: cargo clippy PASS fast: cargo test PASS fast: svelte-check PASS fast: UI package svelte-check PASS fast: stream package typecheck PASS fast: Vitest PASS fast: UI package Vitest PASS fast: stream package Vitest PASS fast: OpenAPI and TypeScript client drift PASS fast: terminal TypeScript PASS fast: terminal Vitest ```
Author
Owner

Merge commit: d9197837c5adb20ad0da2a6b8872ed2826a92aee (parents fed23a4 and b63a853; worktree clean). At 14:41 UTC the integration load gate reported load5 10.46; I am following the requested two-minute polling interval until it is below 8, for up to 60 minutes.

Merge commit: `d9197837c5adb20ad0da2a6b8872ed2826a92aee` (parents `fed23a4` and `b63a853`; worktree clean). At 14:41 UTC the integration load gate reported load5 `10.46`; I am following the requested two-minute polling interval until it is below 8, for up to 60 minutes.
Author
Owner

Correction to the prior timestamp: uptime displayed 14:41 CEST, which was 12:41 UTC; load5 then was 10.46. At the 12:43:49 UTC poll, load5 was 8.97, still above the < 8 integration threshold.

Correction to the prior timestamp: `uptime` displayed 14:41 CEST, which was 12:41 UTC; load5 then was `10.46`. At the 12:43:49 UTC poll, load5 was `8.97`, still above the `< 8` integration threshold.
Author
Owner

At 12:50:56 UTC, load5 was 6.38 (below 8), so I started scripts/verify integration on merge commit d9197837c5adb20ad0da2a6b8872ed2826a92aee.

At 12:50:56 UTC, load5 was `6.38` (below 8), so I started `scripts/verify integration` on merge commit `d9197837c5adb20ad0da2a6b8872ed2826a92aee`.
Author
Owner

Merge job complete. Head: d9197837c5adb20ad0da2a6b8872ed2826a92aee (parents fed23a4818ed53a78872b61143ddacccbd5a649d and b63a853186e046a774ff367ee74f9f4d175e58a7). The worktree is clean; no push.

Conflict resolution: crates/server/tests/migrations.rs was the only content conflict. The merged helper and upgrade assertions expect migrations 1..=16, preserving 0015_remote_agents.sql and step 21's 0016_session_attachment_audit.sql. stream.rs, CLI/MCP registration, contracts, and generated files merged automatically. I regenerated docs/openapi.json with infraternal openapi, packages/api-client/src/schema.ts with openapi-typescript, and the generated client with its generator script.

Coexistence check: remote-host SSH OPEN still returns unsupported, asserted by the tunnel integration test. Step 21's reattach authorization still checks owner, kind, and target; attachment state and audit writes remain transactional and covered by storage and SSH product tests. The integration gate passed the SSH product path and remote mTLS infraternal agent enrollment/exec/revoke path.

scripts/verify fast (exit 0), verbatim output:

WARN load5=8.73 exceeds online CPU count=8; timing-sensitive checks may be delayed
PASS fast: migrations are append-only
PASS fast: workspace package dependencies
PASS fast: JavaScript dependencies
PASS fast: build web app
PASS fast: cargo fmt --check
PASS fast: cargo clippy
PASS fast: cargo test
PASS fast: svelte-check
PASS fast: UI package svelte-check
PASS fast: stream package typecheck
PASS fast: Vitest
PASS fast: UI package Vitest
PASS fast: stream package Vitest
PASS fast: OpenAPI and TypeScript client drift
PASS fast: terminal TypeScript
PASS fast: terminal Vitest

scripts/verify integration (exit 0), verbatim output:

PASS integration: JavaScript dependencies
PASS integration: build web app
PASS integration: build release binary
PASS integration: real HTTP behavior
PASS integration: Docker socket _ping
PASS integration: rootless Podman socket _ping
PASS integration: engine adapters against Docker and Podman
PASS integration: bounded follow:false log snapshots against Docker and rootless Podman
PASS integration: TypeScript stream client against Docker and Podman
PASS integration: stream authorization and CLOSE regressions against Docker
PASS integration: persistent PTY termination preempts blocked send
PASS integration: resource HTTP API against Docker and rootless Podman
PASS integration: compiled CLI and MCP against real server and engines
PASS integration: SSH contract against isolated real sshd
PASS integration: SSH product API and stream against isolated real sshd
PASS integration: remote mTLS infraternal agent enroll, rotate, list, exec and revoke against Docker
Merge job complete. Head: `d9197837c5adb20ad0da2a6b8872ed2826a92aee` (parents `fed23a4818ed53a78872b61143ddacccbd5a649d` and `b63a853186e046a774ff367ee74f9f4d175e58a7`). The worktree is clean; no push. Conflict resolution: `crates/server/tests/migrations.rs` was the only content conflict. The merged helper and upgrade assertions expect migrations `1..=16`, preserving `0015_remote_agents.sql` and step 21's `0016_session_attachment_audit.sql`. `stream.rs`, CLI/MCP registration, contracts, and generated files merged automatically. I regenerated `docs/openapi.json` with `infraternal openapi`, `packages/api-client/src/schema.ts` with `openapi-typescript`, and the generated client with its generator script. Coexistence check: remote-host SSH OPEN still returns `unsupported`, asserted by the tunnel integration test. Step 21's reattach authorization still checks owner, kind, and target; attachment state and audit writes remain transactional and covered by storage and SSH product tests. The integration gate passed the SSH product path and remote mTLS infraternal agent enrollment/exec/revoke path. `scripts/verify fast` (exit 0), verbatim output: ```text WARN load5=8.73 exceeds online CPU count=8; timing-sensitive checks may be delayed PASS fast: migrations are append-only PASS fast: workspace package dependencies PASS fast: JavaScript dependencies PASS fast: build web app PASS fast: cargo fmt --check PASS fast: cargo clippy PASS fast: cargo test PASS fast: svelte-check PASS fast: UI package svelte-check PASS fast: stream package typecheck PASS fast: Vitest PASS fast: UI package Vitest PASS fast: stream package Vitest PASS fast: OpenAPI and TypeScript client drift PASS fast: terminal TypeScript PASS fast: terminal Vitest ``` `scripts/verify integration` (exit 0), verbatim output: ```text PASS integration: JavaScript dependencies PASS integration: build web app PASS integration: build release binary PASS integration: real HTTP behavior PASS integration: Docker socket _ping PASS integration: rootless Podman socket _ping PASS integration: engine adapters against Docker and Podman PASS integration: bounded follow:false log snapshots against Docker and rootless Podman PASS integration: TypeScript stream client against Docker and Podman PASS integration: stream authorization and CLOSE regressions against Docker PASS integration: persistent PTY termination preempts blocked send PASS integration: resource HTTP API against Docker and rootless Podman PASS integration: compiled CLI and MCP against real server and engines PASS integration: SSH contract against isolated real sshd PASS integration: SSH product API and stream against isolated real sshd PASS integration: remote mTLS infraternal agent enroll, rotate, list, exec and revoke against Docker ```
Commenting is not possible because the repository is archived.
No labels
No milestone
No project
No assignees
1 participant
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
kayg/infraternal-v0#39
No description provided.