Files
stack/docs/scratchpads/1256-fleet-runtime-preflight.md
T

5.9 KiB

#1256 — Fleet runtime preflight

Agent: tiny

Branch: fix/1256-fleet-runtime-preflight from origin/next@476db12b92971634b67fd2057b7577ee5894e449

Issue: mosaicstack/stack#1256 blocker 1

Adjacent PR: #1258 (fix/1256-fleet-pane-path-node) owns the bootstrapped-Node candidate and must remain a separate change

Budget: 30K-token soft cap; one bounded implementation lane

Objective

Make fleet provisioning fail before installation effects when the roster names a runtime binary absent from the exact PATH the tmux pane will receive. Make mosaic fleet doctor report the same named runtime check. Diagnostics must name the runtime, every requesting roster row, the pane PATH searched, and an exact install command.

For Pi the exact command is:

npm install -g @earendil-works/pi-coding-agent

Constraints

  • TDD: add the failing behavior test and capture RED before implementation.
  • Runtime resolution uses the launcher's pane-PATH construction; a second PATH model is forbidden.
  • Operator PATH is non-authoritative and must not cause a false pass.
  • Tests use an isolated --mosaic-home/temporary HOME and never mutate host runtime binaries.
  • No install, removal, or binary-resolution changes on sb-it-1-dt.
  • PR targets next and requires a reviewer other than fred.
  • Commit identity is tiny <[email protected]>.
  • #1258's Node candidate is a dependency/adjacent change, never reimplemented here.

Planned seam

  1. Factor the shell pane-path builder/resolver into one sourceable and executable fleet helper.
  2. Have start-agent-session.sh source that helper, preserving one definition of the pane PATH.
  3. Have the TypeScript fleet command invoke the same helper under the unit-equivalent clean launcher environment.
  4. Group roster rows by distinct runtime and effective pane PATH, then report requesting row names.
  5. Run the preflight before installFleet performs any write.
  6. Add the named result to roster-v2 fleet doctor JSON and set a failing exit when a runtime is absent.
  7. Install/copy the helper alongside start-agent-session.sh and update framework manifest/docs as required.

This seam overlaps #1258 only at the location of the existing shell function. Development may use #1258 as a local dependency, but the final PR diff must exclude #1258's separately owned Node change after that PR lands or after an agreed rebase order.

Acceptance evidence

Requirement Evidence
Missing Pi blocks install before effects isolated CLI test: nonzero + no installed files/runner effects
Operator PATH cannot create false green test puts Pi only on operator PATH and omits it from constructed pane PATH
Exact pane PATH reused launcher and CLI call one shared shell helper; contract test exercises both
Actionable diagnosis runtime + roster rows + searched PATH + exact install command assertions
Distinct runtimes repeated rows produce one check with all row names
Doctor reports named check JSON assertion + nonzero exit for missing runtime
Present runtime passes isolated pane-path fixture with executable binary
No host mutation tests use temporary HOME/Mosaic home and fixture binaries only
Baseline safety focused tests, package typecheck/lint/format, full relevant suite, CI

Progress log

  • 2026-08-16: Dispatch received from fred; issue #1256 and PR #1258 measured.
  • 2026-08-16: Fresh clone created under ~/agent-work/tiny-fleet-runtime-preflight; local Git identity pinned to tiny so retired global mos-dt-0 identity cannot win.
  • 2026-08-16: Design inspection found the pane PATH exists only inside start-agent-session.sh; the right seam is a shared shell helper rather than a parallel TypeScript reconstruction.
  • 2026-08-16: RED measured on origin/next@476db12b: focused fleet-roster-v2-dispatch.spec.ts ran 11 tests; the new case failed because install returned success, wrote units for two agents, and emitted no runtime=pi diagnosis while Pi existed only on operator PATH.
  • 2026-08-16: Factored pane home/PATH/resolution into sourceable and executable pane-runtime-path.sh; install invokes it before the first effect, doctor emits the same named checks, and the launcher sources it.
  • 2026-08-16: Fred/rhodey review exposed the #1241 name-resolution blind spot: mosaic can resolve while its #!/usr/bin/env node interpreter cannot. Measurement confirmed every supported current Mosaic package shape is a Node-shebang script, but executing mosaic --version is not observational because CLI startup runs the cache-writing/network update checker before Commander handles the flag.
  • 2026-08-16: Final executable check reads and unwraps direct and /usr/bin/env shebangs (including env -S), resolves the declared dependency against pane PATH, and runs only side-effect-free node --version when Node is declared. Native binaries do not inherit a permanent Node requirement. Install, doctor, and launcher share this implementation.
  • 2026-08-16: Isolated greenfield fixture places resolved Mosaic and Pi Node-shebang scripts in pane-visible npm-global bin while using an empty system suffix; both checks become unexecutable with dependency=node, and install leaves holder/tools/units absent. No host binary or HOME is changed.
  • 2026-08-16: GREEN evidence before #1258 rebase: focused install/doctor/preflight suites pass; fleet.spec.ts 209/209; full Vitest 87 files / 1,557 tests; launcher shell suite, typecheck, lint, build, and focused format check pass. Full framework-shell reaches an unrelated host-measurement drift in unchanged invariant_r_unittest.py (expected Pi 0.84.1, host resolves 0.84.2); no invariant was changed in this lane.
  • 2026-08-16: Merge-order gate remains: origin/next is still 476db12b; #1258 is unmerged at 6dc35e5. Rebase after it lands, relocate its Node candidate into the helper with explicit provenance, rerun gates, then open the PR to next for an independent non-fred review.