Skip to content

Legacy ID Migration Mapping — Inventory + Proposal

Legacy ID Migration Mapping — Inventory + Proposal

Section titled “Legacy ID Migration Mapping — Inventory + Proposal”

Last verified: 20/05/2026 (kh-prod-readiness-S56, OQ-2 ratification — bare-digit storage format applied)

Context. Task ID-15 (docs/reference/task-list.json) ratifies a bulk migration of all legacy-format item identifiers across the three task surfaces to the canonical ID-N / ID-N.M shape per docs/plans/phase-0-investigation/s48-feedback.md §B2 (“ID-15 / ID-15.3 used consistently across task list, backlog, roadmap, and workflow prompts/docs”). This document is the Subtask ID-15.1 RESEARCH output: a full inventory of legacy IDs across the three surfaces + a proposed mapping table for Liam ratification at session close. Subtasks ID-15.2..5 (TECH design, script authoring, application + cross-doc sweep, script deletion) all carry the mapping decided here.

Cross-references.

  • docs/reference/task-list.json — Task ID-15 (parent), ID-15.1..5 (subtasks).
  • docs/plans/phase-0-investigation/s48-feedback.md §B2 — ratification of the ID-N canonical format requirement.
  • lib/validation/task-list-schema.tsTask.id regex ^\d+$ (strict; only string-of-digits accepted).
  • lib/validation/backlog-schema.tsBacklogItem.id z.string().min(1) (permits any non-empty string; PRODUCT inv 37 says existing IDs must not change without explicit migration — this Task is that migration).
  • lib/validation/roadmap-schema.tsRoadmapItem.id documented as “Dotted-decimal positional ID” (no legacy formats present; out of scope).

All inventory queries used jq against the three JSON surface files. Roadmap is inspected recursively because items live inside sections[].items[] and sub-section nesting may be present.

Terminal window
# Backlog — flat items[] array
jq -r '.items[].id' docs/reference/product-backlog.json | sort
# Task-list — Task array with subtasks[]; compound IDs derived in the script
jq -r '.tasks[].id' docs/reference/task-list.json | sort -n
jq -r '.tasks[] | .id as $tid | .subtasks[] | "\($tid).\(.id)"' \
docs/reference/task-list.json
# Roadmap — recursive walk; items may nest in sub-sections
jq -r '[.. | .items? // empty | .[] | select(type=="object") | .id] | unique | .[]' \
docs/reference/product-roadmap.json | sort -V
# Detect non-dotted-decimal IDs in roadmap (legacy-format check)
jq -r '[.. | .items? // empty | .[] | select(type=="object") | .id] | unique | .[]' \
docs/reference/product-roadmap.json \
| grep -v -E '^[0-9]+(\.[0-9]+)*$' || echo "(none — all dotted-decimal)"

Counts verified against jq '.items | length' (backlog), jq '.tasks | length' (task-list), jq '[.. | .items? // empty | .[] | select(type=="object")] | length' (roadmap items recursive).


§2.1 Backlog (docs/reference/product-backlog.json)

Section titled “§2.1 Backlog (docs/reference/product-backlog.json)”

Total items: 46. One already canonical (ID-17); 45 legacy.

FormatCountIDsNotes
AST-S{N}-O{M}7AST-S3-O1, AST-S3-O2, AST-S10-O1, AST-S10-O2, AST-S11-O1, AST-S11-O2, AST-S11-O3ast-dataflow follow-ons (one per session arc). Single tightly-coupled track.
C{N}-DT-* / C{N}-T*-* / C{N}-PA* / C{N}-Mobile-*16C1-DT-Login-1/-2, C1-DT-Settings-2, C1-T3-Settings-3, C2-DT-BidDetail-1/-2, C2-DT-Session-1/-2, C2-PA5, C2-T3-Session-1, C3-DT-Digest-1/-2/-3, C4-DT-Guide-1, C4-DT-ItemDetail-3, C8-Mobile-2Design critique audit outputs (per surfaced field). Cluster by track field (onboarding/authentication/bid-management/change-reporting/browse/mobile).
OPS-*17OPS-6, OPS-11, OPS-13, OPS-24, OPS-25, OPS-27, OPS-28, OPS-29, OPS-30, OPS-32, OPS-33, OPS-36, OPS-43.1, OPS-47, OPS-59 (main), OPS-62, OPS-63Operational tech-debt; standalone items historically. Note OPS-43.1 uses dot-suffix (S37 batch-5 follow-up — was a sub-item of OPS-43). Note OPS-59 (main) parenthetical disambiguator (cross-track conflict). Two paired items: OPS-28 declares dependencies: ["OPS-29"].
RLS-P{N}2RLS-P8, RLS-P9RLS-pattern audit follow-ups (P-prefix denotes “Phase”; audit source implementation-readiness-audit-s240.md).
Other3ENG-TAX-SIMPLIFY, EVAL-2, PL-3Singleton legacy prefixes. ENG-TAX-SIMPLIFY depends on P0-TX-OPTION-E (a SHIPPED reference no longer in backlog).
ID-N canonical1ID-17First entry to use the canonical format (S52 WP0 close — RSS auth design review).

Legacy total: 45 IDs. All 45 require migration.

§2.2 Task-list (docs/reference/task-list.json)

Section titled “§2.2 Task-list (docs/reference/task-list.json)”

Total Tasks: 8. Total Subtasks: 22. All IDs already canonical (Task.id matches ^\d+$; Subtask id is bare integer per schema).

Task IDTitleSubtasks
6workflow-orchestration skill body2 (6.1, 6.2)
7task-executor body rewrite + task-planner agent2 (7.1, 7.2)
8implement-subtask skill + spec-driven-implementation EDIT2 (8.1, 8.2)
9Astro+Starlight docs + Warp docubot port + decommission /update-docs4 (9.1, 9.2, 9.3, 9.4)
10start-session skill self-adaptation + diary shape3 (10.1, 10.2, 10.3)
15Bulk ID-N format migration (this Task)5 (15.1..15.5)
16ast-dataflow handover review + worktree closure3 (16.1, 16.2, 16.3)
18Author skill-routing-map.md1 (18.1)

Highest existing ID: 18. New IDs for backlog migration start at 19.

Task list is NOT in scope for this migration — it is already canonical.

§2.3 Roadmap (docs/reference/product-roadmap.json)

Section titled “§2.3 Roadmap (docs/reference/product-roadmap.json)”

Total sections: 16. Total items (recursive): 61. All item IDs match ^[0-9]+(\.[0-9]+)*$ (dotted-decimal positional, e.g. 1.4, 3.8, 11.19, 12.15.3).

Terminal window
jq -r '[.. | .items? // empty | .[] | select(type=="object") | .id] | unique | .[]' \
docs/reference/product-roadmap.json \
| grep -v -E '^[0-9]+(\.[0-9]+)*$'
# → (no output — all dotted-decimal)

Roadmap is NOT in scope for this migration — its IDs are positional (section-anchored), not legacy format codes. RoadmapItemSchema.id documents the dotted-decimal convention explicitly. Roadmap IDs would only change if a roadmap section restructure happens, which is independent of the legacy-ID migration.

SurfaceTotal IDsLegacy IDsCanonical IDsMigration in scope
Backlog46451YES — all 45
Task-list30 (8 Task + 22 Subtask)030No (already canonical)
Roadmap61 items + 16 sections0 (positional)77 (positional)No (positional, not legacy)
TOTAL legacy to migrate45

§3.1 Cluster-vs-standalone decision rules (see §4)

Section titled “§3.1 Cluster-vs-standalone decision rules (see §4)”

Items are grouped into clusters (contiguous ID-N blocks preserving semantic continuity) when:

  • They share a tight semantic theme AND were surfaced from the same source (e.g. the seven AST-S*-O* items are all ast-dataflow track follow-ons).
  • They share a track value AND would naturally be planned as a single initiative (e.g. the five onboarding-track C-cluster items map to a “First-Time-Admin Onboarding” initiative).
  • Liam’s mental model already treats them as a set (the two OPS-28/OPS-29 paired auth-allowlist items; the two RLS-P* items).

Items receive standalone IDs when:

  • They are isolated tech-debt (e.g. OPS-11 PK rename, OPS-13 batch-dedup RPC, OPS-63 quality-scan CHECK fix).
  • Their track overlaps with others but the work is independent (e.g. several bid-management-track C items are independent feature ideas, not a single initiative).
  • The item is a one-off (PL-3 portal automation PoC, EVAL-2 Jaccard-metric bug, ENG-TAX-SIMPLIFY taxonomy retirement).

§3.2 Proposed mapping table (45 legacy IDs → 21..65 targets, bare-digit per S56 OQ-2)

Section titled “§3.2 Proposed mapping table (45 legacy IDs → 21..65 targets, bare-digit per S56 OQ-2)”

Ratification status (S53 close + S56 revise):

  • S53 close (Liam Q4): 3/7 clusters YES (C1 ast-dataflow, C2 Onboarding, C3 Auth-allowlist); 4/7 REVISE (C4, C5, C6, C7) → resolved S56 (below).
  • S53 close (Liam OQ-2..OQ-8): all defaults accepted (shared pool, ID-17 as-is, always-rewrite sweep scope, OPS-43.1 lineage in notes, OPS-59 (main) drop parenthetical, BacklogItem.id schema tighten in ID-15.4, no inventory gaps — R-WP-S* confirmed out-of-scope).
  • S56 revise (Liam, per-cluster):
    • C4 Auth design — KEEP as cluster (ID-35..36).
    • C5 Bid-mgmt UX — SPLIT all four to standalone (no shared substrate per §4.3 tie-break).
    • C6 Change Reports — KEEP as cluster (ID-37..39) BUT rename rationale: “Digest” → “Change Reports” per CLAUDE.md gotcha (“user-facing label is Change Reports; internal code still uses digest”).
    • C7 RLS-audit — KEEP as cluster (ID-40..41). RLS-P8 stays spec_needed. RLS-P9 audit was completed in S243-era (Liam-confirmed S56, no issues found, findings not filed); ID-15.4 application step flips status: spec_needed → done with status_note recording the confirmation.
  • S56 informational: +2 shift from original ID-19..ID-63 to ID-21..ID-65 (forced by ID-19 + ID-20 occupying task-list since S53 + S55 closes; topology unchanged).

[live snapshot 2026-05-20T22:00:00.000Z]: AST-S3-O1 + AST-S3-O2 absent from live docs/reference/product-backlog.json at HEAD 3e4ee5c2 (closed separately per Liam, status not migrated). Post-migration backlog occupies bare-digit ids 17, 18, 23..65 per OQ-A non-compaction default (43 items, not 45). Drift handled in scripts/migrate-legacy-ids-to-id-n.ts runtime: legacy-format ids absent from inventory emit [WARN] log + populate skipped[] array. Mapping below reflects the original 45-item plan; the script + inventory at scripts/legacy-id-mapping.inventory.json reflect the 43-item live state. ID-15.3 deliverable per TECH §A.0 final paragraph.

[live snapshot ID-15.4 apply 2026-05-21]: Migration applied to docs/reference/product-backlog.json. RLS-P9 removed entirely (audit-confirmed-clean S243+S56, Liam-ratified S58 ID-15.4 — not worth tracking). Final post-migration occupancy: 17, 18, 23..40, 42..65 (44 items; slot 41 vacated — non-compaction per OQ-A). Cross-doc sweep applied across ALWAYS + BEST-EFFORT tiers: 55 files, 412 replacements, 0 misses. Schema tightened: BacklogItem.idz.string().regex(/^\d+$/). All bare-digit canonical.

Cluster 1 — ast-dataflow follow-ons (7 items → ID-21..ID-27). Tightly coupled (same track, sequential session arcs S3 / S10 / S11). Preserves semantic continuity: ID-21/22 = S3 outputs; ID-23/24 = S10 outputs; ID-25/26/27 = S11 outputs. Reads cleanly in task-list ordering.

LegacyProposedRationale
AST-S3-O121S3 follow-on (column-reads heuristic extension)
AST-S3-O222S3 follow-on (wildcard confidence tier)
AST-S10-O123S10 follow-on (type-evolution-check skill candidate)
AST-S10-O224S10 follow-on (enum-member-audit skill candidate)
AST-S11-O125S11 follow-on (OPS-T1 codemod impl, 16-24h)
AST-S11-O226S11 follow-on (MCP outputSchema full rollout, 29h)
AST-S11-O327S11 follow-on (OQ-R9 opaque-Json RPC migration, 7h)

Cluster 2 — Onboarding initiative (5 items → ID-28..ID-32). Track = onboarding. All surfaced from the design critique audit. Plausibly a single “First-Time-Admin + First-Session Onboarding” Task initiative when the work activates. Sequential block preserves Liam’s mental grouping.

LegacyProposedRationale
C1-T3-Settings-328”Getting Started” / Setup Checklist for first-time admins
C1-DT-Settings-229Progressive disclosure wizard for admin settings
C2-PA530First-session onboarding overlay for Bid Session
C2-T3-Session-131Onboarding overlay for first bid session (3-step prompt)
C4-DT-Guide-132”Getting Started” guide type for infrequent users

Cluster 3 — Auth allowlist paired items (2 items → ID-33..ID-34). Track = authentication. OPS-28 declares dependencies: ["OPS-29"] — explicit pair. Sequential block preserves dependency ordering and Liam’s stated “second-client onboarding” theme.

LegacyProposedRationale
OPS-2933Multi-client auth domain allowlist (table-driven). Comes first — dep target.
OPS-2834Admin-controlled user provisioning (invite-only). Depends on ID-33.

Cluster 4 — Authentication design items (2 items → ID-35..ID-36). Track = authentication. Both C1-DT-Login-* items surfaced from same audit; loose coupling (session-duration research + branding feature). S56-ratified KEEP (audit-lineage value outweighs split). Sequential block but note these are NOT functionally paired the way ID-33/34 are.

LegacyProposedRationale
C1-DT-Login-135Session duration vs security research
C1-DT-Login-236Organisation branding on login (multi-org)

Cluster 5 — SPLIT (S56-ratified). The four C2-DT-* bid-management items are independently shippable per §4.3 tie-break (“prefer standalone unless cluster genuinely tight”); cluster-framing was loose. All four move to the standalone block below (bid-management track, ID-54..ID-57).

Cluster 6 — Change Reports items (3 items → ID-37..ID-39). Track = change-reporting. Three C3-DT-Digest-* items from same audit; plausibly a single “Change Reports evolution” Task when activated. Sequential block preserves source ordering. Terminology fix per S56 revise — user-facing label is “Change Reports” (per CLAUDE.md gotcha); legacy item ID strings still contain “Digest” because that is the historical audit code, but rationale strings + post-migration backlog description field MUST use “Change Reports”.

LegacyProposedRationale
C3-DT-Digest-137Change Reports comparison view (side-by-side)
C3-DT-Digest-238Change Reports as governance artefact (immutable records)
C3-DT-Digest-339Change Reports distribution list

Cluster 7 — RLS-pattern audit follow-ups (2 items → ID-40..ID-41). Track = database. Both from implementation-readiness-audit-s240.md (S53 carry-in). Independent items but same audit source; sequential block preserves audit lineage. S56-ratified KEEP cluster. RLS-P9 carries a status flip per S56 (audit completed — see status_note column).

LegacyProposedRationalePost-migration status
RLS-P840RLS auto-enable trigger gaps (LIKE / PARTITION OF)spec_needed (unchanged)
RLS-P941Retroactive RLS audit for pre-migration tablesdone (S243-era audit completed, no issues found — Liam-confirmed S56; ID-15.4 applies the status_note)

Standalone items (24 items → ID-42..ID-65). No tight cluster; ordering within this block is largely arbitrary. Proposed order groups by track for readability (database, ai-integration, bid-management, browse, mobile, ingestion, cloud-run, documentation, testing). Now includes the 4 items from the split C5 (bid-management track expands 1 → 5).

LegacyProposedTrackRationale
OPS-642databaseDB-layer empty-string coercion for classification
OPS-1143databasecontent_item_workspaces PK constraint rename
OPS-1344databaseEP6 batch dedup RPC latency measurement (blocked)
OPS-43.145databaseRemaining SECDEF→INVOKER flips (35/39 shipped; 4 remain)
OPS-6346databaserun_quality_scan CHECK constraint bug
EVAL-247ai-integrationcompare-quality.ts Jaccard metric net-gain handling
OPS-2448ai-integrationMCP get_certification_status holder coverage tests
OPS-2749ai-integrationMarketing-persona H2 enhancements for daily-briefing
OPS-3050ai-integrationClassifier tool-schema hygiene (strict: true)
OPS-3351ai-integrationPlugin endpoint parameterisation
ENG-TAX-SIMPLIFY52ai-integrationRetire embedded taxonomy in plugin SKILL.md
PL-353bid-managementPortal automation PoC (re-scoped — Claude Cowork)
C2-DT-Session-154bid-managementSplit-screen vs single-pane on mobile (research) — from split C5
C2-DT-Session-255bid-managementRegeneration instruction templates — from split C5
C2-DT-BidDetail-156bid-managementBid overview as morning briefing — from split C5
C2-DT-BidDetail-257bid-managementQuestion-level routing from Overview — from split C5
C4-DT-ItemDetail-358browseItem detail as shareable report (“Share” / “Export to PDF”)
OPS-2559browseCert holder dropdown UX placeholder
C8-Mobile-260mobileEvaluate bottom-sheet navigator for mobile bid sessions
OPS-4761ingestionEP3 UI Pattern E retrofit
OPS-59 (main)62ingestion/admin/imports dedicated UI surface
OPS-6263cloud-runCloud Run buildpack equivalent of Vercel build cache
OPS-3664documentationdocs/operations/ inventory §2.5 full refresh
OPS-3265testingWP7 AC4c-B integration test empty-title brittleness flag

Final tally. 45 legacy IDs → 21..65 (45 contiguous new IDs) per original plan. Post-apply actual: 42 legacy IDs migrated (AST-S3-O1/O2 absent — §A.0 drift; RLS-P9 removed S58 ID-15.4 Liam-ratified). Combined with existing ID-17 + ID-18 (both now bare-digit 17 + 18 after prefix strip), the post-migration backlog occupies 17, 18, 23..40, 42..65 (44 items; slot 41 vacated).

17, 18, 23..40, 42..65 form a near-contiguous block (gaps at 19/20/21/22/41 — task-list Tasks at 19/20, absent AST-S3 slots at 21/22, vacated RLS-P9 slot at 41). The shared integer pool with task-list per s48-feedback B2 is ratified (Liam S53 OQ-2).

Per-cluster shift summary (S56 revise outcomes):

ClusterPre-S56 IDsPost-S56 IDsS56 outcome
C1 ast-dataflowID-19..2521..27+2 shift
C2 OnboardingID-26..3028..32+2 shift
C3 Auth allowlistID-31..3233..34+2 shift
C4 Auth designID-33..3435..36+2 shift, KEEP cluster
C5 Bid-mgmt UXID-35..38(vacated)SPLIT → standalone bid-management
C6 Change ReportsID-39..4137..39renumber (-4 after C5 vacate), KEEP, terminology fix
C7 RLS auditID-42..4340..41renumber (-4), KEEP, RLS-P9 status → done
StandaloneID-44..6342..65renumber +C5 additions (20 → 24 items)

§3.3 — S56 OQ-2 ratification — bare-digit storage format

Section titled “§3.3 — S56 OQ-2 ratification — bare-digit storage format”

S56 ratification (Liam, post-15.6 RESEARCH): BacklogItem.id aligns DOWN to bare digit. Targets in §3.2 are the bare-digit literal strings the migration script writes to product-backlog.json. The “ID-N” prefix remains a PROSE convention only (CLAUDE.md references, agent briefs, journal blocks, this research doc’s cluster headers).

Schema impact (lands in Phase A 15.4 apply step):

  • BacklogItem.id tightens from z.string().min(1) to z.string().regex(/^\d+$/) (matching Task.id schema in lib/validation/task-list-schema.ts).
  • Shared constant target: BARE_ID_REGEX = /^\d+$/ exported from lib/validation/schemas.ts (per ID-15.6 research §7.7); both Task.id and BacklogItem.id import.

Roadmap unaffected — positional dotted-decimal (1.3, 9.15.2) preserved per OQ-3 ratification.

Cross-doc sweep impact: the sweep regex set in ID-15.2 TECH spec (Phase A re-dispatch pending) rewrites legacy ID matches to bare-digit targets, not ID-N prefixed. Prose “ID-N” references in code/docs OUTSIDE backlog data stay as-is (prose convention).

Why not ID-N prefix everywhere: Task.id has been bare-digit canonical since task-list inception; rewriting "15""ID-15" across 10 existing Tasks + dependencies + downstream 20.1 mirror generator would expand scope without semantic benefit. Aligning backlog DOWN preserves the canonical surface unchanged.


§4 — Decision rules (cluster vs standalone)

Section titled “§4 — Decision rules (cluster vs standalone)”

The rules below should guide both this initial migration AND future additions to the backlog so the same heuristic stays applied.

§4.1 Cluster (sequential ID-N block) when ANY of:

Section titled “§4.1 Cluster (sequential ID-N block) when ANY of:”
  1. Shared track + shared surface source. Items with the same track field AND surfaced from the same audit / session arc (e.g. five onboarding-track C items all from the design critique audit, seven ast-dataflow-tooling items all from sequential ast-dataflow sessions).
  2. Declared dependency pairing. Items where one declares the other as a dependencies[] entry (e.g. OPS-28OPS-29). Sequential IDs in dependency order improve readability.
  3. Theme-driven initiative. Items that would plausibly be planned as a single initiative Task when activated (e.g. three change-reporting digest-evolution items; two RLS audit follow-ups).
  1. Item is functionally independent of every other backlog entry.
  2. Item’s track value is shared with others but only loosely (no shared surface source, no dependency pairing, no initiative grouping).
  3. Item could conceivably ship on its own with no coordination.

When an item could plausibly belong to a cluster OR be standalone, prefer standalone unless the cluster is genuinely tight. Loose clustering produces sequential IDs that fragment when items are activated independently (one cluster member promoted to a Task while siblings remain backlog), creating non-contiguous gaps that confuse the mental model. Tight clusters survive fragmentation because the relationship is doc-recorded (notes field) and the sequential numbering is a soft hint, not a hard contract.

  • Dependency order first (dep target = lower ID).
  • Then session arc / surfaced date (earliest first).
  • Then source-ordering within the audit (preserves audit narrative).

This decision rule applies to the backlog only. Task-list IDs are auto-assigned by the schema (string-of-digits, no semantic content), and roadmap IDs are dotted-decimal positional (anchored to section structure, not work themes).


§5 — Open questions for Liam ratification

Section titled “§5 — Open questions for Liam ratification”

The following decisions need explicit YES / NO / REVISE from Liam at session close before ID-15.2 (TECH design) dispatches.

OQ-1. Cluster groupings (per-cluster YES/NO/REVISE)

Section titled “OQ-1. Cluster groupings (per-cluster YES/NO/REVISE)”

Confirm each of the seven proposed clusters preserves semantic continuity in a way that matches your mental model:

  • Cluster 1AST-S*-O*ID-19..ID-25 (seven items, contiguous block, ordered by session arc S3 / S10 / S11). YES / NO / REVISE?
  • Cluster 2 — Onboarding (C1-T3-Settings-3, C1-DT-Settings-2, C2-PA5, C2-T3-Session-1, C4-DT-Guide-1) → ID-26..ID-30. YES / NO / REVISE?
  • Cluster 3 — Auth allowlist pair (OPS-29, OPS-28) → ID-31..ID-32 (ordered by dep target first). YES / NO / REVISE?
  • Cluster 4 — Auth design (C1-DT-Login-1, C1-DT-Login-2) → ID-33..ID-34. Loose coupling — Cluster or standalone? YES / NO / REVISE?
  • Cluster 5 — Bid-management UX (C2-DT-Session-1, C2-DT-Session-2, C2-DT-BidDetail-1, C2-DT-BidDetail-2) → ID-35..ID-38. Loose coupling — Cluster or standalone? YES / NO / REVISE?
  • Cluster 6 — Digest evolution (C3-DT-Digest-1/-2/-3) → ID-39..ID-41. YES / NO / REVISE?
  • Cluster 7 — RLS audit follow-ups (RLS-P8, RLS-P9) → ID-42..ID-43. YES / NO / REVISE?

OQ-2. Shared ID-N integer pool across task-list + backlog?

Section titled “OQ-2. Shared ID-N integer pool across task-list + backlog?”

s48-feedback.md §B2 calls for “ID-15 / ID-15.3 used consistently across task list, backlog, roadmap” but doesn’t explicitly say whether task-list Tasks and backlog items share a single integer pool (the proposal here) or whether the backlog restarts its own counter.

The proposal here ASSUMES a shared pool — backlog items become ID-19..ID-63 continuing from task-list’s highest ID-18. Pro: zero collision risk; backlog graduation to Task is a status-flip, not an ID change. Con: visually mixes task-list Tasks (high-engagement) with backlog parked items (low-engagement) in the same integer space.

Alternative: separate counters (backlog gets its own B1, B2, … or BL-1, BL-2, …). Pro: clean namespace separation. Con: graduation requires renaming the item; defeats the purpose of unified ID-N.

Liam to ratify. Shared pool (default) / separate counters / something else?

OQ-3. Should canonical ID-17 be renumbered?

Section titled “OQ-3. Should canonical ID-17 be renumbered?”

ID-17 (RSS auth design review) was added S52 WP0 as the first canonical-format backlog item. Under the shared-pool model (OQ-2 = yes), it sits at ID-17 between task-list ID-16 (closed) and task-list ID-18 (pending). It does NOT collide with anything, but its position in the integer sequence is anomalous (no Task ID-17 exists).

Options:

  • (a) Leave as-is — ID-17 continues to refer to the existing backlog item. No migration cost. Slight visual oddity in task-list ordering (ID-16ID-18 skips 17 in Tasks).
  • (b) Renumber ID-17 to ID-64 (after the migration block) — restores visual contiguity in task-list but adds one more renumber to the migration script.

Default proposal: (a) leave as-is. Minimal migration cost. The “skip” is trivial — the canonical convention doesn’t require ID-N to be densely packed.

The ID-15.2 TECH spec will design the cross-doc reference sweep. Confirm the always-rewrite scope per the migrate-roadmap-section-3.ts precedent (Liam to confirm wholesale acceptance, or specify exceptions):

  • Always-rewrite (live code + tracked refs): lib/, app/, __tests__/, scripts/, .claude/agents/, .claude/skills/, docs/reference/, docs/runbooks/, docs/operations/.
  • Best-effort (historical): docs/continuation-prompts/, docs/plans/, docs/audits/, docs/specs/ (legacy spec refs may be intentional historical record), .planning/.archive/ (point-in-time snapshots).
  • Never-rewrite (verbatim historical): Anything inside .planning/.archive/.* (treated as snapshot).

YES / NO / REVISE?

OPS-43.1 (the only legacy ID with a sub-decimal suffix) maps to flat ID-47 in the proposal — the sub-decimal semantic (“a follow-up to OPS-43, which is SHIPPED and removed from backlog”) is preserved in the notes field but disappears from the ID. Acceptable, or do you want a footnote / status_note mechanism to flag the lineage?

YES (acceptable) / NO (revise) / ADD-ANNOTATION?

OQ-6. Handling of OPS-59 (main) parenthetical disambiguator

Section titled “OQ-6. Handling of OPS-59 (main) parenthetical disambiguator”

OPS-59 (main) is the only ID with a parenthetical. The parenthetical disambiguates from cross-track conflicts during the S226 era. Post-migration the ID is just ID-60 — the (main) suffix has no further meaning. Confirm this can be dropped silently (no need for note field annotation).

YES (drop silently) / NO (note in notes field)?

OQ-7. Schema constraint update (post-migration)

Section titled “OQ-7. Schema constraint update (post-migration)”

Once migration applies and all backlog IDs match ^ID-\d+$, should BacklogItem.id schema in lib/validation/backlog-schema.ts tighten from z.string().min(1) to z.string().regex(/^ID-\d+$/)? This would block future non-canonical IDs at the schema layer (forcing function for ongoing discipline).

Pro: enforces canonical convention going forward. Con: locks in the format choice; any future namespace-separation (OQ-2 revisit) would require schema loosening.

Default proposal: YES — tighten schema in ID-15.4 (apply migration) commit.

OQ-8. Are there legacy IDs in scope that this inventory missed?

Section titled “OQ-8. Are there legacy IDs in scope that this inventory missed?”

The Task description (ID-15) lists these legacy formats:

  • OPS-* ✓ (17 found)
  • AST-S{N}-O{M} ✓ (7 found)
  • C{N}-T{M}-* / C{N}-DT-* / C{N}-PA{N} ✓ (16 found, includes C8-Mobile-2)
  • R-WP-S{N}-{X}NONE FOUND in any surface. This format appears in task-list commit_refs and session_refs (e.g. “R-WP-S11-D” referring to cross-track work-package merge commits) but does NOT appear as an item id anywhere. Confirm this format is out-of-scope for item-ID migration (it’s a commit/session label, not an item ID).
  • RLS-P{N} ✓ (2 found)
  • “Plus anything else” — surfaced: ENG-TAX-SIMPLIFY, EVAL-2, PL-3 (3 found singletons).

Anything Liam knows about that this inventory missed? Strongly recommend final review of the jq output in §1 before script authoring.


For reproducibility (and so the migration script’s input can be cross-checked against this snapshot):

Terminal window
# Verified 20/05/2026 against production-readiness HEAD ecc7ae31
# All three commands run from main repo root.
$ jq -r '.items[].id' docs/reference/product-backlog.json | wc -l
46
$ jq -r '.tasks | length' docs/reference/task-list.json
8
$ jq -r '[.tasks[].subtasks | length] | add' docs/reference/task-list.json
22
$ jq -r '[.. | .items? // empty | .[] | select(type=="object")] | length' \
docs/reference/product-roadmap.json
61
$ jq -r '.sections | length' docs/reference/product-roadmap.json
16

End of ID-15.1 RESEARCH output. Ratification gate at session close; ID-15.2 TECH dispatch is gated on Liam’s responses to OQ-1..OQ-8 above.