9.3 KiB
FCM-M4-001 — v1-to-v2 inventory, preview, and migrator
- Task / issue: FCM-M4-001 / Fleet configuration control plane and operator documentation (mosaicstack/stack#758)
- Branch / base:
feat/758-v1-v2-migratorfromorigin/mainc1aecfabe97a5dc81a72f44910cd4e626f41863f - Base tree:
46cdfbcdc1d1ff9c7b8b2b9cf3841086590bf774 - Scope: field-complete inventory, non-mutating preview, canonical v2 migration output, and migration/recovery disposition evidence. All effects use injected fakes or temporary fixtures.
- Budget: 35K task estimate is the hard working cap. Keep one card/one PR and prefer focused reuse of the v2 compiler, shared role resolver, generated-env boundary, M1 executable disposition inventory, and reconciler observations.
Objective
Implement preview-first v1 migration that never infers unresolved classes or lifecycle, preserves observed running/stopped state, quarantines forbidden legacy environment inputs with key-name/SHA-256-only diagnostics, inventories remote/connector/schema-only entries without reconciling them, covers every M1-classified shipped artifact, and emits deterministic recovery disposition evidence for the later M4-002 canary/rollback gate.
Acceptance mapping
- Field-by-field v1 inventory and no-mutation preview.
- Canonical output compiled by
roster-v2.tsand semantically validated by the existing baseline-plus-roles.localresolver. - Only approved deterministic aliases; every other noncanonical class requires an explicit disposition.
- Observed stopped/running maps explicitly to persisted lifecycle; stopped observations never produce running targets.
- Generated env is regenerated; strict local data is relocated; forbidden keys are quarantine inputs reported only by key name and SHA-256.
- Remote/connector/schema-only entries are inventory-only and excluded from local reconciliation output.
- Every shipped M1 example/profile/service preset has executable migration disposition evidence.
- Deterministic migration/recovery evidence records source, output, exclusions, quarantine, and restore prerequisites without executing a canary or rollback.
Boundaries
Out of scope: FCM-M4-002 executable canary/rollback and host fixture, #766 communications, #636 commands/channels, live fleet/systemd/tmux/session/migration/deploy/connector/remote/gateway effects, docs/TASKS.md, parent issue mutation, commit, push, and PR operations.
TDD plan
Migration rules and redaction are critical data-mutation/security logic, so tests are written red-first for inventory completeness, explicit class disposition, observed-state preservation, quarantine redaction, inventory-only remote/schema entries, compiler/resolver reuse, artifact coverage, and recovery evidence. Production code follows only after the focused tests fail for the missing behavior.
Plan
- Map existing v1 loader, v2 compiler/resolver, env quarantine, reconciler observation, and M1 disposition guard.
- Add behavior-oriented failing migration tests with temporary fixtures and injected observation/filesystem adapters only.
- Implement the narrow migration module and CLI boundary without a second resolver or live command runner.
- Add scoped M4 migration/recovery documentation and executable shipped-artifact evidence.
- Run focused tests, full package tests, package/root typecheck and lint, formatting, diff checks, and adversarial redaction/no-effect verification.
- Run independent code/security review, remediate findings, reconstruct the synthetic tree using a temporary index, and stop uncommitted.
Progress
- Collision checks passed: no local/remote branch, worktree, target path, or open PR owned
feat/758-v1-v2-migrator. - Dedicated worktree created at the exact green
origin/mainbase. - Required global/repository guides and FCM requirements/evidence loaded.
- No matching migration skill exists under the configured skill directories; no unrelated skill loaded.
- Added a preview-only CLI and migration module that compile with the existing v2 parser/renderer and validate through the shared persona resolver.
- Added value-free raw-v1 inventory, strict unknown-field/synonym/duplicate detection, inventory-only remote and connector handling, and explicit class/tool-policy decisions.
- Added separate reviewed lifecycle observations with only unambiguous running/stopped mappings.
- Added sanitized, non-mutating environment preflight and recovery evidence explicitly marked non-executable.
- Added executable disposition evidence derived from the exact 13-entry M1 inventory and operator documentation.
- Tightened untrusted decisions/observations to reject unknown keys, invalid types/enums, extra local records, and competing automatic-alias dispositions.
- Remediated independent review findings: v1 runtime/reset defaults are preserved,
~workdirs expand only at env preflight, malformed/required agent fields fail closed before remote exclusion, and all seven shipped v1 fixtures now execute real previews with explicit evidence. - Remediated socket and locality authority blockers: socket-only agents stay local;
host == fleetHoststays local; onlyhost != fleetHostis inventory-only; ssh-only, missing reviewed fleet-host identity, and contradictory host/ssh targets block explicitly without lifecycle omission. - Remediated final exact-tree blockers: a declared v1 root socket cannot be overridden; matching/conflicting socket decisions retain reviewed running evidence; canonical ordering uses a shared locale-independent Unicode code-point comparator; migration evidence preserves all four legacy environment dispositions; backup documentation no longer claims validation that M4-001 does not perform.
- Remediated immutable-review socket-presence blocker: both
socket_nameandsocketNameare field-presence-aware, so explicit empty/default-server declarations remain authoritative and incompatible named decisions block rather than replacing them. - Remediated the replacement-tree blockers: the shared v2 compiler and reconciler accept an explicit empty socket as literal default-server identity; present-empty holder session, default/agent work directory, runtime reset command, and alias values block rather than defaulting; missing preview inputs emit one stable blocked JSON object with non-zero status. Snake/camel aliases and whitespace-only input have adversarial coverage.
- Remediated the subsequent authority blockers: each present-empty CLI path emits exactly one stable blocked JSON object with exit 1 before file reads, and reconciler
start/restartor desired-stateapply/reconcilefail closed before fixedmosaic-fleetsystemd services can act on a default-server roster. - Remediated committed-head review blockers: explicitly declared empty runtime objects use the production v1
/clearreset fallback while omittedpiretains/new; lifecycle observations are sorted by canonical agent name; and bare CLI path flags reach preview validation, emit one stable blocked JSON object with exit 1, and perform zero reads. Built production-CLI subprocess tests cover all three bare flags. - Remediated late-audit blockers: the documented M4 guard invokes the 13-artifact validator and all seven v1 previews; canonical
~/~/...workdirs remain unchanged in migration evidence and traversal-free forms expand at the shared production projection boundary while ordinary relative and home-relative traversal paths remain rejected; remote inventory and exclusion evidence sort canonically; and every default-server lifecycle-mutating reconciler path fails before observation, projection preparation/application, or fixed-unit effects. Explicit regressions preserveplan,status,doctor, andverifyas observational default-server commands. - Remediated exact-tree traversal review:
~/../escapeand~/src/../../escaperemain unexpanded and fail the unchanged sharedunsafe-pathvalidation. Both the shared generated-environment boundary and the production v1 environment caller have red-first regressions, preventing earlier caller normalization from bypassing the boundary.
Verification evidence
- Focused migration/compiler/environment/reconciler/CLI: 8 files, 372 tests passed.
- Documented 13-artifact guard: 1 matching test passed and executed all seven v1 previews.
- Full
@mosaicstack/mosaic: 59 files, 902 tests passed. - Workspace build: 23 tasks passed.
- Root typecheck: 42 tasks passed.
- Root lint: 23 tasks passed.
- Root format check and
git diff --check: passed. - Built production CLI: canonical
~/srcremains in ready roster/YAML evidence; generated projection preflight succeeds with no blockers; a bare path flag emits one blocked JSON object, exit 1, and no stderr. - Independent high-effort late-audit review: no blocker remained in the four assigned repair surfaces; separate exact-tree security audits found no qualifying newly introduced vulnerability.
- Exact temporary-index synthetic tree includes every tracked changed path; immutable SHA and duplicate reconstruction are recorded in the final handoff.
Risks / blockers
- M4-001 emits rollback prerequisites/evidence only; executable rollback/canary and the managed/unmanaged host fixture remain owned by M4-002.
- Remote/connector entries remain inventory-only; later federation or connector reconciliation requires separately reviewed work.
- Existing environment data is only preflighted. Cutover backup, quarantine write, legacy removal, and generated projection application remain later reviewed effects.