Files
stack/docs/scratchpads/758-fcm-m2-002-fleet-agent-crud.md
jason.woltje bc5e73629e
All checks were successful
ci/woodpecker/push/publish Pipeline was successful
ci/woodpecker/push/ci Pipeline was successful
feat(fleet): add generation-guarded agent CRUD (#773)
2026-07-15 12:03:05 +00:00

5.2 KiB

FCM-M2-002 — Generation-Guarded Fleet Agent CRUD

  • Task / issue: FCM-M2-002 / #758
  • Branch / base: feat/758-fleet-agent-crud from origin/main 191efaefeb5c0c6bb218c1292d12ce8e73ace12b
  • Budget: 30K card allocation; no deployment or live-fleet actions.

Objective

Provide local roster-owned create, get, update, and delete mutations with a generation precondition, deterministic dry-run plan, complete-state structural/semantic/projection validation before writes, atomic roster persistence, and redacted recovery output on a late projection failure.

Scope and exclusions

  • Roster v2 is the sole desired-state authority. Reuse parseRosterV2, renderRosterV2Yaml, validateRosterV2Semantics, and the generated-environment boundary.
  • Fresh create defaults to enabled: true and desired_state: stopped; this card never starts a runtime.
  • Excluded: reconcile/apply; lifecycle/session/systemd/tmux actions; migration/canary; remote/connector/gateway mutation; arbitrary commands/channels/secrets; generated files as authority; docs/TASKS.md and orchestration ledger changes.

Red-first plan

  1. Add failing tests for dry-run non-mutation, stale generation, concurrent writer locking, stopped default create, equivalent idempotency, complete proposed-state semantic/boundary validation, atomic roster write, and injected late projection failure with redacted recovery details.
  2. Implement only a roster-v2 CRUD service and file adapter; no legacy fleet add/remove behavior expansion.
  3. Add operator/reference docs for JSON outcomes, generation retries, recovery, and no-runtime-action boundary.

Progress

  • Preflight: clean exact base and no duplicate PR confirmed.
  • Intake read: FCM PRD/AC-FCM-03, task row, launch and generated-env boundaries, roster v2/resolver contracts, legacy fleet command behavior, delivery/QA/TypeScript/security/documentation guidance.
  • TDD: RED observed for the missing CRUD module. GREEN: focused suite passes 7 tests covering stopped-default create, stale generation, idempotency, dry-run non-mutation, concurrent lock denial, exact stale/absent generated-projection delete cleanup, and redacted late-projection recovery.
  • REVIEW-1 remediation: RED observed for absent CLI create/get/update/delete/plan wiring. Added roster-v2-only JSON commands, including safe get, read-only planning/dry-run, explicit persisted-start recording (never runtime start), stable handled error codes, and focused CLI coverage.
  • REVIEW-2 remediation: RED observed for missing direct fleet-control-plane registration and ambiguous partial late-I/O result. The public surface is now direct mosaic fleet {create,get,update,delete,plan} (not root gateway mosaic agent); a late filesystem projection failure returns non-zero redacted JSON with authoritativeRoster: committed and projections: incomplete, proving no rollback/no-op claim.
  • REVIEW-3 remediation: RED observed for unnamed update/delete plans and deleted-agent quarantine conflict. plan <operation> [name] now requires target names only for update/delete; delete validates/removes only exact generated state while retaining local/legacy/quarantine/unrelated files. Actual CLI/filesystem tests cover create/update/delete plans, plan validation/non-mutation, retained artifacts/dry-run bytes, unsafe permission/symlink rejection, and post-roster delete recovery. Added the required operator how-to.
  • REVIEW-4 remediation: RED observed that actual Commander create accepted and silently dropped disallowed command, channel, and secretRef keys. The --agent object and nested launch now use strict own-property allowlists; non-plain/prototype-sensitive shapes and unknown keys fail invalid-request before resolver, roster, or projection mutation. Actual Commander plan/create/update tests cover top-level command/channel/secretRef/constructor/prototype/__proto__ shapes and nested launch unknown fields, byte-identical retained artifacts, non-zero exit, and diagnostics that never echo rejected values. Docs state the same boundary.

Risks / assumptions

  • ASSUMPTION: M2 mutations operate exclusively on the existing v2 roster contract because generation/lifecycle fields are v2-only; legacy v1 add/remove commands remain unchanged compatibility paths.
  • A multi-file roster/projection write cannot be one filesystem rename. The roster is authoritative; a post-roster projection failure returns a redacted recovery plan naming only safe paths/actions, never environment values.

Verification evidence

  • pnpm --filter @mosaicstack/mosaic test -- fleet-agent-crud-command.spec.ts fleet-agent-crud.spec.ts generated-env-boundary.spec.ts — PASS (48 tests after REVIEW-4 remediation).
  • pnpm --filter @mosaicstack/mosaic test — PASS (54 files, 794 tests after REVIEW-4 remediation).
  • pnpm --filter @mosaicstack/mosaic lint — PASS.
  • pnpm --filter @mosaicstack/mosaic typecheck — PASS.
  • pnpm format:check and git diff --check — PASS.
  • Root pnpm typecheck, pnpm lint, pnpm format:check, and git diff --check — PASS after REVIEW-4 remediation; full package test is 54 files / 794 tests.
  • REVIEW-4 remediation focused checks are green; fresh full-delta independent review is required before author-green. No commit, push, or PR opened.