fix: move network checks off the session-start blocking path - #1860
Merged
Conversation
The session-start digest runs on a session-open hook that blocks session initialization, and every external-network call it made was individually unbounded: `gh auth status`, secondmate liveness, secondmate convergence, pending remote handoff delivery, and the fleet-sync fetch. One unreachable remote secondmate could consume the whole FM_SESSION_START_TIMEOUT and truncate the digest, so a slow network could cost the work queue itself. Measured against a host hanging 25s per SSH connection, that startup took 1m18s. The digest is now composed from local reads alone. bin/fm-startup-network.sh runs the same checks concurrently in a bounded detached worker and the digest harvests whatever finished, without ever waiting. Same fixture: 0.84s. Nothing is dropped. fm-bootstrap.sh stays the single owner of every sweep and still runs all of them, through a new FM_BOOTSTRAP_NETWORK phase split whose `skip` and `only` halves are a partition of the unsplit run. Deferral is safe because the sweeps are idempotent detectors, the result is durable and always surfaces (inline, or as a `check: startup-network` wake), and the worker re-verifies that the fleet lock still names the session that asked before it mutates anything. While the worker is still running the digest names exactly what is unconfirmed rather than implying it passed. A relaunch performed by the deferred pass is now always reported, because the digest that printed the superseded endpoint record is already out. Also collapses the duplicate tasks-axi compatibility probe: the verdict is computed once and handed to the bootstrap child for one process hop, then consumed so it never reaches a spawned agent's environment. 10 tasks-axi invocations per startup become 7. Verified on Claude Code 2.1.222 that a worker detached by the session-open hook survives the hook returning, the one vendor behavior this design needs and no portable test can see. Re-landed on current main, superseding PR #1845, which was cut from a pre-#1842 base. The digest's section numbering in AGENTS.md section 3 now states the emission order directly - supervision block and its read-once contract, fleet state, network checks, then context - which keeps #1826's fleet-state-before-context ordering. The old-bin test shim keeps main's git-archive baseline from #1851, which already subsumes this branch's reason for widening that shim.
…ent base Re-runs the unreachable-remote latency fixture against default-branch tip 8398d31 rather than the now-historical 345de4e, and records the sweep-result comparison the deferral's safety argument rests on: the deferred worker's published report is byte-identical to the three sweep lines the blocking baseline printed, with the unreachable route preserved in both.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Intent
Re-land the network-free session-start change cleanly on current main. It previously shipped green as PR #1845 but was cut from a pre-#1842 base and can no longer merge cleanly, so this is a fresh branch off current origin/main with the #1845 work re-applied and every conflict resolved. The old branch was deliberately NOT force-pushed, to avoid an AXI custody deadlock with its still-active run; #1845 gets closed as superseded once this lands.
What the change delivers (preserve this intent fully): session start prints its digest from local state alone, with zero synchronous external-network call on the blocking path. Every network check a session start owes - GitHub auth, dead-secondmate relaunch, secondmate convergence, pending handoff delivery, and project clone refresh - still RUNS with its safety guarantees intact, but concurrently in a bounded detached worker owned by the new bin/fm-startup-network.sh, reported in the digest's own NETWORK CHECKS section. bin/fm-bootstrap.sh remains the single owner of every sweep; the new FM_BOOTSTRAP_NETWORK phase split ('skip'/'only') is a partition of the unsplit run and changes only WHEN each sweep runs, never WHETHER. Unrecognized values fall back to 'all' on purpose so a typo can never silently skip a safety sweep. The duplicate tasks-axi compatibility probe is collapsed so the verdict is computed once (10 tasks-axi invocations per startup become 7).
Captain-accepted design decision on the deferred-report race, already settled and deliberate: suppress the deferred sweep wake ONLY after a durable harvest acknowledgement. No per-generation bookkeeping - next-session re-derivation covers the overwrite case, because these sweeps are idempotent detectors. Do not flag the absence of per-generation bookkeeping as a gap; it was chosen.
Conflict resolution decisions made here, all deliberate:
Empirical verification done on this base, recorded in docs/verification/supervision.md: against a fixture home with one remote secondmate whose host hangs 25s per SSH connection, session start went from 1m21.15s with 3 blocking SSH attempts (default-branch tip 8398d31) to 3.36s, and the deferred worker's published report came back byte-identical to the three sweep lines the blocking baseline printed, with the unreachable route preserved in both and the result surfacing as a queued 'check: startup-network' wake. That doc's latency record was re-measured against the current tip rather than left citing the now-historical 345de4e.
This is firstmate shared, tracked startup/supervision infrastructure, held to the highest bar: deterministic and idempotent enforcement, the one-owner rule for contracts, behavioral tests through the executable interface only, one sentence per line in tracked Markdown, plain dash never em dash, and bin/fm-lint.sh clean.
What Changed
NETWORK CHECKSreport and completion wake, while reusing the tasks-axi compatibility verdict to eliminate duplicate probes.Risk Assessment
✅ Low: The deferred-worker design is well-bounded, preserves the bootstrap phase partition and lock-safety invariants, and the fix round correctly prevents failed report publication from being acknowledged as successful.
Testing
After diff-based scoping, the focused bootstrap, session-start, and deferred-worker suites passed; an initial load-sensitive acknowledgement-test failure was stabilized and rerun successfully, while a public CLI fixture demonstrated immediate startup return, all five checks reported as pending, completed deferred results, and durable wake delivery.
Evidence: Deferred startup network CLI transcript
Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
🔧 **Review** - 1 issue found → auto-fixed ✅
bin/fm-startup-network.sh:333- The required guarantee says every deferred check remains "reported ... with its safety guarantees intact," but this hunk ignores failure to replace.startup-network.reportand still publishes the generation asdone. If that atomic write fails, harvest can acknowledge an absent or previous generation's report as the current completed result, silently losing or misreporting findings. Publish a failed state with an explicitNETWORK_CHECKSdiagnostic instead of completing when the report write fails.🔧 Fix: Fail deferred startup when report publication fails
✅ Re-checked - no issues remain.
✅ **Test** - passed
✅ No issues found.
git diff --stat 8398d3109b8d153d86081bb358eea00a13a8ff1c..b343fc2272bcd7fc8ebdb5f0b852b99050062a99and changed-file inspectiontests/fm-bootstrap.test.shtests/fm-session-start.test.shtests/fm-startup-network.test.shbefore and after the test-only timing stabilization/var/folders/0k/bf8mwt2n5qddzk24r20gfk0c0000gn/T/no-mistakes-evidence/01KZD0R6Q631YMPE0FVDBHEDE1/fixture/run-evidence.sh✅ **Document** - passed
✅ No issues found.
✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.