feat(fleet): mosaic fleet regen — regenerate roster-derived projections (PR3 of #791) #813
Reference in New Issue
Block a user
Delete Branch "feat/791-pr3-fleet-regen"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
PR3 of #791 —
mosaic fleet regen(regeneration-from-SSOT)Part of #791. Third and final PR of the ratified 3-PR DAG (b strict ownership separation #802 ✅ merged · a transactional pre-update snapshot #811 ✅ merged · d regeneration-from-SSOT — this PR). The umbrella #791 stays open until MS-LEAD closes it.
What this adds
mosaic fleet regen— a projection-only recovery command that rebuilds eachfleet/agents/<name>.env.generatedfrom theroster.yamlSSOT after an upgrade or partial write leaves the generated projections stale or missing.--writeapplies;--jsonfor machine output.CommandRunneris declared but never referenced on any executable path), and arecordingRunnergate asserts zero runner invocations across every test.projectRosterV2AgentGeneratedEnv+ the generated-env boundary) — it does not reimplement fleet logic.KEY=value.reconcile/plan/verifydo, and now forwards configuredrolesDir/overrideDirso a custom-persona-root deployment cannot have reconcile accept a roster that regen rejects.Concurrency / lock hardening
Regen serializes against agent CRUD and reconcile via both fleet locks (
roster.yaml.mutation.lock+roster.yaml.reconcile.lock), acquired mutation→reconcile and released in reverse. Both are non-blockingwxlocks that throw on contention → no deadlock. The shared managed-lock helper was hardened:statitself fails (dev/ino unavailable) — it removes only a leaf whose content matches our random UUID, so it can never delete a CRUD (empty) or differently-tokened replacement.Tests (TDD, red-first, co-located)
fleet-regen-command.spec.ts— 26 tests: dry-run/write dispositions, the load-bearing never-restarts gate, all lock regressions (ownership-proof-before-unlink, acquire-unwind fault, dual-lock stale warning, stranded-lock on init failure, stat-failure strand), and persona-root wiring. Every finding fixed in review was proven red-first.Known limitation — deferred to a follow-up
A residual check-then-unlink TOCTOU remains in the lock release (between the final ownership proof and the path
unlink). It is byte-identical to the already-merged reconcile-lock release onmain, unreachable within thewxwriter protocol (no Mosaic writer removes a lock it doesn't own; only an externalrm/stale-lock reaper can vacate the inode mid-release), and its true fix is a cross-cutting mechanism change — an fd-held advisory lock adopted by all fleet writers (CRUD + reconcile + regen) — out of scope for a projection-only recovery PR. Tracked as a separate follow-up issue. Two independent reviews (author≠reviewer) treated it as non-blocking.Review evidence
typecheck·lint·format:check· full mosaic vitest 1278.Base:
31607a4(freshmain). No self-merge — holding at PR-open for MS-LEAD's exact-head review + durable Reviewer-of-Record before merge.Reviewer-of-Record — exact head
1eb37f6f— VERDICT: APPROVEIndependent exact-head adversarial/security review (FRESH standalone, not carried-forward).
jason.woltje; separation by lane, not by provider account).1eb37f6fd084afbdc8c00e4ff5f57d2c89fc2c14· tree614169817658f7f280e22054efdd4d8812ad12ff· base31607a4(merge-base == current main).Findings — all 8 adversarial areas PASS (zero blockers):
deps.runnernever invoked;recordingRunnergate assertscalls==[]&&systemctl==[]; sole side-effect = one atomic write.wx, deadlock-impossible (only regen holds both, fixed order); init-failure cleanup dev/ino+token-guarded (no stranded lock on writeFile- or stat-fault); per-lock fault labels correct (no mislabel).wxwriter protocol (only externalrm/stale-reaper vacates the inode). Appropriate to defer for a projection-only PR.<name>.env.generated; legacy.env/.env.local/.env.quarantineuntouched.validateRosterV2Semanticsgate → regen and reconcile cannot disagree on persona acceptance.--writesafety — atomic temp(0o600,wx)+rename; fail-closed (all validated before any write; mid-loop fault →incompletewith exact lists).INFO (non-blocking): (a) refactor makes the merged reconcile-lock release functionally equivalent but not byte-identical to main (removed one redundant ownership check; closed no window) — minor correction to the "byte-identical" wording; (b) no explicit test asserts both locks unlinked after a successful
--write(covered indirectly). Neither blocks.Gate status → mergeable: exact-head authoritative-green CI ✓ · fresh independent exact-head RoR APPROVE ✓ · scope clean ✓ · based on current main ✓ · CWE-367 residual deferred to #814 ✓. Durable RoR persisted to provider before queue guard.