Files
stack/REPORT-T2.md
T

6.8 KiB

REPORT-T2

Date: 2026-08-13 11:29 CDT Branch: feat/wf-fleet-t2-launch Base: 216cd722 Issue: #1209

What changed

  • Added mosaic fleet launch <name> [--dry-run] in packages/mosaic/src/commands/fleet-launch-command.ts and registered it on the existing fleet command.
  • Added strict schema-one parsing for the user-owned ~/.mosaic/fleet/agents/<name>/profile.json:
    • required schema and harness
    • default bundle primary
    • optional model, overlay, plugins, skills, and string-valued env
    • unknown-key refusal naming the key
    • dedicated SCHEMA_TOO_NEW code and upgrade guidance
  • Added the three-layer settings composer. Objects merge recursively, scalars use the higher layer, arrays replace, and null deletes a key. The selected agent overlay defaults to no overlay when the profile field is absent.
  • Writes canonical merged settings to <agent-home>/settings.json and the future harvest comparison snapshot to <agent-dir>/settings.generated.json.
  • Resolves primary to its named bundle, reads an optional account email, and reports forms such as primary -> fred_example.com ([email protected]).
  • Validates credential targets with lstat, rejects symlink credential files, resolves and checks containment under the harness auth root, and refuses a real credential file at the seat-link path as first-auth state.
  • Installs selected plugin and skill entries as seat-local symlinks, prunes stale symlinks, and refuses real objects instead of deleting them.
  • Builds a declared seat environment with the harness home variable, MOSAIC_AGENT_NAME, and profile environment entries. Mechanical values override conflicting profile entries.
  • Extended launch.ts so harnessHome() accepts fleet context and remains the home-resolution seam. The fleet launcher uses the existing runtime preflight, prompt, ledger, lease-gated, and process execution path over a minimal ambient environment.
  • Added deterministic dry-run output containing source layers, merged settings, output and snapshot paths, resolved bundle, symlink plans, declared environment, and harness argv.
  • Added 17 focused tests, including the required merge, schema, A3, dry-run snapshot, managed-link, command dry-run, execution-seam, and non-zero failure cases.

Reconciliation decisions and contradictions

Prominent contradiction: roster registries do not contain the frozen launch schema

The existing code has two other profile/registry concepts:

  • fleet-profiles.ts models system-type YAML roster templates. Its FleetProfile has no harness bundle, overlay, plugin, skill, or seat environment fields.
  • roster-v2 models topology and lifecycle. It requires class, provider, reasoning, tool policy, working directory, lifecycle, and launch-yolo fields that schema-one profile.json does not contain.

Deriving a complete roster-v2 member from the frozen per-agent profile is therefore not possible without inventing values. Launch now reads only the per-agent profile.json and does not require roster-v2 or the legacy v1 roster. roster-v2 remains the existing lifecycle/topology registry. No second launch registry was introduced.

The pre-existing resolveFleetIdentity() path requires a legacy roster and a secure tmux helper whenever MOSAIC_AGENT_NAME is present during contract composition. For profile-backed launch, launch.ts excludes roster identity keys only from the contract-build environment, then exports the declared profile seat identity to the harness process. Legacy root runtime launches retain the existing roster-backed behavior. This is the smallest reconciliation that allows profile-only launch without fabricating roster-v2 fields.

The prototype used a whole plugins directory symlink, while this task requires selected entry links and pruning. Launch refuses that historical shape with an explicit migration message. It does not delete or silently convert the whole-store link.

Existing FleetProfile name

The system-type YAML FleetProfile remains unchanged. The new type is named FleetAgentLaunchProfile to keep the concepts separate while treating per-agent profile.json as the launch SSOT.

Ambiguities and bounded choices

  • The design does not freeze the generated snapshot filename. This implementation uses settings.generated.json in the agent directory, beside the hidden harness home.
  • The design explicitly identifies Claude .credentials.json and Pi auth.json. Codex and OpenCode use auth.json in the filename map, matching their harness-home composition shape, but no real credential launch was performed in this task.
  • Full interactive harvest-back disposition is not implemented. The task asks to store the generated snapshot for the future diff, and this change does that.
  • A machine descriptor file and content digests were not added. Dry-run and execution consume one resolved in-memory composition, and dry-run prints that composition.
  • No real harness process or real operator home was used. Every new filesystem test uses a temporary fixture root.

Test run

Dependency install and build:

$ pnpm install --frozen-lockfile
Scope: all 28 workspace projects
Lockfile is up to date, resolution step is skipped
Done in 4.7s using pnpm v10.6.2

$ pnpm --filter @mosaicstack/mosaic... build
Scope: 13 of 28 workspace projects
packages/mosaic build: Done

Focused and touched integration tests:

$ pnpm --filter @mosaicstack/mosaic exec vitest run src/commands/fleet-launch-command.spec.ts src/commands/launch.spec.ts src/commands/fleet.spec.ts
Test Files  3 passed (3)
Tests       256 passed (256)

Typecheck and lint:

$ pnpm --filter @mosaicstack/mosaic typecheck
> tsc --noEmit
(exit 0)

$ pnpm exec eslint packages/mosaic/src/commands/fleet-launch-command.ts packages/mosaic/src/commands/fleet-launch-command.spec.ts packages/mosaic/src/commands/launch.ts packages/mosaic/src/commands/fleet.ts packages/mosaic/src/commands/fleet.spec.ts
(exit 0)

$ pnpm exec prettier --check packages/mosaic/src/commands/fleet-launch-command.ts packages/mosaic/src/commands/fleet-launch-command.spec.ts packages/mosaic/src/commands/launch.ts packages/mosaic/src/commands/fleet.ts packages/mosaic/src/commands/fleet.spec.ts
Checking formatting...
All matched files use Prettier code style!

Package-wide Vitest result:

$ pnpm --filter @mosaicstack/mosaic exec vitest run
Test Files  1 failed | 83 passed (84)
Tests       4 failed | 1535 passed (1539)

All four failures are in src/mutator-gate/mutator-gate.acceptance.spec.ts. Three expected MUTATOR_UNVERIFIED but received STALE_GENERATION; one runtime-gate assertion expected status zero and received status two. An isolated rerun produced the same four failures. I did not confirm whether they predate this branch. The focused launch, fleet, and typecheck runs are green.