# 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 [--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//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 `/settings.json` and the future harvest comparison snapshot to `/settings.generated.json`. - Resolves `primary` to its named bundle, reads an optional account email, and reports forms such as `primary -> fred_example.com (fred@example.com)`. - 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. ### Historical whole-store plugin link 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: ```text $ 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: ```text $ 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: ```text $ 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: ```text $ 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.