Files
stack/docs/PRDs/2026-08-31_PRD_rev1/CLI.1-parity.md
T
jason.woltje 13968e9a8b
ci/woodpecker/pr/ci Pipeline failed
docs: PRD rev1 review Q90 — Prettier-format the bundle, add rev0 archive README
Addresses CPS-PRD-REV1-REVIEW-Q90 findings F1 and F3 on PR #1491:

F1 (format gate): `prettier --write` on the 18 rev1 bundle documents.
Whitespace, table padding, list markers and emphasis delimiters only — a
normalized token comparison of every file before/after shows zero content
difference, so the ratified text is unchanged and no re-ratification applies.

F3 (rev0 relative links): the archived rev0 PRD stays byte-identical
(sha256 60cc2f98...36afdf verified) per GOV.1 archive-never-edit. A sibling
docs/PRDs/2026-08-26_PRD_rev0/README.md records the digest, the original
location, the owner disposition that the in-file links are intentionally
historical, and a resolution table for all 9 targets (11 occurrences), each
verified to exist. Future relocated archives ship the same README instead of
edited bytes.

F2 (test step) is investigated separately against the CI log.
2026-09-02 09:40:46 -05:00

159 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
id: CLI.1
status: ratified
ratified: 2026-09-01 (Jason Woltje; PRD rev1 ratification PR)
---
# CLI.1 — CLI surface and parity obligation
## The rule
The CLI is the **primary execution method** (D8); the WebUI operates the same
tooling over the Gateway API and never bypasses it (D12). Register OD-49 fixes
`mosaic config` as the stable installation-configuration command family backed
by one desired-state engine; register OD-53 makes every interface (CLI, TUI,
WebUI, API, automation) a client of that same engine.
Parity is therefore **structural, not aspirational**: a capability that exists
in the CLI without a WebUI surface is an incomplete projection; a WebUI wish
with no backing tool is **"blocked on tooling"** and the tool is built first
(D8 consequence). Neither side ever grows private logic.
## Parity matrix obligation
The ratified bundle must carry (or cite, per D8's baseline inputs) three
artifacts, kept current:
1. **Tool inventory** — what official tooling exists and what is missing.
2. **WebUI→tool mapping** — every page control mapped to the tool it calls
([[UI.1-webui-surfaces]] page inventory is the row source).
3. **Measured `next`-branch state** — what actually works today.
All three artifacts were measured 2026-08-31 against `origin/next` commit
`9aa4983c` and appear below. Grill: [[GOV.5-open-questions]] Q-C1 (matrix
freshness ownership after ratification).
## Artifact 1 — tool inventory (measured, `origin/next` @ `9aa4983c`)
Registration root: `packages/mosaic/src/cli.ts` (commander); command modules
under `packages/mosaic/src/commands/`; `coord`/`prdy`/`doctor`/runtime
launchers dispatch to bash tools under `packages/mosaic/framework/tools/`
(subcommand tables at `commands/launch.ts:11511255`); sibling packages
(`brain`, `forge`, `macp`, `quality-rails`, `log`, `memory`, `queue`,
`storage`) register their own families.
Control-plane-relevant families, by rev1 domain:
| Domain | Families (measured) |
| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| SEAT | `fleet` (init/install/systemd/lifecycle/roster/add/remove/verify/ps), `fleet` roster-v2 CRUD (`get/plan/create/update/delete`), `fleet apply`/`reconcile`/`doctor`/`regen`, `fleet provision`, `fleet migrate-v1 preview`, `agent` (configs + enroll + nested fleet-agent commands), `promote`, `comms send` |
| ROLE | `fleet persona` (`list/show/customize` — baseline ⊕ `roles.local/` overrides), `fleet profile` (`list/show` topology templates) |
| HARN | `config` (framework config + hooks), `compose-contract <harness>`, `skill`, `seq`, `init`/`sync`/`bootstrap`, `doctor`, runtime launchers (`claude`/`codex`/`opencode`/`pi`, experimental `claudex`, `yolo`) |
| PROV | `gateway config` (raw provider API-key env vars only), `wizard` (setup-time provider config) |
| AUTHN | `login`, `auth users {list,create,delete}`, `auth sso {list,test}` (stubbed — see gaps), `auth sessions list` (stubbed), `gateway` token lifecycle (`config rotate-token/recover-token`) |
| SESS | `tui`, `sessions {list,resume,destroy}`, `interaction` (durable-session surface: enroll/attach/send/chat/stop/recover), `coord`, `watch`, `mission` |
| Governance/other | `prdy {init,update,validate,status}`, `federation {grant,peer}`, `macp tasks gate`, `telemetry`, `upgrade`/`update`/`restore`/`uninstall`, `q`, sibling-package families |
Notable structural facts: there is **no top-level `mosaic role` verb** — role
management lives at `fleet persona`, three levels deep; and `doctor`/`status`
exist twice (top-level framework-scoped vs `fleet`-scoped), shadowing by name.
## Artifact 2 + 3 — WebUI→tool mapping with measured state
Rows are the [[UI.1-webui-surfaces]] page domains; measured against
`apps/web/src/spa/pages/` and the gateway controllers on the same commit.
| Surface function | WebUI today | CLI today | Parity state |
| ---------------------------------------------------- | ------------------------------------------------------------------------------- | ----------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Seat lifecycle & roster (SEAT) | **no Seats page** (routes are only /admin, /settings, /projects, /tasks, /chat) | complete (`fleet`/`agent` families) | CLI-ahead — page is D2's work, tooling exists |
| Role/persona config (ROLE) | no page | `fleet persona` | CLI-ahead; naming mismatch: no `mosaic role` verb for the ROLE page to mirror |
| User role/ban (AUTHN) | admin UsersTab toggles role/ban via admin endpoints directly | `auth users` lacks `set-role`/`ban`/`unban` | **WebUI-only mutation — violates the D12 rule as implemented** |
| SSO admin (AUTHN) | SsoProviderSection reads _public_ `/api/sso/providers` discovery | `auth sso list/test` stubbed: "admin endpoint missing" | **blocked on gateway tooling**; CLI and WebUI don't even hit the same surface |
| Auth-session admin (AUTHN) | — | `auth sessions list` stubbed (no server endpoint) | blocked on gateway tooling |
| Provider list/test (PROV) | settings ProvidersTab: `GET /api/providers`, `POST /api/providers/test` | none — only `gateway config` raw env-var writes | **WebUI-only read/test — no `mosaic provider` family exists** |
| Default harness/provider/model selection (HARN/SESS) | `GET/PUT /api/chat/preferences/selection` per user | none persists the stored preference (`tui --model` is per-session only) | WebUI-only mutation |
| Authorization hierarchy & grants (UI-audit) | **no page** | **no command** | **the largest D12 gap**: `hierarchy.controller.ts` exposes full CRUD (companies, estates, platform-projects, grants incl. `grants/:id/change`) with audit repository and grant evaluation behind it — reachable only by raw API |
| Federation grants/peers | no page | `federation grant/peer` | CLI-ahead (posture pending Q-T1) |
**Consequences for the build order** (D8: tool first, then surface):
`mosaic provider {list,test}`, `auth users {set-role,ban,unban}`, a stored
harness-selection command, the missing gateway admin endpoints for SSO/session
listing, and a CLI face for the hierarchy/grant surface all precede their
pages. The two **WebUI-only mutations** (role/ban toggle, harness selection)
are standing D12 violations to remediate, not precedents to extend. The
hierarchy CRUD surface is the natural backing for [[UI.1-webui-surfaces]]'s
authorization audit page — but it must get a CLI face and an audit read-path
before the page ships.
## Command families in scope for the control plane
`mosaic config` (OD-49 desired-state engine), `mosaic coord` (agent coordination
boundary — register OD-09), `mosaic prdy` (PRD creation/acceptance — register
OD-22), role management (one canonical API, L2-D14), seat lifecycle
(launch/relaunch per register OD-59), `mosaic doctor` (drift detection classes,
e.g. the #1194 framework-tool drift addendum in [[GOV.4-workstream-contracts]]).
## `mosaic config` v1 subset (pulled 2026-08-31 from the minimal-subset spec)
The Q14 ruling (2026-08-29) fixes the current scope: shipped surface
`edit/get/set/show/hooks/path` **plus exactly two new read-only verbs**
`mosaic config validate` and `mosaic config plan` (`--file` | `--preset`,
mutually exclusive; `--format table|json`). `apply`, `add`, `restructure`,
`migrate`, `remove`, `export` are **out of v1 pending a full-engine ruling**
([[GOV.5-open-questions]] Q-D5) — the configuration-lifecycle draft's "stable
namespace" table describing the full family is aspirational, not current state.
Contract highlights: **valid** vs **conformant** are distinct verdicts with
distinct exit codes (nonconformance is a diagnostic, not a parser failure);
`plan` emits `create|update|blocked` operations with risk classes
(`none|review-required|full-engine-required`), a SHA-256 `planId`, and
`applySupported: false` always in v1; destructive/unsupported drift is
`blocked`, never silently normalized; absolute no-mutation during
validate/plan (no writes, no network, no credential calls); results ride the
T78 `CapabilityResultV1` envelope (capability IDs
`config.installation.validate`/`.plan`); inputs capped, YAML
aliases/anchors/tags rejected, no secret-shaped fields accepted or echoed.
## E2 inputs (triage 2026-08-31; see [[GOV.2-docs-inventory]])
**Canonical ground truth**: `requirements/cli-capability-migration.md` (T78,
`source_of_truth: true`), `fleet/reference/cli.md` (local fleet CLI vs
gateway-backed catalog), `USER-GUIDE/getting-started/quickstart.md`.
**Pending pulls**: DRAFT S2 `tool-gateway-mapping.md`; brain
`docs/specs/2026-08-29_mosaic-config-minimal-subset.md` (`mosaic config
validate/plan`, cites OD-49OD-55) and
`docs/guides/proposed/workflows/configuration-lifecycle.md` (the OD-49 engine
family definition).
## S2 contract feed (extraction 2026-08-31)
Full extraction record: lane `S2-EXTRACTION-2026-08-31.md` (per-contract cores, dependency edges, ruling cross-checks). Pulls binding on this section:
- **Contract 5 §4.5 is the parity clause this section's matrix enforces**:
CLI remains the primary execution method for every Gateway command; no
WebUI-only command exists; a Gateway command without CLI exposure is a
conformance gap tracked at the family's implementing issue. The
hierarchy/grants CRUD gap measured in this section is exactly such a
tracked conformance gap once contract 5 ratifies.
- **Command envelope**: typed request/result DTOs (no `any`), closed
per-family error taxonomy, audit correlation id, fail-closed — aligns with
the T78 `CapabilityResultV1` direction already in this section.
- **Contract 9 (api-artifacts)**: `ApiAuthClass` closed six-value enum
(`none`/`session`/`api-key`/`admin`/`federation`/`bootstrap`); OPENAPI.yaml
generated, CI byte-drift-gated, never hand-edited; hard ordering — nothing
under contract 9 lands before contract 5 (PR #1438) is on the trunk.
- **Roll-up (contract 8)** ships as a query-only tool with no command
counterpart (A5 rank 5) — the taxonomy precedent for read-only surfaces in
the parity matrix.
- **Mandated removals** the CLI inventory must track: `mosaic auth users
delete` (with the hard-delete endpoint) is required to be disabled/removed
by contract 4.
## Parity freshness ruling (Q-C1, Jason 2026-09-01)
The parity matrix becomes a generated artifact with a CI drift-gate witness in
the stack repo (the contract-9 pattern): CI regenerates the tool inventory and
WebUI→tool mapping from code and fails on divergence from the committed
matrix. No human cadence to forget. Building the witness is E6-return
follow-up work.