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

72 lines
5.9 KiB
Markdown

# #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:
```text
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.