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]inpackages/mosaic/src/commands/fleet-launch-command.tsand registered it on the existing fleet command. - Added strict schema-one parsing for the user-owned
~/.mosaic/fleet/agents/<name>/profile.json:- required
schemaandharness - default bundle
primary - optional
model,overlay,plugins,skills, and string-valuedenv - unknown-key refusal naming the key
- dedicated
SCHEMA_TOO_NEWcode and upgrade guidance
- required
- Added the three-layer settings composer. Objects merge recursively, scalars use the higher layer, arrays replace, and
nulldeletes a key. The selected agent overlay defaults to no overlay when the profile field is absent. - Writes canonical merged settings to
<agent-home>/settings.jsonand the future harvest comparison snapshot to<agent-dir>/settings.generated.json. - Resolves
primaryto its named bundle, reads an optional account email, and reports forms such asprimary -> 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.tssoharnessHome()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.tsmodels system-type YAML roster templates. ItsFleetProfilehas 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.jsondoes 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.jsonin the agent directory, beside the hidden harness home. - The design explicitly identifies Claude
.credentials.jsonand Piauth.json. Codex and OpenCode useauth.jsonin 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.