Skip to content

Canonical-pipeline → task-list migration — PLAN

Canonical-pipeline → task-list migration — PLAN

Section titled “Canonical-pipeline → task-list migration — PLAN”

Spec status header Slug: canonical-pipeline-task-list-migration Version: v1.0 (draft, S65 WP1b) Last verified: 22/05/2026 Linked PRODUCT: docs/specs/id-31-canonical-pipeline-task-list-migration/PRODUCT.md Linked TECH: docs/specs/id-31-canonical-pipeline-task-list-migration/TECH.md Authored by: task-planner under planning-and-task-breakdown, fresh Planner instance per Q-PLANNER-2 / B4 — independent review pass over PRODUCT.md + TECH.md by a Planner who did not author either upstream spec. Status: DRAFT — awaits Checker promotion of Subtask 31.4 in_progress → done. Cross-Task input: docs/research/cross-task-dependency-map-and-sequencing.md (S65 WP0, commit a6095553 on origin/main; absent on production-readiness at PLAN-author time, expected post-merge).


This PLAN decomposes canonical-pipeline-task-list-migration (Task ID-31) into seven implementation Subtasks {31.5..31.11} that land the umbrellas.json ledger surface + schema + helpers + skill extension + supporting tests, per the ratified PRODUCT.md (17 invariants) and TECH.md (17 Proposed changes, 803 L).

The decomposition reflects four major ratifications absorbed at S65 session-start that materially reshape the original TECH §6 7-Subtask outline:

  1. P-OQ-4 A2 EXPANDED (NEW, S65 W0 — supersedes PRODUCT P-OQ-4 default): T0 is NOT a distinct Task. The canonical-pipeline umbrella entry’s substrate_doc references mempalace + cocoindex-code + gitnexus + original documentation for historical / pre-phase context. PLAN does NOT decompose into a “T0 retro Task” Subtask. The umbrella + cross-references is the canonical pair. See §6 for the load-bearing narrative.
  2. T-OQ-1 RATIFIED DEFAULT: Helper at lib/validation/umbrellas-helpers.ts (consistent with lib/validation/jsonb.ts co-location pattern). lib/ledger/ is premature; task-view-repo and .planning/task-management/ rejected on technical grounds. Confidence HIGH per WP0 §4.
  3. OQ-B1 ordering: ID-31 Promote-mode extension (Subtask 31.9 handling umbrella_id add) lands AFTER ID-30 PR-A curator-skill rewrite. Largest-semantic- change first.
  4. OQ-C2 strict-sequence: ID-31 §3 schema (umbrellas-schema.ts + umbrellas-helpers.ts) lands AFTER ID-30 PR-A schema additions. Both touch lib/validation/. Do NOT co-land.

The retro-Task population originally scoped under TECH §6.1 row 31.10 (T0-T6 opens) is REMOVED from this PLAN. Retro T1-T6 (six Tasks for already-shipped phases) remain PRODUCT invariants but are dispatched in Wave 3 via separate orchestrator-driven opens (not as Subtasks of ID-31). T0 specifically is collapsed per P-OQ-4 A2 EXPANDED. The PLAN’s scope ends at “infrastructure ready to receive retro opens” — schema, helpers, initial umbrellas.json, skill extension, tests, MAX-ID discipline.

Subtask count: 7. Well within the 25-soft-ceiling. Sibling-only deps verified across all rows. No cross-Task Subtask references (cross-Task ordering lives at the Wave level per §4 and §5).

Total estimated effort: ~4-5h wall-clock (down from TECH §9’s ~5h because retro opens are out of scope here).

1.1 Forward-compat constraint locked at Wave 2 merge (ID-9 consumer)

Section titled “1.1 Forward-compat constraint locked at Wave 2 merge (ID-9 consumer)”

The umbrellas.json field names are LOCKED at Subtask 31.5 schema authoring. ID-9 docubot (Wave 7) will consume verbatim. Field names MUST be id, title, substrate_doc, task_ids, status, phase — no renames post-Wave-2. This is called out in every Subtask brief that touches the schema.

1.2 Stub-umbrella set (brief-specific override of TECH §3.3)

Section titled “1.2 Stub-umbrella set (brief-specific override of TECH §3.3)”

Per brief: 3 stub umbrellas in 31.7 backfill — prod-readiness, ux-platform, ai-platform. This is a deliberate brief override of TECH §3.3’s 4-stub set (production-readiness, sales-proposals, intelligence-workspaces, docs-foundation). The brief’s 3 names reflect Liam’s preferred initial taxonomy post-S65 WP0 absorption.


§2 Subtask records (TM-shape, for orchestrator integration into task-list.json)

Section titled “§2 Subtask records (TM-shape, for orchestrator integration into task-list.json)”

Each Subtask is rendered below as a structured block with the load-bearing fields the Executor receives. The Orchestrator copies these into Task 31’s subtasks[] array. The id integer is local to Task 31 (not a global Task id); Subtask ids are 5 through 11 inclusive.


Subtask 31.5 — Author umbrellas-schema.ts + unit test

Section titled “Subtask 31.5 — Author umbrellas-schema.ts + unit test”
  • id: 5
  • title: Author lib/validation/umbrellas-schema.ts + unit test
  • status: pending
  • dependencies: [] (no sibling deps — foundation layer)
  • priority: should-have
  • effort_h: 0.5
  • file-ownership zone:
    • lib/validation/umbrellas-schema.ts (NEW)
    • __tests__/validation/umbrellas-schema.test.ts (NEW)

description (≤200 chars): Author the Zod schema for umbrellas.json per TECH §3.2. Three exports: UmbrellaStatus (4-value enum), UmbrellaEntrySchema, UmbrellasSchema (root). Strict mode throughout.

details (load-bearing — Executor receives this verbatim):

SCOPE: Create `lib/validation/umbrellas-schema.ts` per TECH §3.2 spec. Mirror the
existing pattern in `lib/validation/{task-list,backlog,roadmap}-schema.ts` —
strict-mode Zod objects, no barrel re-export, named-export each schema + each
inferred type.
EXACT SCHEMA TO AUTHOR (verbatim from TECH §3.2, lines 122–230):
- `UmbrellaStatus = z.enum(['proposed', 'in_progress', 'done', 'archived'])`
- `UmbrellaEntrySchema` with 6 fields, all required, .strict():
- `id`: z.string().regex(/^[a-z][a-z0-9-]*[a-z0-9]$/, 'Umbrella id must be kebab-case…')
- `title`: z.string().min(1)
- `substrate_doc`: z.string().min(1)
- `task_ids`: z.array(z.string().regex(BARE_ID_REGEX, 'task_ids[] entries must be bare-digit Task ids'))
- `status`: UmbrellaStatus
- `phase`: z.string().min(1)
- `UmbrellasSchema` root with 5 fields, .strict():
- `document_name`: z.literal('umbrellas')
- `document_purpose`: z.string().min(1)
- `last_updated`: z.string() with 200-char cap, single-line, single-session-id refine, kh-{prod-readiness|main}-S{N} prefix regex — IDENTICAL to TaskListSchema.last_updated (copy that block verbatim)
- `related_documents`: z.array(z.string())
- `umbrellas`: z.array(UmbrellaEntrySchema)
IMPORTS:
- `import { z } from 'zod';`
- `import { BARE_ID_REGEX } from '@/lib/validation/schemas';` (already exists at `lib/validation/schemas.ts:50`)
- NO barrel re-export (CLAUDE.md gotcha — direct file imports only).
FORWARD-COMPAT CONSTRAINT (LOAD-BEARING per Wave 2 merge):
The 6 UmbrellaEntry field names — `id`, `title`, `substrate_doc`, `task_ids`,
`status`, `phase` — are LOCKED. ID-9 docubot (Wave 7) consumes verbatim. Do NOT
rename, do NOT add fields without surfacing as a T-OQ to the orchestrator (T-OQ-5
explicitly defers schema growth).
UNIT TEST CASES (in `__tests__/validation/umbrellas-schema.test.ts`):
- Valid root parses (umbrellas array with at least one entry).
- Each of 4 UmbrellaStatus enum values accepted as `status`.
- Invalid status string rejected.
- Invalid `id` shape rejected: 'NotKebab', 'has space', '-leading-hyphen', 'trailing-'.
- Valid `id` shapes accepted: 'a', 'foo', 'foo-bar', 'foo-bar-baz', 'foo2', 'a1b2-c3'.
- Empty `task_ids[]` accepted.
- `task_ids[]` entry not matching BARE_ID_REGEX rejected (e.g. 'ID-30', 'abc').
- `task_ids[]` entry matching ('28', '30', '36') accepted.
- Multi-membership (same Task id in two entries) accepted (schema imposes no uniqueness).
- `.strict()` rejects unknown extra fields at both root and entry level.
- last_updated rejects: empty, multi-line, multi-session-id append, >200 chars,
non-kh-prefix.
- last_updated accepts valid: `kh-prod-readiness-S65 WP1b close-out — umbrellas schema landed`.
VERIFY:
- `bun run test -- umbrellas-schema` — all green.
- `tsc --noEmit` against the new file (no type errors).
- ESLint local rules pass (no-barrel-imports / no-silent-promise-catch don't apply
here — schema file).
NO IMPLEMENTATION OF HELPER FILE IN THIS SUBTASK. Helper lives in 31.6.
NO `umbrellas.json` AUTHORING IN THIS SUBTASK. Data file lives in 31.7.

testStrategy: Unit test __tests__/validation/umbrellas-schema.test.ts covers all 6 enum values, kebab-case regex, BARE_ID_REGEX on task_ids, strict-mode rejection, last_updated discipline, and multi-membership acceptance — all green via bun run test -- umbrellas-schema.


Subtask 31.6 — Author umbrellas-helpers.ts (journal-block helper) + unit test

Section titled “Subtask 31.6 — Author umbrellas-helpers.ts (journal-block helper) + unit test”
  • id: 6
  • title: Author lib/validation/umbrellas-helpers.ts (formatRetrospectiveJournalBlock) + unit test
  • status: pending
  • dependencies: [5] (consumes UmbrellaEntry type from schema)
  • priority: should-have
  • effort_h: 0.75
  • file-ownership zone:
    • lib/validation/umbrellas-helpers.ts (NEW)
    • __tests__/validation/umbrellas-helpers.test.ts (NEW)

description (≤200 chars): Author formatRetrospectiveJournalBlock(input) helper per TECH §5. Returns formatted journal text matching PRODUCT inv 12. UK English. ISO 8601 timestamps.

details (load-bearing):

SCOPE: Implement the `formatRetrospectiveJournalBlock` helper per TECH §5.1 signature
+ §5.2 worked example. The helper renders a structured retrospective journal block
for use in retrospective Subtask `details` fields (Wave 3 retro T1-T6 opens — not
this Task).
T-OQ-1 RATIFIED DEFAULT: Helper file lives at `lib/validation/umbrellas-helpers.ts`
(NOT `lib/ledger/`). Sibling to `umbrellas-schema.ts` for co-location with the
schema. Confirmed HIGH-confidence per WP0 §4.
EXACT SIGNATURE (verbatim from TECH §5.1):
```typescript
import type { UmbrellaEntry } from '@/lib/validation/umbrellas-schema';
export interface RetrospectiveOpeningInput {
retro_open_session: string; // e.g. "kh-prod-readiness-S64"
original_session: string; // e.g. "S242"
original_branch: string; // e.g. "content-items-investigation"
continuation_prompt_path: string; // e.g. "docs/continuation-prompts/..."
commits: Array<{ sha8: string; message_line: string }>;
migration_files?: string[];
plan_md_section: string; // e.g. "4.1"
followup_flags?: string[];
umbrella_id?: string;
}
export function formatRetrospectiveJournalBlock(input: RetrospectiveOpeningInput): string

OUTPUT TEMPLATE (verbatim from TECH §5.1 + §5.2 worked example):

<info added on {ISO_TIMESTAMP}>
RETROSPECTIVE OPENING — Task opened in `done` status post-implementation.
Original work happened {original_session} per `{continuation_prompt_path}`.
Commits ({original_session}, {original_branch}):
- {sha8} — {message_line}
... (one line per commit, in input order)
Migration files: (only if `migration_files` is non-empty)
- {file}
... (one line per file)
Follow-up flags: (only if `followup_flags` is non-empty)
- {flag}
... (one line per flag)
Umbrella: {umbrella_id} (only if `umbrella_id` is non-null)
PLAN.md §{plan_md_section} acceptance criteria all met.
</info added on {ISO_TIMESTAMP}>

The opening + closing <info added on …> timestamps MUST match exactly. Generate a single ISO 8601 timestamp via new Date().toISOString() at invocation time; tests inject a fixed timestamp via vi.useFakeTimers() / vi.setSystemTime().

UK ENGLISH ENFORCED throughout output text (PRODUCT inv 15): the template uses “organisation”, “behaviour”, “colour” — but the structural words (“Commits”, “Migration files”, “Follow-up flags”, “Umbrella”) match TECH §5.2 verbatim and stay in the form shown.

NO umbrellas.json LOOKUP IN THIS HELPER. The optional umbrella_id input is inserted into the output as a plain string — the helper does NOT load umbrellas.json to verify the id exists. That verification is the caller’s responsibility (Wave 3 orchestrator at retro-open time).

UNIT TEST CASES (in __tests__/validation/umbrellas-helpers.test.ts):

  • Output starts with <info added on and ends with </info added on .
  • Opening + closing timestamps match (extract via regex; assert equal).
  • Body contains RETROSPECTIVE OPENING — Task opened in \done` status`.
  • Body contains Original work happened {original_session}.
  • Commits block lists one line per input commit in order with - {sha8} — {message_line}.
  • migration_files omitted from output when input is undefined/empty.
  • migration_files rendered as bulleted list when input is non-empty.
  • followup_flags omitted when undefined/empty; rendered when non-empty.
  • Umbrella: ... line omitted when umbrella_id undefined; rendered when present.
  • Body ends with PLAN.md §{plan_md_section} acceptance criteria all met.
  • Fixture round-trip: feed the input from TECH §5.2 worked example; output matches verbatim modulo timestamp.

VERIFY:

  • bun run test -- umbrellas-helpers — all green.
  • tsc --noEmit against helper + test.
  • Manual eye on a worked output via fixture run.

NO BARREL RE-EXPORT. Direct file import only.

**testStrategy:** Unit test `__tests__/validation/umbrellas-helpers.test.ts` matches
helper output against TECH §5.2 worked example fixture (timestamp-stubbed), verifies
opening/closing timestamps align, and verifies optional fields render correctly when
present and omit when absent.
---
### Subtask 31.7 — Author initial `docs/reference/umbrellas.json` (canonical-pipeline + 3 stubs)
- **id:** 7
- **title:** Author initial `docs/reference/umbrellas.json` with canonical-pipeline + 3 stub umbrellas
- **status:** `pending`
- **dependencies:** `[5]` (consumes schema for parse validation)
- **priority:** `should-have`
- **effort_h:** 0.25
- **file-ownership zone:**
- `docs/reference/umbrellas.json` (NEW)
**description (≤200 chars):** Create initial `umbrellas.json` with `canonical-pipeline`
populated entry (`task_ids` initially empty pending Wave-3 retro opens) + 3 stub
umbrellas (`prod-readiness`, `ux-platform`, `ai-platform`) per brief override of TECH
§3.3.
**details (load-bearing):**
```text
SCOPE: Create `docs/reference/umbrellas.json` with the brief-specified initial
populated set (1 + 3 stubs).
P-OQ-4 A2 EXPANDED (LOAD-BEARING):
T0 is NOT a distinct Task. The canonical-pipeline umbrella's `substrate_doc` body
references mempalace + cocoindex-code + gitnexus + original documentation for
historical/pre-phase context. This Subtask authors the `umbrellas.json` entry that
points `substrate_doc` to `docs/specs/id-31-canonical-pipeline-implementation-plan/PLAN.md`
— and authors a NEW small adjacent index file
`docs/specs/id-31-canonical-pipeline-implementation-plan/PRE-PHASE-REFERENCES.md` that
lists the historical references (mempalace wing, cocoindex-code corpus,
GitNexus repo, original Phase 0.9 docs). PLAN.md itself stays untouched per PRODUCT
non-goal (line 73-74). The PRE-PHASE-REFERENCES.md doc is the historical-context
artefact substituting for what would have been "T0 Task subtasks".
BRIEF OVERRIDE on stub set (NOT TECH §3.3's 4-stub):
Stubs to author in this Subtask:
- id: 'prod-readiness', title: 'Production Readiness', substrate_doc: 'docs/tracks/production-readiness.md', task_ids: [], status: 'in_progress', phase: 'Phase 1'
- id: 'ux-platform', title: 'UX Platform', substrate_doc: 'docs/tracks/ux-platform.md', task_ids: [], status: 'proposed', phase: 'Phase 1'
- id: 'ai-platform', title: 'AI Platform', substrate_doc: 'docs/tracks/ai-platform.md', task_ids: [], status: 'proposed', phase: 'Phase 1'
Two of the three stub substrate_doc paths (`docs/tracks/ux-platform.md` and
`docs/tracks/ai-platform.md`) may not exist yet on disk — that is INTENTIONAL. The
schema validates only that `substrate_doc` is a non-empty string. The Astro renderer
(future, ID-9 Wave 7) will surface a 404 badge if the substrate doc isn't yet
written, signalling the stub's substrate is still pending. Do NOT create empty
placeholder substrate files in this Subtask.
CANONICAL-PIPELINE ENTRY:
- id: 'canonical-pipeline'
- title: 'Canonical Pipeline Implementation'
- substrate_doc: 'docs/specs/id-31-canonical-pipeline-implementation-plan/PLAN.md'
- task_ids: [] (left EMPTY at first commit — populated by Wave 3 retro opens
when T1-T6 retro Tasks land; T8 = ID-28 added when T8 status reaches
`in_progress`; T7 + T9-T14 added JIT)
- status: 'in_progress'
- phase: 'Phase 1'
PRE-PHASE-REFERENCES.md SHAPE:
Author a NEW small markdown file at
`docs/specs/id-31-canonical-pipeline-implementation-plan/PRE-PHASE-REFERENCES.md` (~30-50
lines) containing:
- Title + one-paragraph context: "Pre-phase substrate (S180-S241) for the
canonical-pipeline initiative. Per P-OQ-4 A2 EXPANDED (S65 W0), this initiative
has no T0 retro Task — the historical context lives here as cross-references to
the knowledge sources that captured the pre-phase work."
- References section listing FOUR canonical sources:
1. mempalace wing — `wing_canonical_pipeline` (or equivalent — Executor verifies
current wing name via `mempalace_list_wings` before writing)
2. cocoindex-code corpus — `docs/specs/id-31-0.9-canonical-pipeline/{PRODUCT,TECH}.md`
and architecture sub-docs (`02-data-flow.md`, `04-workspace-types.md`,
`05-qa-flow.md`, `06-mcp-tooling.md`, `08-new-features.md`)
3. GitNexus repo — knowledge-hub indexed corpus (Executor cites the
gitnexus_query / gitnexus_context entry path)
4. Original Phase 0.9 documentation — pointer to the drift audit +
implementation-readiness audit + STILL-OPEN consolidation set in
`docs/specs/id-31-0.9-canonical-pipeline/` (Executor enumerates the files present
at impl time; references stay paths-only — no content duplication)
- Closing line linking forward to PLAN.md: "Pre-phase substrate complete S241.
Phase 1 implementation begins at `PLAN.md` §1."
UK ENGLISH throughout (PRODUCT inv 15).
`last_updated` FIELD discipline — must match the schema regex
`/^kh-(prod-readiness|main)-S\d+/`, be ≤200 chars, single-line, single session-id.
Example acceptable form:
`kh-prod-readiness-S65 WP1b close-out — initial umbrellas.json + canonical-pipeline + 3 stubs`
VERIFY:
- `bun run test -- umbrellas-roundtrip` (after 31.8 authors the test) — green.
- Manual `cat docs/reference/umbrellas.json | jq` — valid JSON, 5 umbrellas.
- File `docs/specs/id-31-canonical-pipeline-implementation-plan/PRE-PHASE-REFERENCES.md`
exists, is ~30-50 lines, references all four canonical sources.
FORWARD-COMPAT REMINDER:
Field names locked at Wave 2 merge. ID-9 docubot will read this file verbatim in
Wave 7. Any field-name change post-this-Subtask requires coordinated edit to ID-9
brief.

testStrategy: bun run test -- umbrellas-roundtrip (after 31.8 lands) parses docs/reference/umbrellas.json cleanly via UmbrellasSchema and asserts 4 umbrella entries present (1 canonical-pipeline + 3 stubs). Manual eye on PRE-PHASE-REFERENCES.md matching all 4 historical-source references per P-OQ-4 A2 EXPANDED narrative.


Subtask 31.8 — Add round-trip tests (umbrellas-roundtrip + umbrellas-task-list-roundtrip)

Section titled “Subtask 31.8 — Add round-trip tests (umbrellas-roundtrip + umbrellas-task-list-roundtrip)”
  • id: 8
  • title: Add round-trip tests for umbrellas.json (self-parse + cross-doc with task-list)
  • status: pending
  • dependencies: [5, 7] (schema + umbrellas.json must exist)
  • priority: should-have
  • effort_h: 0.5
  • file-ownership zone:
    • __tests__/validation/umbrellas-roundtrip.test.ts (NEW)
    • __tests__/docs/umbrellas-task-list-roundtrip.test.ts (NEW)

description (≤200 chars): Author two round-trip tests per TECH §3.4: schema self- parse + cross-doc validation of task_ids[] against real Task entries. Orphans warn (don’t fail) per P-OQ-2.

details (load-bearing):

SCOPE: Author two new test files per TECH §3.4 verbatim:
TEST 1: `__tests__/validation/umbrellas-roundtrip.test.ts`
- describe block: 'umbrellas.json round-trip'
- it block: 'parses cleanly via UmbrellasSchema'
- readFileSync('docs/reference/umbrellas.json', 'utf-8')
- JSON.parse + UmbrellasSchema.parse
- expect(parsed.umbrellas.length).toBeGreaterThan(0)
TEST 2: `__tests__/docs/umbrellas-task-list-roundtrip.test.ts`
- describe block: 'umbrellas ↔ task-list round-trip (PRODUCT inv 9)'
- Reads both `docs/reference/umbrellas.json` AND `docs/reference/task-list.json` at
top-level (parse-once pattern).
- it block 1: 'every umbrellas[].task_ids[] entry references a real Task'
- For each umbrella entry, for each task_id in task_ids[]: assert realTaskIds.has(id)
- Collect broken refs into array; expect(broken).toEqual([])
- HARD FAIL on broken reference (FAIL fast — the canary).
- it block 2: 'warns (but does not fail) on orphan Tasks (P-OQ-2 default)'
- Build set of assigned Task ids (union of all task_ids[] across umbrellas).
- For each Task in task-list.tasks: if id not in assigned, push to orphans[].
- if orphans.length > 0: console.warn(`Umbrella round-trip: ${N} orphan Task(s):`, orphans)
- expect(true).toBe(true) // never fail — soft warning only
USE EXACT IMPLEMENTATIONS FROM TECH §3.4 LINES 299-353 (copy verbatim, adjusting
import paths to `@/lib/validation/umbrellas-schema` + `@/lib/validation/task-list-schema`).
IMPORTANT — the test parses task-list.json via TaskListSchema. As of Wave 2
landing time, task-list.json has Tasks ID-6 through ID-35 across all observed
branches. The cross-doc test must pass with whatever the task-list.json HEAD shape
is — do NOT bake in specific Task ids. Use the set-membership pattern.
ORPHAN WARNING expected at first run: with canonical-pipeline.task_ids[] empty (per
31.7), every existing Task is orphan. console.warn fires once per missing-assignment
Task. Test still passes per P-OQ-2 soft-warning design.
VERIFY:
- `bun run test -- umbrellas-roundtrip` — green.
- `bun run test -- umbrellas-task-list-roundtrip` — green; console.warn emitted with
list of orphan ids.
- The two test files are sibling-isolated (no shared fixture/helper — TECH T-OQ-4
ratified default: per-test re-read accepted).
NO MODIFICATION OF SCHEMA OR HELPER FILES IN THIS SUBTASK. Tests only.

testStrategy: Both test files run green via bun run test -- umbrellas; the cross-doc test correctly catches broken Task-id references (verified via local mutate of umbrellas.json adding a non-existent id — test goes red; revert — test goes green).


Subtask 31.9 — Extend update-roadmap-backlog skill (Create mode + umbrella_id field)

Section titled “Subtask 31.9 — Extend update-roadmap-backlog skill (Create mode + umbrella_id field)”
  • id: 9
  • title: Extend update-roadmap-backlog skill — Create mode for task-list target + shared umbrella_id field
  • status: pending
  • dependencies: [5, 7] (schema + initial umbrellas.json must exist)
  • priority: should-have
  • effort_h: 0.5
  • file-ownership zone:
    • .claude/skills/update-roadmap-backlog/SKILL.md (edit — surgical addition)

description (≤200 chars): Surgical addition to update-roadmap-backlog: extend Create mode to support task-list target + add shared umbrella_id input field triggering same-commit umbrellas.json edit. Per T-OQ-2 RATIFIED.

details (load-bearing):

SCOPE: Surgical addition to `.claude/skills/update-roadmap-backlog/SKILL.md`.
T-OQ-2 RATIFIED DEFAULT (from S65 W0 ratifications):
Extend Create mode (NOT add new OpenTask mode). Add `task-list` as a target option.
Add a shared `umbrella_id` field.
WAVE 2 ORDERING (LOAD-BEARING — OQ-B1):
THIS SUBTASK MUST DISPATCH AFTER ID-30 PR-A curator-skill rewrite has merged.
The ID-30 PR-A rewrite is the "biggest semantic shift" (Branch B/C semantic rewrite
+ Create/Update/Delete/Promote modes under Shape A). ID-31 §6.4 `umbrella_id`
extension is a parameter-only surgical addition. Dispatch order:
1. ID-30 PR-A curator-skill rewrite — merges first.
2. ID-31.9 Promote-extension (this Subtask) — surgical insert into rewritten skill.
3. ID-23 caller-count amendments — later wave (Wave 5).
If ID-30 PR-A has NOT merged at dispatch time, ESCALATE to the orchestrator. Do NOT
proceed; the surgical-insertion model requires the rewritten skill as input.
CHANGES TO THE SKILL BODY:
(a) Create mode — add `task-list` as a target option.
Currently the skill's Create mode (per the post-ID-30 form) supports targets
`product-roadmap` + `product-backlog`. Add a third target: `task-list`. The new
target writes a new top-level Task into `docs/reference/task-list.json#/tasks`.
Required Task fields at Create time (per TaskSchema strict mode — see
`lib/validation/task-list-schema.ts`):
- id (string regex `^\d+$`) — caller supplies; must equal MAX_ID_ACROSS_BRANCHES + 1
- title, description, status, priority, dependencies, subtasks (may be []),
updatedAt, effort_estimate, owner, priority_note, status_note,
cross_doc_links, session_refs, commit_refs
All four nullable fields (effort_estimate, owner, priority_note, status_note) must
be PRESENT (explicit null acceptable).
(b) Shared `umbrella_id` field — ALL Create-mode targets (and Promote mode).
Add a new optional input field `umbrella_id: string | null` (kebab-case or null;
default null). Semantics:
- When non-null AND destination_shape resolves to a Task (top-level): triggers a
same-commit edit to `docs/reference/umbrellas.json` appending the new Task id
to the named umbrella's `task_ids[]` array. Idempotent (skip if already present).
- When non-null AND destination_shape is subtask: ignored. Subtasks inherit
parent Task's umbrella membership.
- When null: no umbrellas.json edit. Task lands as orphan (P-OQ-2 default — soft
warning at next round-trip test run).
(c) New skill step "9. Umbrella membership edit (optional)":
After the existing Create-mode write completes, if `umbrella_id` is non-null:
- Load `docs/reference/umbrellas.json`.
- Parse via UmbrellasSchema (import from `@/lib/validation/umbrellas-schema`).
- Find umbrella entry with `id === input.umbrella_id`. If not found, ERROR + abort.
- Append destination Task id to that umbrella's `task_ids[]` (skip if already
present — idempotent).
- Bump `last_updated` on umbrellas.json per the field-discipline rule (single
line, ≤200 chars, single session-id, kh-{prod-readiness|main}-S{N} prefix).
- Validate via `UmbrellasSchema.parse(...)`. Abort on failure.
- Commit BOTH `task-list.json` AND `umbrellas.json` edits in a single commit
(PRODUCT inv 17 commit-coupling discipline).
DOC THE FORWARD-TASK OPEN PATTERN (per TECH §6.5):
When the orchestrator opens each forward Task JIT (per PRODUCT inv 6):
1. Compute fresh resolved id via cross-branch MAX-ID query.
2. Open the Task with spec-chain Subtasks ({N.1 RESEARCH, N.2 PRODUCT, N.3 TECH,
N.4 PLAN}) per `spec-driven-implementation` skill.
3. Call `update-roadmap-backlog` Create with `target: 'task-list'` and
`umbrella_id: 'canonical-pipeline'` (or other applicable umbrella).
4. Optionally append `(see Task ID-NN)` backlink to PLAN.md §4.n header per Inv 14.
CHECK ID-30 PR-A's `capability_theme` PARAMETER COEXISTS PEACEFULLY:
Per cross-task dep map row 10: ID-30 PR-A Promote rewrite adds `capability_theme`
copy-through; this Subtask's `umbrella_id` is the same Promote-mode shape extension.
The combined Promote signature becomes:
Promote(source_backlog_id, dest_task_id, [capability_theme], [umbrella_id])
Both are optional, both surface in different fields. No conflict.
VERIFY:
- Diff against pre-edit SKILL.md shows only Step 9 + Create-mode target addition +
`umbrella_id` field addition — no other body rewrites.
- Manual run-through with a fixture Task open simulating the post-edit skill flow.
- Skill body length stays within the existing 25-soft-ceiling discipline.
DO NOT REWRITE PROMOTE-MODE SEMANTICS. The ID-30 PR-A rewrite owns that.
DO NOT TOUCH TRIAGE-FINDING SKILL. That's ID-23's surface.

testStrategy: Manual dry-run of skill update by orchestrator opening a synthetic forward Task with umbrella_id: 'canonical-pipeline'; verifies (a) Task appears in task-list.json, (b) Task id appears in umbrellas.json canonical-pipeline.task_ids[], (c) single commit covers both edits, (d) bun run test -- umbrellas-roundtrip stays green.


Subtask 31.10 — Author MAX-ID cross-branch discipline section in workflow-orchestration skill

Section titled “Subtask 31.10 — Author MAX-ID cross-branch discipline section in workflow-orchestration skill”
  • id: 10
  • title: Append MAX-ID cross-branch discipline section to workflow-orchestration skill body
  • status: pending
  • dependencies: [] (orthogonal to schema work; can dispatch in parallel)
  • priority: should-have
  • effort_h: 0.5
  • file-ownership zone:
    • .claude/skills/workflow-orchestration/SKILL.md (edit — append new sub-section)

description (≤200 chars): Append “Task ID assignment: cross-branch MAX-ID discipline” sub-section to workflow-orchestration SKILL.md per PRODUCT inv 10. T-OQ-3 RATIFIED: defer CI guard.

details (load-bearing):

SCOPE: Append a new sub-section to `.claude/skills/workflow-orchestration/SKILL.md`
documenting the cross-branch MAX-ID discipline per PRODUCT invariant 10.
T-OQ-3 RATIFIED DEFAULT (from S65 W0): Defer cross-branch MAX-ID CI guard. The S62
W4 ID-28 rename (`9e498e2f`) is the only known collision to date; recovery pattern
is the worked example.
NEW SUB-SECTION CONTENT:
```markdown
## Task ID assignment: cross-branch MAX-ID discipline (PRODUCT inv 10)
Before opening any NEW Task on any branch, the opening orchestrator MUST query the
maximum Task id across all active long-lived branches and assign
`MAX_ID_ACROSS_BRANCHES + 1`.
### Active branches at S65 (revise on each major branch-set change)
- `origin/main`
- `origin/production-readiness`
- `origin/content-items-investigation`
(Verify the active set at dispatch time — `git branch -r | grep origin` then filter
to long-lived. Drop ephemeral feature branches.)
### Discipline
```bash
# For each active branch B:
for B in main production-readiness content-items-investigation; do
git fetch origin "${B}" --quiet
raw=$(git show "origin/${B}:docs/reference/task-list.json")
max_id_B=$(echo "${raw}" | python3 -c "
import json, sys
d = json.load(sys.stdin)
print(max(int(t['id']) for t in d['tasks']))
")
echo "${B}: ${max_id_B}"
done
# MAX_ID_ACROSS_BRANCHES = max(max_id_B for each B)
# New Task id = MAX_ID_ACROSS_BRANCHES + 1

Collision recovery (worked example: S62 W4 ID-28 rename)

Section titled “Collision recovery (worked example: S62 W4 ID-28 rename)”

If post-merge a collision is detected (two branches independently used the same id), rename the later-merged Task:

  1. Identify the renamed Task (typically the later merge).
  2. Single commit with message of shape: chore(s{NN}-w{N}): rename ID-{old} → ID-{new} (cross-branch collision resolve)
  3. The commit spans:
    • task-list.json (Task id update + any internal dependencies[] references)
    • umbrellas.json task_ids[] (if the Task was in any umbrella)
    • All cross_doc_links pointing at the old id (grep -rl "ID-{old}" docs/ covers most surfaces)
  4. Worked example: S62 W4 commit 9e498e2f resolved ID-28 collision (production- readiness vs content-items-investigation) by renaming p-r’s ID-28 to ID-33.

No CI guard (per OQ-5 + T-OQ-3 ratification)

Section titled “No CI guard (per OQ-5 + T-OQ-3 ratification)”

This discipline is human-orchestrator-only. No CI guard exists at S65. If a second collision occurs within 6 months of S65, re-engage T-OQ-3 with a concrete CI guard proposal (likely a workflow_run job querying gh api repos/.../contents/... across branches).

PLACEMENT: Append this sub-section at the end of the existing SKILL.md body OR within
the most appropriate existing section (locate where Task-opening / Task-creation is
already discussed; insert under that heading). Use the existing section structure for
placement — do not introduce a new top-level structure.
VERIFY:
- Diff against pre-edit SKILL.md shows only the appended sub-section, no other body
rewrites.
- New section reachable from the SKILL.md TOC (if a TOC exists; otherwise just
cross-referenced from the orchestrator's existing dispatch checklist).
- ESLint markdown link checks pass (`bun run lint` if applicable).
DO NOT TOUCH ANY OTHER SKILL BODY IN THIS SUBTASK. This is workflow-orchestration
only.

testStrategy: Manual eye on the diff — section appended exactly once, content matches PRODUCT inv 10 verbatim. Verify worked example commit SHA 9e498e2f resolves correctly via git show 9e498e2f --stat (the commit exists in p-r history per WP0 doc).


Subtask 31.11 — Smoke test gate + integration verification

Section titled “Subtask 31.11 — Smoke test gate + integration verification”
  • id: 11
  • title: Run smoke test gate covering schema, helper, and round-trip tests end-to-end
  • status: pending
  • dependencies: [5, 6, 7, 8, 9, 10] (consumes all six prior Subtasks)
  • priority: should-have
  • effort_h: 0.5
  • file-ownership zone:
    • (no new files — verification-only Subtask; final commit polish)

description (≤200 chars): Run end-to-end smoke test gate per TECH §6.2 covering schema + helper + round-trip + skill extension. Verify Wave 2 close-out criteria for ID-31 §3.

details (load-bearing):

SCOPE: Final-verification Subtask. No new code or tests; verify all prior Subtasks
land cleanly and the system is in a state ready for Wave 3 retro opens (separate
orchestrator dispatch, NOT part of this Task).
SMOKE-TEST GATE (verbatim from TECH §6.2):
```bash
bun run test -- umbrellas-schema umbrellas-helpers umbrellas-roundtrip umbrellas-task-list-roundtrip

ALL FOUR TEST FILES MUST BE GREEN (zero failures). This confirms the schema + helper + round-trip infrastructure is ready to receive Wave 3 retro-Task lands.

ADDITIONAL MANUAL VERIFICATION:

  1. cat docs/reference/umbrellas.json | jq '.umbrellas | length' returns 4 (1 canonical-pipeline + 3 stubs per 31.7).
  2. cat docs/reference/umbrellas.json | jq '.umbrellas[0].id' returns “canonical-pipeline”.
  3. cat docs/reference/umbrellas.json | jq '.umbrellas[0].substrate_doc' returns “docs/specs/id-31-canonical-pipeline-implementation-plan/PLAN.md”.
  4. File docs/specs/id-31-canonical-pipeline-implementation-plan/PRE-PHASE-REFERENCES.md exists and references all four canonical sources (mempalace + cocoindex-code + gitnexus + original docs).
  5. .claude/skills/update-roadmap-backlog/SKILL.md diff post-31.9 shows only the Step 9 + Create-mode target addition + umbrella_id field — no other rewrites.
  6. .claude/skills/workflow-orchestration/SKILL.md diff post-31.10 shows only the MAX-ID cross-branch discipline sub-section append.
  7. bun run test -- umbrellas-task-list-roundtrip emits the expected orphan-Task console.warn (every Task is currently orphan because canonical-pipeline.task_ids[] is empty — this is the expected steady-state at end-of-Wave-2).
  8. tsc --noEmit on the worktree — zero new type errors.
  9. bun run lint — zero new lint errors.

OPTIONAL ADVANCED VERIFICATION (defer if time-budget exhausted):

  • ts-morph references query on UmbrellasSchema confirms no unexpected callers (only the round-trip tests at this point).
  • Mempalace search “canonical-pipeline umbrella” returns relevant historical-context entries — confirms the PRE-PHASE-REFERENCES.md cross-references are reachable from the wing.

CLOSE-OUT COMMIT: If all gates green, this Subtask closes with a single conventional commit: feat(s65-wp1b-31.11): umbrellas surface ready for Wave 3 retro opens — smoke gate green Or, more typically, this Subtask’s verification IS its content — no code changes. The orchestrator promotes status to done and proceeds to Wave 3 dispatch.

WAVE 3 HANDOFF: At end of this Subtask, the infrastructure is READY for Wave 3 retrospective Task opens (T1-T6 — six per P-OQ-5 default, one commit per Task). Wave 3 is NOT part of this PLAN. The orchestrator dispatches retro opens separately, consuming formatRetrospectiveJournalBlock() (Subtask 31.6) at retro-open time and the extended update-roadmap-backlog Create mode (Subtask 31.9) for new-Task creation.

ESCALATION IF ANY GATE RED: If any smoke test fails:

  1. Pause Wave 3 dispatch.
  2. Identify the failing Subtask owner.
  3. Re-dispatch the failing Subtask with the error log as additional context.
  4. Re-run smoke gate.
**testStrategy:** Smoke gate `bun run test -- umbrellas-schema umbrellas-helpers
umbrellas-roundtrip umbrellas-task-list-roundtrip` runs green; manual eye verifies 9
listed checks pass.
---
## §3 Sibling-only dependency DAG (acyclic verification)
The seven Subtasks form a strict-DAG with only sibling-Subtask dependencies (no
cross-Task references). Visualised:
┌───────────── 31.5 (schema) ─────────────┐
│ ↓ │
│ 31.6 (helpers) │
│ ↓ │
│ │

31.10 (max-id) 31.7 (umbrellas.json) ─┐ │ │ ↓ │ │ │ 31.8 (round-trip) ─────┤ │ │ ↓ │ │ │ 31.9 (skill ext) ──────┤ │ │ │ │ └─────────────────► 31.11 (smoke gate) ◄──┘ (consumes all 6)

### 3.1 Dependency list (Subtask.dependencies[] integers)
| Subtask | Sibling deps | Rationale |
| --- | --- | --- |
| 31.5 | `[]` | Foundation — no deps. |
| 31.6 | `[5]` | Consumes `UmbrellaEntry` type from schema. |
| 31.7 | `[5]` | Consumes schema for parse-validation. |
| 31.8 | `[5, 7]` | Consumes schema + data file. |
| 31.9 | `[5, 7]` | Consumes schema (for skill body imports) + initial data file. |
| 31.10 | `[]` | Orthogonal — workflow-orchestration skill edit independent of schema. |
| 31.11 | `[5, 6, 7, 8, 9, 10]` | Smoke gate consumes everything. |
### 3.2 Sibling-only verification
Every dependency listed above is an integer in range `[5, 11]` — local to Task 31.
No cross-Task Subtask references. Cross-Task ordering (e.g. "31.9 lands AFTER
ID-30 PR-A merges") is enforced at the **Wave level** in §4 below, NOT via Subtask
dependencies. The TaskSchema `.superRefine()` (lib/validation/task-list-schema.ts:132)
enforces sibling-only at parse-time.
### 3.3 Acyclicity verification
Topological order: 31.5 → 31.6 → 31.7 → 31.8 → 31.9 → 31.10 → 31.11. Parallel-eligible
pairs:
- 31.6 ∥ 31.7 (both depend only on 31.5; disjoint file zones — `umbrellas-helpers.ts`
vs `umbrellas.json`).
- 31.8 ∥ 31.9 (both depend on `[5, 7]`; disjoint file zones — test files vs skill
body).
- 31.10 ∥ {31.5..31.9} (no deps; touches only workflow-orchestration skill body).
No cycle exists. DAG verified acyclic.
---
## §4 Wave alignment
Per WP0 §6 sequencing (S65 cross-task dependency map), the seven Subtasks distribute
across Wave 2, Wave 3, and Wave 4 (or parallel-with-Wave-2 for the workflow-
orchestration edit).
### 4.1 Wave 2 (next session, ~S66) — Schema + helper foundation
- **31.5 (schema authoring)** — STRICTLY AFTER ID-30 PR-A schema additions merge
(OQ-C2 ratification). Both touch `lib/validation/`; do NOT co-land. The TECH §1.1
pattern read of `task-list-schema.ts` happens on the post-PR-A state. Pre-dispatch
check at orchestrator level: `git log --oneline origin/production-readiness --
lib/validation/backlog-schema.ts` must show PR-A's `rank` addition.
- **31.6 (helper authoring)** — depends on 31.5; lands in same wave.
- **31.10 (workflow-orchestration skill MAX-ID section)** — orthogonal; can dispatch
in parallel-with-Wave-2 (no file collisions, no schema deps).
### 4.2 Wave 3 (~S67) — Data backfill + skill extension + round-trip
- **31.7 (initial umbrellas.json + PRE-PHASE-REFERENCES.md)** — depends on 31.5.
- **31.8 (round-trip tests)** — depends on 31.5 + 31.7.
- **31.9 (update-roadmap-backlog skill extension)** — STRICTLY AFTER ID-30 PR-A
curator-skill rewrite merges (OQ-B1 ratification). This Subtask is a surgical
insert into the post-PR-A rewritten skill. Pre-dispatch check at orchestrator
level: `git log --oneline origin/production-readiness -- .claude/skills/update-
roadmap-backlog/SKILL.md` must show PR-A's Branch B/C semantic rewrite landed.
### 4.3 Wave 4 (or end-of-Wave-3) — Smoke gate
- **31.11 (smoke gate)** — depends on all six prior Subtasks. Closes the ID-31 §3
infrastructure scope. The orchestrator dispatches Wave 3 retrospective T1-T6 opens
AFTER this Subtask passes (per §1 — retro opens are NOT part of this PLAN).
### 4.4 Parallel-eligibility summary
Within Wave 2: 31.5 sequential → 31.6 (depends) — but 31.10 dispatches in parallel
to either (no schema dep). Within Wave 3: 31.7 → 31.8 sequential; 31.9 parallel to
31.8 (disjoint files — test files vs skill body — and same deps `[5, 7]`).
If Liam wants minimum wall-clock, the orchestrator can fan out 31.5+31.10 in
parallel Wave 2 (different file zones), then 31.6+31.7+31.9 fan-out in Wave 2.5,
then 31.8 + 31.11 sequentially close the wave. **But the brief's recommended
sequencing is Wave 2 + Wave 3 + Wave 4, conservatively staged.**
---
## §5 Cross-Task coordination
### 5.1 Strict-sequence ordering with ID-30 PR-A (OQ-B1 + OQ-C2)
Two Subtasks in this PLAN strict-sequence after ID-30 PR-A:
| Subtask | ID-30 dependency | Why |
| --- | --- | --- |
| 31.5 (schema) | ID-30 PR-A schema additions merge first | Both touch `lib/validation/`; OQ-C2 ratified (S65 W0). |
| 31.9 (skill ext) | ID-30 PR-A curator-skill rewrite merges first | Surgical insert into rewritten Promote mode; OQ-B1 ratified (S65 W0). |
The orchestrator enforces this at dispatch level — NOT via Subtask sibling deps
(those stay clean). Pre-dispatch script:
```bash
# Before dispatching Subtask 31.5:
git fetch origin production-readiness --quiet
if ! git log --oneline origin/production-readiness -- lib/validation/backlog-schema.ts | grep -q "rank"; then
echo "BLOCKED: ID-30 PR-A schema additions not yet merged. Defer 31.5."
exit 1
fi

(The exact regex pattern adjusts based on ID-30’s actual commit message conventions at merge time. The orchestrator confirms by reading the post-merge schema file directly and asserting the new field is present.)

5.2 Forward-compat with ID-9 (Wave 7 downstream consumer)

Section titled “5.2 Forward-compat with ID-9 (Wave 7 downstream consumer)”

ID-9 (Astro docs site) is the downstream consumer of umbrellas.json per WP0 §5. The forward-compat constraint is field-name stability:

FieldLocked-atConsumer surface
idSubtask 31.5URL slug for Astro Initiative page (ID-9.11+)
titleSubtask 31.5Page title in Astro Initiative view
substrate_docSubtask 31.5”View substrate” link target
task_idsSubtask 31.5Membership list rendered as Task badges
statusSubtask 31.5Initiative status badge / sort key
phaseSubtask 31.5Phase grouping in Initiatives listing

ID-9 brief (Subtask 9.11/9.12) carries the forward-compat note: “umbrellas.json shape locked S65 Wave 2 — consume verbatim. Any field-name change requires coordinated edit to ID-31 schema + ID-9 narrative templates.”

T-OQ-5 RATIFIED: Defer field growth (display_order / description) until Astro renderer surfaces concrete needs. This means Wave 7 dispatch will determine whether schema growth is warranted; until then, the 6-field shape is canonical.

5.3 Coordination with ID-23 (code-intelligence skill amendments, Wave 5)

Section titled “5.3 Coordination with ID-23 (code-intelligence skill amendments, Wave 5)”

ID-23 will amend update-roadmap-backlog SKILL.md (Inv 8 caller-count pre-grep) and other skill bodies in Wave 5 — AFTER Wave 3 closes. Per WP0 §3 crossover row 5 + OQ-B1: ID-23 amendments are “surgical insert into already-rewritten skill bodies”. The Subtask 31.9 surgical insert lands BEFORE ID-23 touches the same file.

No direct coupling between this PLAN’s Subtasks and ID-23 Subtasks. The ordering is managed at the Orchestrator’s Wave-level dispatch.

5.4 Coordination with ID-32 (CMUX-track codemod)

Section titled “5.4 Coordination with ID-32 (CMUX-track codemod)”

ID-32 declares dependencies: ["31"] as an informational soft dep. No file overlap; no schema overlap; no skill overlap. ID-32’s dependency on ID-31 is purely temporal (ID-32 references concepts that ID-31 establishes, not files). This PLAN does NOT need to coordinate with ID-32 implementation Subtasks at the Wave level.

5.5 No cross-Task Subtask dependencies expressed

Section titled “5.5 No cross-Task Subtask dependencies expressed”

Sibling-only verified per §3.2. All cross-Task ordering lives at the Wave / dispatch level per §4 and §5.1. The sibling-only constraint stays clean.


§6 Ratifications absorbed + P-OQ-4 A2 EXPANDED narrative

Section titled “§6 Ratifications absorbed + P-OQ-4 A2 EXPANDED narrative”

6.1 Ratifications summary (S65 W0 absorptions)

Section titled “6.1 Ratifications summary (S65 W0 absorptions)”
SourceDecisionApplied in
PRODUCT P-OQ-1 RATIFIED ALTT0 umbrella retro (canonical-pipeline)Subtask 31.7 (initial umbrellas.json)
PRODUCT P-OQ-4 RATIFIED A2 EXPANDEDT0 NOT a distinct Task; substrate_doc body references mempalace + cocoindex-code + gitnexus + original docsSubtask 31.7 (PRE-PHASE-REFERENCES.md) + this PLAN’s scope (no T0 Task in decomposition)
TECH T-OQ-1 RATIFIED DEFAULTHelper at lib/validation/umbrellas-helpers.tsSubtask 31.6
TECH T-OQ-2 RATIFIED DEFAULTExtend update-roadmap-backlog Create mode + shared umbrella_id fieldSubtask 31.9
TECH T-OQ-3 RATIFIED DEFAULTDefer cross-branch MAX-ID CI guardSubtask 31.10 (documents discipline, no CI guard)
TECH T-OQ-4 RATIFIED DEFAULTNo test fixture sharingSubtask 31.8 (per-test re-read accepted)
TECH T-OQ-5 RATIFIED DEFAULTDefer UmbrellaEntrySchema field growthSubtask 31.5 (6-field shape locked at authoring)
WP0 OQ-B1 RATIFIED B1ID-30 PR-A curator-skill rewrite lands first; ID-31 §6.4 lands afterSubtask 31.9 (Wave 3 strict-sequence)
WP0 OQ-C2 RATIFIED C2Strict-sequence ID-30 PR-A → ID-31 §3 (NOT co-land)Subtask 31.5 (Wave 2 strict-sequence)
Forward-compat with ID-9Field names locked at Wave 2 mergeSubtask 31.5 (load-bearing locked names: id/title/substrate_doc/task_ids/status/phase)

6.2 P-OQ-4 A2 EXPANDED — load-bearing narrative

Section titled “6.2 P-OQ-4 A2 EXPANDED — load-bearing narrative”

This is the most important ratification to surface explicitly because it materially changes the original PRODUCT.md / TECH.md decomposition. PRODUCT.md (drafted before A2 EXPANDED was ratified) prescribed T0 as a distinct retrospective Task with 4-8 Subtasks per shipping-cadence granularity. TECH.md §6 row 31.10 baked that assumption into the Subtask outline as “Open retrospective Tasks T0-T6 (7 commits per P-OQ-5 default)”. A2 EXPANDED (S65 W0) supersedes both.

A2 EXPANDED rule (verbatim from S65 session-start ratifications):

T0 is NOT a distinct Task. Umbrella substrate_doc body references mempalace + cocoindex-code + gitnexus + original documentation for historical context. Knowledge-graph cross-references preserve the pre-phase narrative. PLAN must NOT decompose into a “T0 retro Task” Subtask. The umbrella entry itself is the only artefact.

How this PLAN honours A2 EXPANDED:

  1. No T0 Subtask in this PLAN’s decomposition. The 7 Subtasks {31.5..31.11} cover schema + helper + initial umbrellas.json + skill extension + tests + smoke gate. None of them open T0 as a distinct Task. T0 simply does not exist as a Task in task-list.json.

  2. canonical-pipeline umbrella entry IS the artefact for T0. Subtask 31.7 authors the canonical-pipeline entry in umbrellas.json with substrate_doc: 'docs/specs/id-31-canonical-pipeline-implementation-plan/PLAN.md'. The umbrella entry’s task_ids[] later (Wave 3) grows to list T1-T6 retro Tasks + T8=ID-28 + JIT-opened forward Tasks. T0 NEVER appears in task_ids[].

  3. PRE-PHASE-REFERENCES.md carries the historical narrative. Subtask 31.7 authors a NEW small adjacent doc at docs/specs/id-31-canonical-pipeline-implementation-plan/PRE-PHASE-REFERENCES.md that lists the four canonical historical sources (mempalace wing, cocoindex-code corpus, GitNexus repo, original Phase 0.9 docs). This doc is the “knowledge-graph cross-references” surface — it points readers to the pre-phase work without duplicating content.

  4. PRODUCT.md non-goal “no edit of PLAN.md” is RESPECTED. PRE-PHASE-REFERENCES.md is a NEW adjacent file, NOT an edit of PLAN.md. PLAN.md stays canonical substrate (PRODUCT inv 13).

  5. PRODUCT Inv 1 (T0 retro umbrella Task) is SUPERSEDED, not deleted. The spec text in PRODUCT.md still describes T0 because PRODUCT.md was not retracted — but the ratification A2 EXPANDED supersedes the operational shape. This PLAN names the supersession explicitly so a future Checker doesn’t flag the missing T0 Task as a PRODUCT inv 1 violation. The Checker’s verification path:

    • PRODUCT Inv 1 (T0 retro Task exists in task-list.json): SUPERSEDED by A2 EXPANDED. No verification required. The canonical-pipeline umbrella entry + PRE-PHASE-REFERENCES.md is the operational equivalent.
    • PRODUCT Inv 7-9 (umbrellas.json shape + round-trip): VERIFIED by Subtasks 31.5, 31.7, 31.8.
    • PRODUCT Inv 10 (cross-branch MAX-ID discipline): VERIFIED by Subtask 31.10.
    • PRODUCT Inv 12 (retro Subtask journal block format): VERIFIED by Subtask 31.6 helper signature + unit test.
    • PRODUCT Inv 13-14 (cross_doc_links + manual backlinks): VERIFIED at Wave 3 retro opens (not this PLAN’s scope).
  6. This decision is LOAD-BEARING — do not invent T0 Subtasks; do not collapse umbrella into substrate; the umbrella + cross-references is the canonical pair. If a future maintainer reviewing this PLAN questions the absence of T0 in the decomposition, the answer is in §6.2 here — A2 EXPANDED ratified S65 W0.

6.3 The other 6 PRODUCT P-OQs — disposition

Section titled “6.3 The other 6 PRODUCT P-OQs — disposition”
P-OQDefaultDisposition in this PLAN
P-OQ-1canonical-pipeline + 4 stubs at first commitOVERRIDDEN by brief: canonical-pipeline + 3 stubs (prod-readiness, ux-platform, ai-platform). See §1.2.
P-OQ-2Zero memberships allowed; soft warning onlyHonoured by Subtask 31.8 round-trip test (orphans warn, don’t fail).
P-OQ-3commit_refs[] + journal block kept dualHonoured by Subtask 31.6 helper signature (commits[] input + future commit_refs[] field at retro-open).
P-OQ-4(default rejected) A2 EXPANDED appliedSee §6.2.
P-OQ-5One commit per retro TaskHonoured in WAVE 3 dispatch (NOT this PLAN — retro opens are out of scope).

RiskLikelihoodImpactMitigation
ID-30 PR-A doesn’t merge before Wave 2 dispatchMediumHighPer Subtask 31.5 + 31.9 dispatch checks (§5.1): orchestrator validates lib/validation/backlog-schema.ts shows PR-A’s rank addition before dispatching 31.5; validates .claude/skills/update-roadmap-backlog/SKILL.md shows PR-A’s Branch B/C rewrite before dispatching 31.9. If gate fails, defer to Wave 3.
Field-name drift between umbrellas-schema.ts and ID-9 narrative templates (Wave 7)LowHighSubtask 31.5 details locks the 6 field names verbatim with a “FORWARD-COMPAT CONSTRAINT (LOAD-BEARING)” warning. ID-9 brief 9.11/9.12 will reference this lock. T-OQ-5 ratified deferral prevents speculative additions.
PRE-PHASE-REFERENCES.md feels like scope creep on PLAN.mdLowLowThe doc is small (~30-50 lines), strictly references-only (no content duplication), and lives ADJACENT to PLAN.md (not an edit of it). Respects PRODUCT non-goal line 73-74. P-OQ-4 A2 EXPANDED narrative is the authority.
Wave 3 retro opens (T1-T6) get “lost” because they’re not in this PLANMediumMediumSubtask 31.11 close-out explicitly handoffs to Wave 3. The orchestrator’s WP0 sequencing doc + this PLAN’s §6.2 (A2 EXPANDED) explicitly carve Wave 3 as retro-open dispatch. The Wave 3 dispatch is a separate orchestrator action that consumes Subtask 31.6 (helper) and Subtask 31.9 (skill ext).
Subtask 31.10 (workflow-orchestration MAX-ID) feels unrelated to “umbrellas migration”LowLowIt’s grouped here because PRODUCT inv 10 prescribes the discipline as part of the migration’s invariant set. The skill body section is small (~30 lines append). Subtask is intentionally orthogonal (no schema dep) so it can parallel-dispatch with 31.5/31.6 without coupling.
tsc --noEmit finds unexpected type errors from BARE_ID_REGEX importLowLowThe import path @/lib/validation/schemas is verified to export BARE_ID_REGEX at lib/validation/schemas.ts:50. Subtask 31.5 details cite this verbatim.
Round-trip test orphan-warning noiseLowLowExpected steady-state at end of Wave 2: every Task is orphan because canonical-pipeline.task_ids[] is empty. The console.warn is informational only (P-OQ-2 default). Wave 3 retro opens populate task_ids[] and the warnings naturally diminish.
Mempalace wing name driftLowLowSubtask 31.7 details explicitly instruct the Executor to verify wing name via mempalace_list_wings before writing the PRE-PHASE-REFERENCES.md reference. Wing name drift is a known operational hazard (CLAUDE.md MemPalace section).

§8 Out-of-scope items (carry-forward to subsequent waves / Tasks)

Section titled “§8 Out-of-scope items (carry-forward to subsequent waves / Tasks)”
  • Wave 3 retro Task opens T1-T6. Six per-Task opens with shipping-cadence Subtasks + journal blocks via formatRetrospectiveJournalBlock(). Orchestrator dispatches separately AFTER this PLAN’s Subtasks close. Per P-OQ-5 default: one commit per Task.
  • Wave 3 forward-Task JIT opens (T7 + T9-T14). Each opens via full spec chain (RESEARCH → PRODUCT → TECH → PLAN → impl) at JIT trigger time. Per PRODUCT inv 6. Not this PLAN.
  • T8 = ID-28 anchor. Already in-flight on content-items-investigation per WP0 §2 ID-31 entry. ID-28’s task_ids[] entry in canonical-pipeline umbrella appends at Wave 3 (whenever T8 status reaches in_progress on the merged branch). Not this PLAN.
  • PRODUCT Inv 11 (shipping-cadence Subtask granularity at retro opens). Procedural discipline enforced at Wave 3 by the orchestrator. Not testable here.
  • PRODUCT Inv 13-14 (cross_doc_links + PLAN.md backlinks). Set at Wave 3 retro-open time via Subtask 31.9 skill extension (cross_doc_links populated by the orchestrator). PLAN.md backlinks remain optional per Inv 14.
  • Astro renderer for umbrellas.json (ID-9 follow-up). Wave 7. Per Non-goal in PRODUCT line 70.
  • CI guard for cross-branch MAX-ID. T-OQ-3 ratified deferral. Subtask 31.10 documents the discipline but does NOT add a CI guard.
  • UmbrellaEntrySchema field growth (display_order, description). T-OQ-5 ratified deferral. Re-evaluate when Astro renderer (Wave 7) surfaces concrete needs.

End of PLAN.md.

Ratification gate: orchestrator promotes Subtask 31.4 status in_progress → done, appends <info added on ...> journal block to 31.4 details, and appends Subtasks {31.5..31.11} records to Task 31’s subtasks[] array. Wave 2 dispatch may then begin AFTER ID-30 PR-A merges (per OQ-B1 + OQ-C2 strict-sequence).