Skip to content

fix: move network checks off the session-start blocking path - #1860

Merged
kunchenguid merged 4 commits into
mainfrom
fm/fm-netfree-rebase-r1
Aug 7, 2026
Merged

fix: move network checks off the session-start blocking path#1860
kunchenguid merged 4 commits into
mainfrom
fm/fm-netfree-rebase-r1

Conversation

@kunchenguid

Copy link
Copy Markdown
Owner

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:

  • AGENTS.md section 3: the digest's step list is renumbered to state emission order directly (supervision block and its read-once contract, fleet state, network checks, then context). This preserves docs: align session-start digest ordering #1826's fleet-state-BEFORE-context ordering and its 'last of the bulk sections' and read-once-contract wording, while adding the new NETWORK CHECKS step. fix(bin): close decisions when answers are sent #1842's --resolve-key answerer-closes lines in section 7 are untouched and verified present.
  • tests/fm-backend.test.sh: resolved to main's version from fix(tests): restore reliable fm-send backend parity coverage #1851. The fix(bin): defer session-start network checks #1845 branch had widened the old-bin shim with 'cp -R' to stop a hand-maintained sibling list from omitting the new bin/ script; main's git-archive-of-the-whole-historical-bin-tree already subsumes that reason entirely, so main's is strictly better and the branch's variant is dropped on purpose.
  • fix(bin): mirror remote secondmate status streams #1846 turned out NOT to touch bin/fm-bootstrap.sh at all (it changed bin/fm-procevent-remote-reply.sh, which this branch never touches), so its remote status-stream mirror is preserved untouched. Its arming call from the secondmate_sync sweep simply now happens in the deferred stage: the mirror behavior AND the off-blocking-path deferral both hold.

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

  • Render the session-start digest entirely from local state while GitHub auth, secondmate maintenance, pending handoffs, and project refreshes run concurrently in a bounded detached worker.
  • Split bootstrap into guarded local and network phases without changing sweep ownership or allowing unknown phase values to skip safety checks.
  • Surface deferred results through a durable NETWORK CHECKS report 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
$ fm-startup-network.sh start --locked 1 --harvest-pid <session-pid>
start returned in 0s while the simulated network sweep continues for 6s

$ fm-startup-network.sh report
IN PROGRESS - the deferred network checks have not finished yet.
NOT yet confirmed: GitHub authentication, dead-secondmate relaunch, secondmate convergence, pending handoff delivery, and project clone refresh with its drift reporting.
Started 0s ago, bounded at 120s.
The result is durable in state/.startup-network.report and arrives as a `check: startup-network` wake.
Read it now with /var/folders/0k/bf8mwt2n5qddzk24r20gfk0c0000gn/T/no-mistakes-evidence/01KZD0R6Q631YMPE0FVDBHEDE1/fixture/root/bin/fm-startup-network.sh report; until it lands, treat none of it as confirmed.

$ fm-startup-network.sh report
completed off the startup path in 6s: GitHub authentication, dead-secondmate relaunch, secondmate convergence, pending handoff delivery, and project clone refresh with its drift reporting.
NEEDS_GH_AUTH: GitHub authentication needs attention
SECONDMATE_LIVENESS: unreachable route preserved; relaunch safely refused
FLEET_SYNC: secondmate convergence completed
HANDOFF_DELIVERY: pending handoff delivery completed
PROJECT_REFRESH: project clone refresh completed
These ran AFTER the sections above were composed, so re-read any record a line here names.

$ persisted wake queue
check	startup-network	check: startup-network: deferred startup network checks finished (done); read them with /var/folders/0k/bf8mwt2n5qddzk24r20gfk0c0000gn/T/no-mistakes-evidence/01KZD0R6Q631YMPE0FVDBHEDE1/fixture/root/bin/fm-startup-network.sh report

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.report and still publishes the generation as done. 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 explicit NETWORK_CHECKS diagnostic 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..b343fc2272bcd7fc8ebdb5f0b852b99050062a99 and changed-file inspection
  • tests/fm-bootstrap.test.sh
  • tests/fm-session-start.test.sh
  • tests/fm-startup-network.test.sh before 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.

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.
@kunchenguid
kunchenguid merged commit 4b6b89d into main Aug 7, 2026
13 checks passed
@kunchenguid
kunchenguid deleted the fm/fm-netfree-rebase-r1 branch August 7, 2026 03:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant