Card RI-4-001 — One transitional PRD authority (RI-N3, SDLC-D-036, #1275)
Worker card for the alpha 0.0.50 release-integrity workstream, executed by a pi zai/glm-5.3:high worker under fargo, independently verified (gates re-run, sabotage control reproduced) by the dispatching seat before push.
What this establishes
@mosaicstack/prdy structured storage under docs/prdy/ is the single PRD authority for the alpha. A new PrdService owns create/get/list/update/link/import/export; bothmosaic prdy and mosaic mission --plan route through it as thin adapters; the raw writers (createPrd/savePrd) are no longer exported — no second writer path.
Service surface (exported from @mosaicstack/prdy)
create (v1, draft) · get/list · update (bumps content version) · linkMission/listMissionLinks · planForMission (create+link, one write) · exportMarkdown · importDocument · acceptSuccessor. Typed errors: PrdNotFoundError, PrdUpdateError, PrdImportInvalidError (structural refusal, nothing written), PrdImportConflictError (refusal + proposed successor v+1, original bytes untouched). PRD_GENERATED_VIEW_LABEL = generated view — do not edit.
Design decisions
Linkage lives on the PRD document itself (missions: PrdMissionLinkage[] in the YAML authority) — survives restart by construction, no sidecar-sync failure mode. PrdMissionLinkage = { missionId, missionVersion, prdVersion, requirementIds, linkedAt }.
Markdown is a labeled generated view: export header carries the label + prd-id/version/generated-at + source path. No code path reads the exported Markdown back (grep-level + behavioral + negative-control: mutating the export leaves service-read authority deep-equal unchanged).
Import is explicit, validated, conflict-aware: zod validation before anything; valid imports persist as draft (validity ≠ approval); identical content → identical no-op; divergent same-id → typed conflict with proposed successor — never overwrites, never merges; successor persists only under explicit acceptSuccessor/--accept-successor.
docs/PRD.md untouched and never read in code — not a peer authority.
Schema v2 is backward-compatible (missions defaults empty; older docs parse).
requirementIds is [] at the mission --plan command — no requirement-selection UI yet; the schema carries ids when a caller has them.
Mission version marker is mission.updatedAt (gateway MissionInfo has no numeric version — noted in code).
Import accepts YAML only; Markdown→YAML reconstruction is deliberately absent (it would violate the read-back invariant).
No version history per PRD (single current version) — future card if required.
## Card RI-4-001 — One transitional PRD authority (RI-N3, SDLC-D-036, #1275)
Worker card for the alpha 0.0.50 release-integrity workstream, executed by a pi `zai/glm-5.3:high` worker under `fargo`, independently verified (gates re-run, sabotage control reproduced) by the dispatching seat before push.
## What this establishes
`@mosaicstack/prdy` structured storage under `docs/prdy/` is the single PRD authority for the alpha. A new `PrdService` owns create/get/list/update/link/import/export; **both** `mosaic prdy` and `mosaic mission --plan` route through it as thin adapters; the raw writers (`createPrd`/`savePrd`) are no longer exported — no second writer path.
## Service surface (exported from `@mosaicstack/prdy`)
`create` (v1, draft) · `get`/`list` · `update` (bumps content `version`) · `linkMission`/`listMissionLinks` · `planForMission` (create+link, one write) · `exportMarkdown` · `importDocument` · `acceptSuccessor`. Typed errors: `PrdNotFoundError`, `PrdUpdateError`, `PrdImportInvalidError` (structural refusal, nothing written), `PrdImportConflictError` (refusal + proposed successor v+1, original bytes untouched). `PRD_GENERATED_VIEW_LABEL` = `generated view — do not edit`.
## Design decisions
- **Linkage lives on the PRD document itself** (`missions: PrdMissionLinkage[]` in the YAML authority) — survives restart by construction, no sidecar-sync failure mode. `PrdMissionLinkage = { missionId, missionVersion, prdVersion, requirementIds, linkedAt }`.
- **Markdown is a labeled generated view**: export header carries the label + prd-id/version/generated-at + source path. No code path reads the exported Markdown back (grep-level + behavioral + negative-control: mutating the export leaves service-read authority deep-equal unchanged).
- **Import is explicit, validated, conflict-aware**: zod validation before anything; valid imports persist as `draft` (validity ≠ approval); identical content → `identical` no-op; divergent same-id → typed conflict with proposed successor — never overwrites, never merges; successor persists only under explicit `acceptSuccessor`/`--accept-successor`.
- `docs/PRD.md` untouched and never read in code — not a peer authority.
- Schema v2 is backward-compatible (`missions` defaults empty; older docs parse).
## Tests — contract per AC-RI-3
`packages/prdy`: 0 → **20 passed** (linkage round-trip incl. fresh-process read-back, export labeling, markdown-mutation negative control, import valid/identical/conflict/invalid). `packages/mosaic`: 1548 → **1557 passed** (6 prdy-adapter + 3 mission-linkage adapter specs; all 1548 pre-existing green).
**Sabotage controls** — worker's (whole persistence block removed): prdy 3 failed / mosaic 2 failed, all linkage tests, zero pre-existing failures; restored byte-identically, green. Dispatching seat's independent control (update-in-place arm only): prdy linkage test reddens (1/20), restore sha-verified green. Coverage note from the narrower control: fresh-linkage is covered at both package levels; update-in-place coverage is prdy-side.
## Gates (re-run by the dispatching seat, rc-honest)
`packages/prdy` build/lint/vitest 20/20 rc=0 · `packages/mosaic` build/lint/vitest 1557/1557 rc=0 · root build **25/25** rc=0 · root typecheck **45/45** rc=0. Scope: `packages/prdy/**`, `packages/mosaic/src/commands/{prdy,mission}*.ts` + specs, plus a card scratchpad (`scratchpads/ri-4-001-prd-authority.md`, repo card convention, disclosed).
## Known notes / non-goals
- `requirementIds` is `[]` at the `mission --plan` command — no requirement-selection UI yet; the schema carries ids when a caller has them.
- Mission version marker is `mission.updatedAt` (gateway `MissionInfo` has no numeric version — noted in code).
- Import accepts YAML only; Markdown→YAML reconstruction is deliberately absent (it would violate the read-back invariant).
- No version history per PRD (single current version) — future card if required.
- PrdService owns create/read/update/link/import/export; wizard and package
CLI become prompt layers over the service (no second writer path)
- PRD documents gain a content version and a missions linkage array persisted
in the YAML authority store (survives restart); linkage writes do not bump
the content version
- exportMarkdown renders a labeled generated view (id + version + do-not-edit
header) that no code path reads back; the store loads .yaml/.yml only
- importDocument validates structure with zod before anything else, persists
valid imports as draft (validity is not approval), and refuses conflicts
with a typed PrdImportConflictError carrying a proposed successor; the
original document stays byte-identical until acceptSuccessor
- raw store writers (createPrd/savePrd) are no longer exported from the
package entry point
- mosaic prdy becomes a thin adapter: --init/--update (wizard for TTY,
service otherwise), --import with --accept-successor, --export
- mosaic mission --plan persists the mission↔PRD linkage (mission id +
version marker, PRD id + version) through the service instead of invoking
the wizard as a second writer; non-TTY runs create non-interactively
RI-4-001 independent review (jarvis, cross-seat per handoff protocol; producer was a pi worker under fargo).
Verified against head 8d258e1d: PrdService is the single authority surface — raw writers createPrd/savePrd deliberately unexported from @mosaicstack/prdy (no second writer path); both mosaic prdy and mission --plan route through it as thin adapters; planForMission performs create + mission<->PRD linkage in one authority write, linkage persisted in the PRD document (survives restart), mission.updatedAt as version marker documented; Markdown export carries the PRD_GENERATED_VIEW_LABEL header; import is conflict-aware (PrdImportConflictError carrying existing vs proposal). Executed locally: prdy 20/20, mosaic prdy.spec + mission-prd.spec 9/9 (after building prdy dist; the 19 unrelated failing suites in a bare minimal install are the known workspace build-order artifact, not this change — same class fargo documented).
RI-4-001 independent review (jarvis, cross-seat per handoff protocol; producer was a pi worker under fargo).
Verified against head 8d258e1d: PrdService is the single authority surface — raw writers createPrd/savePrd deliberately unexported from @mosaicstack/prdy (no second writer path); both mosaic prdy and mission --plan route through it as thin adapters; planForMission performs create + mission<->PRD linkage in one authority write, linkage persisted in the PRD document (survives restart), mission.updatedAt as version marker documented; Markdown export carries the PRD_GENERATED_VIEW_LABEL header; import is conflict-aware (PrdImportConflictError carrying existing vs proposal). Executed locally: prdy 20/20, mosaic prdy.spec + mission-prd.spec 9/9 (after building prdy dist; the 19 unrelated failing suites in a bare minimal install are the known workspace build-order artifact, not this change — same class fargo documented).
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Card RI-4-001 — One transitional PRD authority (RI-N3, SDLC-D-036, #1275)
Worker card for the alpha 0.0.50 release-integrity workstream, executed by a pi
zai/glm-5.3:highworker underfargo, independently verified (gates re-run, sabotage control reproduced) by the dispatching seat before push.What this establishes
@mosaicstack/prdystructured storage underdocs/prdy/is the single PRD authority for the alpha. A newPrdServiceowns create/get/list/update/link/import/export; bothmosaic prdyandmosaic mission --planroute through it as thin adapters; the raw writers (createPrd/savePrd) are no longer exported — no second writer path.Service surface (exported from
@mosaicstack/prdy)create(v1, draft) ·get/list·update(bumps contentversion) ·linkMission/listMissionLinks·planForMission(create+link, one write) ·exportMarkdown·importDocument·acceptSuccessor. Typed errors:PrdNotFoundError,PrdUpdateError,PrdImportInvalidError(structural refusal, nothing written),PrdImportConflictError(refusal + proposed successor v+1, original bytes untouched).PRD_GENERATED_VIEW_LABEL=generated view — do not edit.Design decisions
missions: PrdMissionLinkage[]in the YAML authority) — survives restart by construction, no sidecar-sync failure mode.PrdMissionLinkage = { missionId, missionVersion, prdVersion, requirementIds, linkedAt }.draft(validity ≠ approval); identical content →identicalno-op; divergent same-id → typed conflict with proposed successor — never overwrites, never merges; successor persists only under explicitacceptSuccessor/--accept-successor.docs/PRD.mduntouched and never read in code — not a peer authority.missionsdefaults empty; older docs parse).Tests — contract per AC-RI-3
packages/prdy: 0 → 20 passed (linkage round-trip incl. fresh-process read-back, export labeling, markdown-mutation negative control, import valid/identical/conflict/invalid).packages/mosaic: 1548 → 1557 passed (6 prdy-adapter + 3 mission-linkage adapter specs; all 1548 pre-existing green).Sabotage controls — worker's (whole persistence block removed): prdy 3 failed / mosaic 2 failed, all linkage tests, zero pre-existing failures; restored byte-identically, green. Dispatching seat's independent control (update-in-place arm only): prdy linkage test reddens (1/20), restore sha-verified green. Coverage note from the narrower control: fresh-linkage is covered at both package levels; update-in-place coverage is prdy-side.
Gates (re-run by the dispatching seat, rc-honest)
packages/prdybuild/lint/vitest 20/20 rc=0 ·packages/mosaicbuild/lint/vitest 1557/1557 rc=0 · root build 25/25 rc=0 · root typecheck 45/45 rc=0. Scope:packages/prdy/**,packages/mosaic/src/commands/{prdy,mission}*.ts+ specs, plus a card scratchpad (scratchpads/ri-4-001-prd-authority.md, repo card convention, disclosed).Known notes / non-goals
requirementIdsis[]at themission --plancommand — no requirement-selection UI yet; the schema carries ids when a caller has them.mission.updatedAt(gatewayMissionInfohas no numeric version — noted in code).RI-4-001 independent review (jarvis, cross-seat per handoff protocol; producer was a pi worker under fargo).
Verified against head
8d258e1d: PrdService is the single authority surface — raw writers createPrd/savePrd deliberately unexported from @mosaicstack/prdy (no second writer path); both mosaic prdy and mission --plan route through it as thin adapters; planForMission performs create + mission<->PRD linkage in one authority write, linkage persisted in the PRD document (survives restart), mission.updatedAt as version marker documented; Markdown export carries the PRD_GENERATED_VIEW_LABEL header; import is conflict-aware (PrdImportConflictError carrying existing vs proposal). Executed locally: prdy 20/20, mosaic prdy.spec + mission-prd.spec 9/9 (after building prdy dist; the 19 unrelated failing suites in a bare minimal install are the known workspace build-order artifact, not this change — same class fargo documented).