rcf-lite 0.28.4 → 0.29.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (168) hide show
  1. package/CHANGELOG.md +107 -1
  2. package/bin/rcf.js +4 -0
  3. package/fixtures/canary-manifest.json +9 -9
  4. package/guidance/define-draft-shapes.md +89 -0
  5. package/guidance/define-intake.md +97 -0
  6. package/guidance/define-intent.md +107 -0
  7. package/guidance/discover-prototype.md +67 -0
  8. package/guidance/discovery-prototypes.md +69 -0
  9. package/guidance/harness-template.md +34 -0
  10. package/guidance/managed/agent-instructions-block.hash +1 -1
  11. package/guidance/managed/agent-instructions-block.md +34 -0
  12. package/guidance/manifest.json +9 -2
  13. package/package.json +1 -1
  14. package/rcf/adrs/adr-4124-define-freeze-verb.json +30 -0
  15. package/rcf/adrs/adr-4126-persona-tagged-blockers-two-levels.json +40 -0
  16. package/rcf/adrs/adr-4127-readiness-tab-order-and-register.json +40 -0
  17. package/rcf/adrs/adr-4129-questions-harness-driven-loop.json +25 -0
  18. package/rcf/adrs/adr-4130-intake-harness-split-tool-scanned.json +20 -0
  19. package/rcf/adrs/adr-4132-prototypes-in-discovery-as-evidence.json +20 -0
  20. package/rcf/adrs/adr-4133-dag-dependency-depth-layout.json +40 -0
  21. package/rcf/adrs/adr-4134-index-json-route.json +35 -0
  22. package/rcf/adrs/adr-4135-readiness-po-register-and-adapter.json +35 -0
  23. package/rcf/adrs/adr-4136-embedding-host-fixture.json +35 -0
  24. package/rcf/code-nodes/cn-725.json +18 -2
  25. package/rcf/code-nodes/cn-726.json +10 -2
  26. package/rcf/code-nodes/cn-727.json +13 -4
  27. package/rcf/code-nodes/cn-728.json +18 -2
  28. package/rcf/code-nodes/cn-729.json +10 -2
  29. package/rcf/code-nodes/cn-730.json +13 -3
  30. package/rcf/code-nodes/cn-731.json +20 -0
  31. package/rcf/code-nodes/cn-732.json +14 -0
  32. package/rcf/code-nodes/cn-733.json +14 -0
  33. package/rcf/code-nodes/cn-734.json +14 -0
  34. package/rcf/code-nodes/cn-735.json +20 -0
  35. package/rcf/code-nodes/cn-736.json +14 -0
  36. package/rcf/code-nodes/cn-737.json +14 -0
  37. package/rcf/code-nodes/cn-738.json +14 -0
  38. package/rcf/code-nodes/cn-739.json +18 -0
  39. package/rcf/code-nodes/cn-740.json +19 -0
  40. package/rcf/code-nodes/cn-741.json +16 -0
  41. package/rcf/code-nodes/cn-742.json +16 -0
  42. package/rcf/code-nodes/cn-743.json +15 -0
  43. package/rcf/code-nodes/cn-744.json +22 -0
  44. package/rcf/code-nodes/cn-745.json +16 -0
  45. package/rcf/code-nodes/cn-746.json +14 -0
  46. package/rcf/code-nodes/cn-747.json +18 -0
  47. package/rcf/code-nodes/cn-748.json +16 -0
  48. package/rcf/code-nodes/cn-749.json +16 -0
  49. package/rcf/code-nodes/cn-750.json +15 -0
  50. package/rcf/code-nodes/cn-751.json +18 -0
  51. package/rcf/code-nodes/cn-752.json +14 -0
  52. package/rcf/fbs/fbs-196.json +13 -5
  53. package/rcf/fbs/fbs-198.json +42 -0
  54. package/rcf/fbs/fbs-199.json +59 -0
  55. package/rcf/fbs/fbs-200.json +46 -0
  56. package/rcf/fbs/fbs-201.json +49 -0
  57. package/rcf/fbs/fbs-202.json +110 -0
  58. package/rcf/fbs/fbs-203.json +100 -0
  59. package/rcf/requirements/req-002.json +2 -2
  60. package/rcf/requirements/req-173.json +2 -2
  61. package/rcf/requirements/req-174.json +10 -4
  62. package/rcf/requirements/req-175.json +10 -4
  63. package/rcf/requirements/req-176.json +25 -0
  64. package/rcf/requirements/req-180.json +31 -0
  65. package/rcf/requirements/req-181.json +31 -0
  66. package/rcf/requirements/req-182.json +25 -0
  67. package/rcf/requirements/req-186.json +25 -0
  68. package/rcf/requirements/req-187.json +31 -0
  69. package/rcf/requirements/req-188.json +25 -0
  70. package/rcf/tacs/tac-4121-define-ledgers.json +15 -3
  71. package/rcf/tacs/tac-4122-define-gates.json +40 -4
  72. package/rcf/tacs/tac-4123-define-readiness.json +39 -3
  73. package/rcf/tacs/tac-4124-define-freeze.json +28 -0
  74. package/rcf/tacs/tac-4127-readiness-view.json +49 -0
  75. package/rcf/tacs/tac-4128-define-guidance.json +53 -0
  76. package/rcf/tacs/tac-4129-define-questions.json +45 -0
  77. package/rcf/tacs/tac-4130-define-intake-brief.json +35 -0
  78. package/rcf/tacs/tac-4131-build-dag-view.json +39 -0
  79. package/rcf/tacs/tac-4132-id-lookup.json +42 -0
  80. package/rcf/tacs/tac-4133-readiness-po-layer.json +37 -0
  81. package/rcf/tacs/tac-4134-wespa-host-fixture.json +54 -0
  82. package/rcf/test-suites/ts-016.json +3 -3
  83. package/rcf/test-suites/ts-215.json +148 -4
  84. package/rcf/test-suites/ts-216.json +19 -3
  85. package/rcf/test-suites/ts-218.json +78 -0
  86. package/rcf/test-suites/ts-219.json +70 -0
  87. package/rcf/test-suites/ts-220.json +78 -0
  88. package/rcf/test-suites/ts-221.json +78 -0
  89. package/rcf/test-suites/ts-222.json +100 -0
  90. package/rcf/test-suites/ts-223.json +94 -0
  91. package/rcf/test-suites/ts-224.json +70 -0
  92. package/rcf/test-suites/ts-225.json +78 -0
  93. package/rcf/test-suites/ts-226.json +158 -0
  94. package/rcf/test-suites/ts-227.json +38 -0
  95. package/rcf/test-suites/ts-228.json +86 -0
  96. package/rcf/test-suites/ts-229.json +83 -0
  97. package/rcf/user-stories/us-17302.json +50 -0
  98. package/rcf/user-stories/us-17401.json +14 -2
  99. package/rcf/user-stories/us-17402.json +55 -0
  100. package/rcf/user-stories/us-17403.json +60 -0
  101. package/rcf/user-stories/us-17502.json +60 -0
  102. package/rcf/user-stories/us-17503.json +65 -0
  103. package/rcf/user-stories/us-17601.json +58 -0
  104. package/rcf/user-stories/us-18001.json +55 -0
  105. package/rcf/user-stories/us-18002.json +35 -0
  106. package/rcf/user-stories/us-18101.json +35 -0
  107. package/rcf/user-stories/us-18202.json +40 -0
  108. package/rcf/user-stories/us-18601.json +55 -0
  109. package/rcf/user-stories/us-18602.json +50 -0
  110. package/rcf/user-stories/us-18603.json +45 -0
  111. package/rcf/user-stories/us-18701.json +50 -0
  112. package/rcf/user-stories/us-18702.json +50 -0
  113. package/rcf/user-stories/us-18801.json +45 -0
  114. package/rcf/user-stories/us-204.json +59 -0
  115. package/rcf/user-stories/us-205.json +64 -0
  116. package/rcf/user-stories/us-206.json +54 -0
  117. package/releases/releases.yaml +11 -1
  118. package/src/cli/freeze.js +730 -0
  119. package/src/cli/help.js +12 -0
  120. package/src/cli/ledger.js +228 -12
  121. package/src/cli/questions.js +288 -0
  122. package/src/cli/readiness.js +267 -49
  123. package/src/cli/view.js +29 -0
  124. package/src/define/freeze-record.js +30 -15
  125. package/src/define/ledgers.js +210 -11
  126. package/src/intake/index.js +1 -1
  127. package/src/intake/orchestrator.js +117 -0
  128. package/src/mcp/tools.js +354 -0
  129. package/src/query/delta.js +6 -0
  130. package/src/query/gates.js +314 -39
  131. package/src/query/index.js +16 -2
  132. package/src/query/questions.js +438 -0
  133. package/src/query/readiness.js +248 -7
  134. package/src/server/index.js +24 -2
  135. package/src/server/routes.js +68 -1
  136. package/src/setup/identity-seed.js +17 -0
  137. package/src/view/build-dag.js +563 -0
  138. package/src/view/components/badge.js +41 -0
  139. package/src/view/components/diff.js +72 -0
  140. package/src/view/components/doc-row.js +62 -0
  141. package/src/view/components/empty-state.js +35 -0
  142. package/src/view/components/entity-selector.js +137 -0
  143. package/src/view/components/filter-bar.js +97 -0
  144. package/src/view/components/findings-list.js +49 -0
  145. package/src/view/components/index.js +12 -0
  146. package/src/view/components/pill.js +46 -0
  147. package/src/view/components/sub-tab-strip.js +43 -0
  148. package/src/view/components/toast.js +25 -0
  149. package/src/view/components-fixture.js +265 -0
  150. package/src/view/doc-renderers/architecture.js +304 -0
  151. package/src/view/doc-renderers/build.js +160 -0
  152. package/src/view/doc-renderers/index.js +2 -0
  153. package/src/view/doc-renderers/prd.js +35 -6
  154. package/src/view/html-page.js +700 -602
  155. package/src/view/index.js +96 -3
  156. package/src/view/live-client.js +39 -6
  157. package/src/view/needs-work.js +79 -0
  158. package/src/view/page-init.js +2193 -0
  159. package/src/view/readiness/phrasebook.js +115 -0
  160. package/src/view/readiness/po-layer.js +288 -0
  161. package/src/view/readiness/question-adapter.js +329 -0
  162. package/src/view/readiness/stage-legend.js +71 -0
  163. package/src/view/readiness.js +505 -0
  164. package/src/view/style.css +2017 -382
  165. package/src/view/test-host/embed-client.js +121 -0
  166. package/src/view/test-host/fixture.js +183 -0
  167. package/src/view/test-host/lints.js +220 -0
  168. package/src/view/view-index.js +323 -0
@@ -8,11 +8,19 @@
8
8
  "AC-17501-2",
9
9
  "AC-17501-3",
10
10
  "AC-17501-4",
11
- "AC-17501-6"
11
+ "AC-17501-6",
12
+ "AC-17502-1",
13
+ "AC-17502-2",
14
+ "AC-17502-3",
15
+ "AC-17502-4",
16
+ "AC-17502-5",
17
+ "AC-17502-6",
18
+ "AC-17502-7",
19
+ "AC-17502-8"
12
20
  ],
13
21
  "dependencies": [],
14
22
  "version": "0.1.0",
15
23
  "status": "draft",
16
24
  "createdAt": "2026-09-24T14:30:00Z",
17
- "updatedAt": "2026-09-24T14:30:00Z"
25
+ "updatedAt": "2026-10-01T14:30:00Z"
18
26
  }
@@ -2,13 +2,23 @@
2
2
  "cnId": "CN-730",
3
3
  "path": "test/cli/readiness.test.js",
4
4
  "title": "CLI tests for rcf define readiness",
5
- "description": "Covers AC-17501-5: text output, --json emission, --check exit codes (blocking 4, warn-with-ack 0 with [warn]), admissibility refusal path exit 4.",
5
+ "description": "Covers AC-17501-5 (text output, --json emission, --check exit codes), AC-17502-7 (byte-stable rcf/ tree across a readiness run) and AC-17503-1..9 (default exits 0 + both verdict lines; --level intent exits 4 iff PO fails; --level build exits 4 iff readyToBuild is false, with warn lines emitted; --check all unchanged; --persona filters text and does not change exit; unknown values exit 2; --json --level intent carries _meta.level; text report groups PO before engineer with persona in detail lines; parameterised exit matrix).",
6
6
  "implementsAcIds": [
7
- "AC-17501-5"
7
+ "AC-17501-5",
8
+ "AC-17502-7",
9
+ "AC-17503-1",
10
+ "AC-17503-2",
11
+ "AC-17503-3",
12
+ "AC-17503-4",
13
+ "AC-17503-5",
14
+ "AC-17503-6",
15
+ "AC-17503-7",
16
+ "AC-17503-8",
17
+ "AC-17503-9"
8
18
  ],
9
19
  "dependencies": [],
10
20
  "version": "0.1.0",
11
21
  "status": "draft",
12
22
  "createdAt": "2026-09-24T14:30:00Z",
13
- "updatedAt": "2026-09-24T14:30:00Z"
23
+ "updatedAt": "2026-10-01T16:00:00Z"
14
24
  }
@@ -0,0 +1,20 @@
1
+ {
2
+ "cnId": "CN-731",
3
+ "path": "test/cli/freeze.test.js",
4
+ "title": "CLI tests for rcf define freeze",
5
+ "description": "Covers AC-17601-1..6 and AC-17601-8: happy freeze, refusal on failing D1, --ack on D3/D5/D6 only, section 2.5 summary line, --status is read-only, admissibility refusal is informational, and the readiness CLI stage header + CHANGELOG line no longer use ' -- '.",
6
+ "implementsAcIds": [
7
+ "AC-17601-1",
8
+ "AC-17601-2",
9
+ "AC-17601-3",
10
+ "AC-17601-4",
11
+ "AC-17601-5",
12
+ "AC-17601-6",
13
+ "AC-17601-8"
14
+ ],
15
+ "dependencies": [],
16
+ "version": "0.1.0",
17
+ "status": "draft",
18
+ "createdAt": "2026-09-24T16:33:15Z",
19
+ "updatedAt": "2026-09-24T16:33:15Z"
20
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "cnId": "CN-732",
3
+ "path": "test/define/freeze-record.test.js",
4
+ "title": "Extension tests for freeze-record override-nullable-required contract",
5
+ "description": "Covers AC-17601-7: validateFreezeRecord requires override (nullable), loadFreezeRecord defaults a missing override key to null, saveFreezeRecord refuses to write a body without override.",
6
+ "implementsAcIds": [
7
+ "AC-17601-7"
8
+ ],
9
+ "dependencies": [],
10
+ "version": "0.1.0",
11
+ "status": "draft",
12
+ "createdAt": "2026-09-24T16:33:15Z",
13
+ "updatedAt": "2026-09-24T16:33:15Z"
14
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "cnId": "CN-733",
3
+ "path": "src/setup/identity-seed.js",
4
+ "title": "Identity-seed template with the ## Surface section",
5
+ "description": "IDENTITY_TEMPLATE carries a ## Surface section between ## Register and ## Project-scoped notes naming viewer / runningApp / prDiff, seeded to prDiff so a fresh rcf init project satisfies checkD1Brief profile:surface marker without operator edit. writeIdentityTemplate keeps the slice-1 kept contract: an existing profile.md is left byte-identical.",
6
+ "implementsAcIds": [
7
+ "AC-17401-10"
8
+ ],
9
+ "dependencies": [],
10
+ "version": "0.1.0",
11
+ "status": "draft",
12
+ "createdAt": "2026-10-01T13:22:37Z",
13
+ "updatedAt": "2026-10-01T13:22:37Z"
14
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "cnId": "CN-734",
3
+ "path": "test/setup/identity-register.test.js",
4
+ "title": "Identity-seed Surface section tests",
5
+ "description": "Covers AC-17401-10: ## Surface heading placement; three value names + prDiff default; writeIdentityTemplate on a fresh dir seeds a profile that satisfies checkD1Brief surfaceMarkers; existing profile.md with no ## Surface is left byte-identical.",
6
+ "implementsAcIds": [
7
+ "AC-17401-10"
8
+ ],
9
+ "dependencies": [],
10
+ "version": "0.1.0",
11
+ "status": "draft",
12
+ "createdAt": "2026-10-01T13:22:37Z",
13
+ "updatedAt": "2026-10-01T13:22:37Z"
14
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ "cnId": "CN-735",
3
+ "path": "src/view/readiness.js",
4
+ "title": "Readiness tab panel renderer",
5
+ "description": "renderReadinessPanel(result, { profile, freezeRecord }) returns the eleven ordered blocks of spec section 5 for the Readiness tab: tree line, two verdict pills with formatVerdictLines labels, two per-persona next-action lines, D1..D8 state chips, blockers grouped by persona (register orders the pair; the non-register group collapses with its count visible, never omitted), delta list, per-stage check detail, coverage tree-vs-delta, decisions outstanding, Freeze now control (enabled iff levels.readyToBuild.ok), freeze record. Pure: no I/O, no recompute. pickRegister helper mirrors the CLI's contract.",
6
+ "implementsAcIds": [
7
+ "AC-18001-1",
8
+ "AC-18001-2",
9
+ "AC-18001-3",
10
+ "AC-18001-4",
11
+ "AC-18001-5",
12
+ "AC-18001-6",
13
+ "AC-18001-7"
14
+ ],
15
+ "dependencies": [],
16
+ "version": "0.1.0",
17
+ "status": "draft",
18
+ "createdAt": "2026-10-01T18:00:00Z",
19
+ "updatedAt": "2026-10-01T18:00:00Z"
20
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "cnId": "CN-736",
3
+ "path": "src/view/components/pill.js",
4
+ "title": "Shared pill component",
5
+ "description": "pill({ value, variant, title?, href? }) emits one markup shape across every vocabulary family (gate state, level verdict, persona, AC class) with class suffixes derived from a normalised value. Pure.",
6
+ "implementsAcIds": [
7
+ "AC-18101-1"
8
+ ],
9
+ "dependencies": [],
10
+ "version": "0.1.0",
11
+ "status": "draft",
12
+ "createdAt": "2026-10-01T18:00:00Z",
13
+ "updatedAt": "2026-10-01T18:00:00Z"
14
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "cnId": "CN-737",
3
+ "path": "src/view/components/findings-list.js",
4
+ "title": "Shared findings-list component",
5
+ "description": "findingsList({ heading, count, items }) emits a heading plus an id-anchor list with per-id why strings; ids are capped at 20 and the tail becomes a `... N more suppressed` line. Pure.",
6
+ "implementsAcIds": [
7
+ "AC-18101-2"
8
+ ],
9
+ "dependencies": [],
10
+ "version": "0.1.0",
11
+ "status": "draft",
12
+ "createdAt": "2026-10-01T18:00:00Z",
13
+ "updatedAt": "2026-10-01T18:00:00Z"
14
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "cnId": "CN-738",
3
+ "path": "src/view/components/diff.js",
4
+ "title": "Shared document-level diff component",
5
+ "description": "diff(before, after) renders a two-column before-and-after of two document bodies for the Readiness delta list. 0.29.0 ships document-level only; criterion-level before-and-after is deferred per ADR-4127. Pure.",
6
+ "implementsAcIds": [
7
+ "AC-18101-3"
8
+ ],
9
+ "dependencies": [],
10
+ "version": "0.1.0",
11
+ "status": "draft",
12
+ "createdAt": "2026-10-01T18:00:00Z",
13
+ "updatedAt": "2026-10-01T18:00:00Z"
14
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "cnId": "CN-739",
3
+ "path": "src/view/build-dag.js",
4
+ "title": "Build/DAG sub-tab pure renderer",
5
+ "description": "Pure HTML-string renderer for the Build tab's DAG sub-tab: `buildDagLayout(fbsItems, buildableIds)` projects `dependsOnFbsIds` into depth columns, `buildOrder` row ordering, upstream/downstream closures, longest-chain critical path and the no-in-no-out unconnected lane; `renderBuildDag({ layout, inspectorPayload })` emits the toolbar, canvas (HTML button nodes + inline SVG edges with cubic paths and arrowheads) and inspector shell. `buildDagInspectorPayload(layout)` builds the one-row-per-FBS payload (status, area, size, order, AC count, direct and transitive needs/waits, meta) that rides on the inspector shell as `data-rcf-dag-inspector-data` per the PR 1 contract. Cycles are excluded from the depth layout and surfaced as `cycleIds` for the toolbar finding (AC-204-6); the renderer never emits a `postMessage` call (AC-204-7).",
6
+ "implementsAcIds": [
7
+ "AC-204-1",
8
+ "AC-204-2",
9
+ "AC-204-3",
10
+ "AC-204-6",
11
+ "AC-204-7"
12
+ ],
13
+ "dependencies": [],
14
+ "version": "0.1.0",
15
+ "status": "draft",
16
+ "createdAt": "2026-10-02T19:00:00Z",
17
+ "updatedAt": "2026-10-02T19:00:00Z"
18
+ }
@@ -0,0 +1,19 @@
1
+ {
2
+ "cnId": "CN-740",
3
+ "path": "src/view/page-init.js",
4
+ "title": "Build/DAG client wiring (page-init DAG seam)",
5
+ "description": "`wireBuildDag` and its helpers wire the Build/DAG sub-tab in the browser: `parseDagInspectorPayload` reads the `data-rcf-dag-inspector-data` attribute off the inspector shell (never an inline <script>), click handlers on `.rcf-dag-node` run `selectDagNode` which sets `data-rcf-dag-sel`, auto-presses Show-unconnected when the node is unconnected, outlines upstream/downstream closures via `data-rcf-dag-role` attributes and renders the inspector body from the payload. Filter chips (status, area, Buildable-now, Critical-path, Show-unconnected) run `applyDagFilters` which keeps the current selection intact (AC-204-5). `buildHashFragment` writes `#tab=build&sub=dag&entity=<id>` and `currentDagHashExtras` preserves non-DAG hash params through DAG writes; `applyBuildHash` restores the selection, auto-presses Show-unconnected when the restored node is unconnected and scrolls the node into view (AC-204-4). `renderDagInspector` lists status, area, AC count, size, buildOrder, buildable-now, Needs (direct and transitive total) and Waits (direct and transitive total) with an Open-in-Specs link that moves to `#tab=build&sub=specs&entity=<id>` (AC-204-3).",
6
+ "implementsAcIds": [
7
+ "AC-204-2",
8
+ "AC-204-3",
9
+ "AC-204-4",
10
+ "AC-204-5"
11
+ ],
12
+ "dependencies": [
13
+ "CN-739"
14
+ ],
15
+ "version": "0.1.0",
16
+ "status": "draft",
17
+ "createdAt": "2026-10-02T19:00:00Z",
18
+ "updatedAt": "2026-10-02T19:00:00Z"
19
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "cnId": "CN-741",
3
+ "path": "src/view/view-index.js",
4
+ "title": "ID lookup pure projection + rank helper",
5
+ "description": "`buildViewIndex(model)` projects a BuiltTreeModel into one row per PRD/REQ/US/TAD/TAC/ADR/BS/FBS/TS plus one row per AC under each US, each `{ id, kind, title, snippet, parent, tab }`; `snippet` is the kind-specific prose field whitespace-collapsed and capped at 110 chars; `tab` is the viewer tab that owns the id. `serialiseViewIndex(model)` returns the exact JSON string the server serves (so Content-Length matches). `rankLookupRows(query, rows)` implements the design doc section 6 ranking: single-char id-only, otherwise id first (exact / prefix / contains), then every word must match title or snippet, title weighted above snippet, stable on ties by id, 20-result cap. This is the pure projection the server renders into `./index.json` on every rewalk (AC-205-1 to AC-205-3).",
6
+ "implementsAcIds": [
7
+ "AC-205-1",
8
+ "AC-205-2",
9
+ "AC-205-3"
10
+ ],
11
+ "dependencies": [],
12
+ "version": "0.1.0",
13
+ "status": "draft",
14
+ "createdAt": "2026-10-03T00:00:00Z",
15
+ "updatedAt": "2026-10-03T00:00:00Z"
16
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "cnId": "CN-742",
3
+ "path": "src/server/routes.js",
4
+ "title": "GET /index.json route for the viewer ID lookup",
5
+ "description": "`GET /index.json` returns the server-side ID index as `application/json; charset=utf-8` with `cache-control: no-store`. The handler reads `state.indexJson` (snapshotted per rewalk from `renderModelToPage().indexJson` so bytes match Content-Length) and never touches disk; before the first walk it 503s with `view server initialising`. The route is release-noted (PR 1 relative-script policy, wespa reverse-proxy allow-list adds it before the version pin bump) and is the fourth release-noted viewer route after `./page-init.js` (AC-205-1).",
6
+ "implementsAcIds": [
7
+ "AC-205-1"
8
+ ],
9
+ "dependencies": [
10
+ "CN-741"
11
+ ],
12
+ "version": "0.1.0",
13
+ "status": "draft",
14
+ "createdAt": "2026-10-03T00:00:00Z",
15
+ "updatedAt": "2026-10-03T00:00:00Z"
16
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "cnId": "CN-743",
3
+ "path": "src/view/html-page.js",
4
+ "title": "SearchButton + LookupModal shell markup",
5
+ "description": "`renderSearchButton()` emits a `<button data-rcf-search>` inside the shell `<div class=\"tools\">` to the right of the tabstrip, carrying the Cmd/Ctrl+F mnemonic on `aria-label` + `title`. `renderLookupModal()` emits the modal shell once in the shell outside `#rcf-live-content` so the SSE innerHTML swap never blows it away: `<aside role=\"dialog\" aria-modal=\"true\" aria-labelledby=...>` with `<section>`, `<header>`, labelled `<input>`, aria-live status region, `<ul role=\"listbox\">` results, empty-state block and `Reload index` affordance. No `<div>` tags inside the modal, so the Phase 3.8 D13a shell invariant (`lastIndexOf(\"</div>\")` resolves to the live-content wrapper close) stays intact (AC-205-1, AC-205-7).",
6
+ "implementsAcIds": [
7
+ "AC-205-1",
8
+ "AC-205-7"
9
+ ],
10
+ "dependencies": [],
11
+ "version": "0.1.0",
12
+ "status": "draft",
13
+ "createdAt": "2026-10-03T00:00:00Z",
14
+ "updatedAt": "2026-10-03T00:00:00Z"
15
+ }
@@ -0,0 +1,22 @@
1
+ {
2
+ "cnId": "CN-744",
3
+ "path": "src/view/page-init.js",
4
+ "title": "wireLookup client (ID lookup wiring)",
5
+ "description": "`wireLookup` lazily XHR-fetches `./index.json` on first modal open, refetches once when `window.__rcfLookupDirty` is set by live-client (SSE tree-update), ranks via a mirror of `rankLookupRows`, cycles the active row with Up / Down, picks with Enter and closes with Esc. The Router's `resolveHash` honours `?tab=&entity=` at mount so a landed URL (`?tab=requirements&entity=US-304`) opens the same position at first paint without the LookupModal (AC-205-5). Pick writes `#tab=<tab>&entity=<id>` via `writeHash` so `?embed=` and `?theme=` survive (PR 1 contract); the Router's hashchange listener activates the tab, opens ancestor DocRows and flashes the target. Cmd/Ctrl+F opens the modal from any tab; Cmd/Ctrl+Shift+F is deliberately NOT intercepted so the browser find still works. Marks every id / title / snippet substring hit by a query word (`<mark>`, escaped). Empty state shows `The index could not be loaded.` + `Reload index` on fetch failure; never calls `postMessage`, never writes to localStorage / sessionStorage / document.cookie, and never makes an outbound fetch other than `./index.json` (AC-205-4, AC-205-6, AC-205-7, AC-205-8).",
6
+ "implementsAcIds": [
7
+ "AC-205-4",
8
+ "AC-205-5",
9
+ "AC-205-6",
10
+ "AC-205-7",
11
+ "AC-205-8"
12
+ ],
13
+ "dependencies": [
14
+ "CN-741",
15
+ "CN-742",
16
+ "CN-743"
17
+ ],
18
+ "version": "0.1.0",
19
+ "status": "draft",
20
+ "createdAt": "2026-10-03T00:00:00Z",
21
+ "updatedAt": "2026-10-03T00:00:00Z"
22
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "cnId": "CN-745",
3
+ "path": "src/view/live-client.js",
4
+ "title": "SSE tree-update dirties the ID lookup cache",
5
+ "description": "On every SSE `tree-update` event, live-client sets `window.__rcfLookupDirty = true`. `wireLookup` reads this flag on the next modal open and refetches `./index.json` once, then clears it. This keeps the modal consistent with the live walker without polling (AC-205-4).",
6
+ "implementsAcIds": [
7
+ "AC-205-4"
8
+ ],
9
+ "dependencies": [
10
+ "CN-744"
11
+ ],
12
+ "version": "0.1.0",
13
+ "status": "draft",
14
+ "createdAt": "2026-10-03T00:00:00Z",
15
+ "updatedAt": "2026-10-03T00:00:00Z"
16
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "cnId": "CN-746",
3
+ "path": "src/view/readiness/question-adapter.js",
4
+ "title": "Readiness PO question adapter: feature-detected questions source + source-span grouping",
5
+ "description": "`toQuestions(readiness)` is the pure projection the Readiness PO layer reads. `preferReadinessQuestions(readiness)` feature-detects the DEFINE step 3 PR 2 `computeQuestions` output on `readiness.questions`: when present, the adapter reads from there, using `groups[]` labels and the per-question `heading` / `ask` / `hint` with phrasebook fallback per field; the group label falls back to a conservative sourceSpan prose when no `sourceSpanLabel` is given. Otherwise the adapter reads `personas.productOwner.blockers`, groups by source span (brief:<n>, REQ-N, or a plain stage label) and fills asks from the phrasebook. One source of truth for the PO ask text; nothing is fabricated that is not on the tree (AC-18002-1).",
6
+ "implementsAcIds": [
7
+ "AC-18002-1"
8
+ ],
9
+ "dependencies": [],
10
+ "version": "0.1.0",
11
+ "status": "draft",
12
+ "createdAt": "2026-10-03T09:30:00Z",
13
+ "updatedAt": "2026-10-03T09:30:00Z"
14
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "cnId": "CN-747",
3
+ "path": "src/view/readiness/po-layer.js",
4
+ "title": "Readiness PO layer: VerdictCards, QuestionCards grouped by source span, intent-complete empty state, For-engineers DocRow",
5
+ "description": "`renderReadinessPO(readiness, { persona, engineerBody })` emits the PO layer HTML: two equal-height VerdictCards (intent-complete and ready-to-build) with the chain term muted beside each plain label; one QuestionCard group per source span sourced from `toQuestions(readiness)`; a `data-rcf-empty=\"yes\"` block that renders the verbatim `formatVerdictLines(readiness).intentComplete` string when `questions[]` is empty and both levels are ok (AC-18002-2); the Requirements-that-still-need-work table; and the For-engineers DocRow that wraps the engineer rendering, closed under productOwner / unstated and open under engineer, with the data preserved in the DOM in every register (AC-18002-3). Stamps `data-rcf-source=\"readiness.questions\"` on the questions block when the real compute shape is live (AC-18002-1).",
6
+ "implementsAcIds": [
7
+ "AC-18002-1",
8
+ "AC-18002-2",
9
+ "AC-18002-3"
10
+ ],
11
+ "dependencies": [
12
+ "CN-746"
13
+ ],
14
+ "version": "0.1.0",
15
+ "status": "draft",
16
+ "createdAt": "2026-10-03T09:30:00Z",
17
+ "updatedAt": "2026-10-03T09:30:00Z"
18
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "cnId": "CN-748",
3
+ "path": "src/view/readiness.js",
4
+ "title": "renderReadinessPanel wraps the PO layer around the engineer body and picks the register from profile.md",
5
+ "description": "`renderReadinessPanel(result, { profileText })` picks the register from `profile.md` (productOwner | engineer | unstated), renders the engineer body (the pre-PR-8 Readiness rendering: tree line, CLI verdict lines, next-action-per-persona, D1..D8 chips, PO + Engineer blocker groups, delta/diff) once, and hands it to `renderReadinessPO` as `engineerBody`. The engineer body is never removed from the DOM; `renderReadinessPO` is what folds it into the For-engineers DocRow and decides open/closed per register (AC-18002-3).",
6
+ "implementsAcIds": [
7
+ "AC-18002-3"
8
+ ],
9
+ "dependencies": [
10
+ "CN-747"
11
+ ],
12
+ "version": "0.1.0",
13
+ "status": "draft",
14
+ "createdAt": "2026-10-03T09:30:00Z",
15
+ "updatedAt": "2026-10-03T09:30:00Z"
16
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "cnId": "CN-749",
3
+ "path": "src/view/index.js",
4
+ "title": "View bootstrap attaches computeQuestions output to readiness so the adapter feature-detects the real shape",
5
+ "description": "After `computeReadiness` returns, the view bootstrap calls `computeQuestions(readiness, { tree, ledgers, profileText, persona: 'productOwner' })` and merges the result's `questions`, `groups`, `optional` and `engineer` fields onto the readiness object before it reaches `renderPage`. `preferReadinessQuestions` then returns true and `fromReadinessQuestions` reads the real `computeQuestions` output rather than falling back to the blockers path (AC-18002-1). The phrasebook stays available as the per-field fallback when a question carries no `ask` / `hint` of its own.",
6
+ "implementsAcIds": [
7
+ "AC-18002-1"
8
+ ],
9
+ "dependencies": [
10
+ "CN-746"
11
+ ],
12
+ "version": "0.1.0",
13
+ "status": "draft",
14
+ "createdAt": "2026-10-03T09:30:00Z",
15
+ "updatedAt": "2026-10-03T09:30:00Z"
16
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "cnId": "CN-750",
3
+ "path": "src/view/test-host/fixture.js",
4
+ "title": "Wespa host fixture page: 56px header, resizable sidebar, iframe mounted at ./?embed=1&theme=light with no inline script",
5
+ "description": "`renderTestHostPage()` returns the host-fixture HTML as a pure string: HTML5 doctype, lang='en-GB', a 56px wespa-header carrying the Light/Dark toggle buttons, a resizable sidebar shell (data-rcf-host-sidebar + drag handle) and a content pane carrying `<iframe id=\"rcf-test-host-iframe\" src=\"./?embed=1&amp;theme=light\">`. The fixture ships no inline `<script>` body (CSP-friendly, consistent with the PR 1 contract); its client-side wiring lives at /test-host.js (served via /test-host.js when the test-host route is enabled). The fixture does not persist theme or sidebar width to localStorage (ADR-4136): a passing run has to flip the iframe through the postMessage path, which is the invariant the fixture pins. Proves AC-206-1 (shell + iframe src + no inline script) and underwrites AC-206-6 (no outbound postMessage shape beyond the embed-client's single rcf-view-theme post).",
6
+ "implementsAcIds": [
7
+ "AC-206-1",
8
+ "AC-206-6"
9
+ ],
10
+ "dependencies": [],
11
+ "version": "0.1.0",
12
+ "status": "draft",
13
+ "createdAt": "2026-10-03T09:55:00Z",
14
+ "updatedAt": "2026-10-03T09:55:00Z"
15
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "cnId": "CN-751",
3
+ "path": "src/view/test-host/embed-client.js",
4
+ "title": "Wespa host fixture client: theme postMessage, sidebar drag + collapse/expand, same-origin message target",
5
+ "description": "Classic (non-module) browser script served at /test-host.js when the test-host route is on. Three fixture behaviours: (a) the theme toggle posts `{ type: 'rcf-view-theme', theme }` to `iframe.contentWindow`, targeting `window.location.origin` so a cross-origin receiver would refuse the message (underwrites AC-206-4 together with the viewer's own origin check in page-init.js); (b) the sidebar drag handle sets `--wespa-sidebar-width` on the <main> grid, clamped to 64..400 px live; (c) collapse/expand snaps the sidebar between 64 px and 200 px. Reads the iframe's `data-theme` attribute as evidence of the postMessage round-trip (AC-206-2). After the iframe's hash-only navigation, `data-embed` and the search string carry embed=1 and the theme, which the live-proof script captures (AC-206-3). The host does not read event.origin (the viewer does) and does not persist theme to localStorage (ADR-4136 invariant).",
6
+ "implementsAcIds": [
7
+ "AC-206-2",
8
+ "AC-206-3",
9
+ "AC-206-4"
10
+ ],
11
+ "dependencies": [
12
+ "CN-750"
13
+ ],
14
+ "version": "0.1.0",
15
+ "status": "draft",
16
+ "createdAt": "2026-10-03T09:55:00Z",
17
+ "updatedAt": "2026-10-03T09:55:00Z"
18
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "cnId": "CN-752",
3
+ "path": "src/view/test-host/lints.js",
4
+ "title": "Three embedding lints: framing headers, target=_top, localStorage namespace",
5
+ "description": "Three pure assertions callable by any test harness; test/view/wespa-host-fixture.test.js is the suite caller. (1) `assertFramingHeaders(response)` refuses on `X-Frame-Options` or on CSP `frame-ancestors` forbidding same-origin, and accepts `frame-ancestors 'self'`. (2) `assertNoTargetTop(renderedHtml)` greps for `target=\"_top\"` / `target='_top'` / `target=_top` and refuses on any match; returns `{ ok, count }`. (3) `assertLocalStorageNamespace(sourceTreeRoot)` walks every .js file under `src/view/**` (excluding vendored and .min.js) and asserts every `localStorage.*` / `sessionStorage.*` / shared `storage.*` call site uses a key literal starting with `rcf-view:v1:` or a constant resolving to that prefix. Together they pin AC-206-5 against regressions.",
6
+ "implementsAcIds": [
7
+ "AC-206-5"
8
+ ],
9
+ "dependencies": [],
10
+ "version": "0.1.0",
11
+ "status": "draft",
12
+ "createdAt": "2026-10-03T09:55:00Z",
13
+ "updatedAt": "2026-10-03T09:55:00Z"
14
+ }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "createdAt": "2026-09-24T14:30:00Z",
3
- "updatedAt": "2026-09-24T14:30:00Z",
3
+ "updatedAt": "2026-10-01T13:12:16Z",
4
4
  "acIds": [
5
5
  "AC-17401-1",
6
6
  "AC-17401-2",
@@ -9,7 +9,9 @@
9
9
  "AC-17401-5",
10
10
  "AC-17401-6",
11
11
  "AC-17401-7",
12
- "AC-17401-8"
12
+ "AC-17401-8",
13
+ "AC-17401-9",
14
+ "AC-17401-10"
13
15
  ],
14
16
  "fbsId": "FBS-196",
15
17
  "prdId": "PRD-001",
@@ -18,11 +20,17 @@
18
20
  "executionStatus": "complete",
19
21
  "title": "DEFINE slice 2: stage gates D1..D8 pure check functions",
20
22
  "summary": "Ship src/query/gates.js exposing one check function per stage D1..D8 with the section 2.4 shape { stage, gate, state, checks[] }. Blocking stages (D1, D2, D4, D7, D8) enforce the floors listed in proposal section 3.2; warn-with-ack stages (D3, D5, D6) run only the cheap data-backed checks and are acknowledgeable via freeze.gates[<gate>] at the current tree hash. AC class parses off the bracketed prefix on AC description (decision 6); D4 per-class opt-outs read manifest.baselineAcOptOuts[] with baselineKey 'defineD4:failure' or 'defineD4:mustNot' per ADR-4122.",
21
- "dependsOnFbsIds": ["FBS-195"],
23
+ "dependsOnFbsIds": [
24
+ "FBS-195"
25
+ ],
22
26
  "approach": "One file, eight exported functions plus the STAGE_ORDER, STAGE_GATES, STAGE_SHORT_NAMES and INTERFACE_KINDS constants. Every function follows the same shape: decide notApplicable per section 3.2; assemble a checks[] list of { name, ok, over, pass, total, failing }; fold to state, honouring the warn-with-ack acknowledgement window when the stage is D3/D5/D6. Ledger reads use the emptyLedger fallback so an absent ledger contributes no findings. AC class parsing is a static regex over the description string (leading '[failure]' / '[must-not]' / '[happy]' / '[edge]' / '[non-functional]', case-sensitive). Profile parsing is a light presence check on rcf/.identity/profile.md (surface and register markers).",
23
27
  "contextRequirements": {
24
- "tacIds": ["TAC-4122-define-gates"],
25
- "adrIds": ["ADR-4122-define-gates-blocking-and-optout"]
28
+ "tacIds": [
29
+ "TAC-4122-define-gates"
30
+ ],
31
+ "adrIds": [
32
+ "ADR-4122-define-gates-blocking-and-optout"
33
+ ]
26
34
  },
27
35
  "deliverables": [
28
36
  "src/query/gates.js: STAGE_ORDER, STAGE_GATES, STAGE_SHORT_NAMES, INTERFACE_KINDS, checkD1Brief..checkD8Freeze, plus foldState and parseAcClass helpers",
@@ -0,0 +1,42 @@
1
+ {
2
+ "createdAt": "2026-09-24T16:33:15Z",
3
+ "updatedAt": "2026-09-24T16:33:15Z",
4
+ "acIds": [
5
+ "AC-17601-1",
6
+ "AC-17601-2",
7
+ "AC-17601-3",
8
+ "AC-17601-4",
9
+ "AC-17601-5",
10
+ "AC-17601-6",
11
+ "AC-17601-7",
12
+ "AC-17601-8"
13
+ ],
14
+ "fbsId": "FBS-198",
15
+ "prdId": "PRD-001",
16
+ "bsId": "BS-001",
17
+ "buildOrder": 198,
18
+ "executionStatus": "notStarted",
19
+ "title": "DEFINE slice 3: rcf define freeze CLI + freeze-record override + hygiene",
20
+ "summary": "Ship src/cli/freeze.js implementing 'rcf define freeze' as the only freeze-record writer, wire it into bin/rcf.js and src/cli/help.js, update src/define/freeze-record.js so override is a nullable-required field (loader defaults missing keys to null; validator refuses a body without the key), and replace the ' -- ' double-dash in the readiness CLI stage header and the CHANGELOG TODO-regex line with a colon.",
21
+ "dependsOnFbsIds": ["FBS-197"],
22
+ "approach": "One CLI module composing computeReadiness (REQ-175) and saveFreezeRecord (REQ-172). Ack parsing is a small helper walking --ack and --reason multi-valued arrays in parallel. Ack folding uses the same WARN_WITH_ACK rules gates.js applies at the current tree hash. Counts derivation reuses tree.kindById and parseAcClass; interface counts walk each TAC's interfaces[]. Version reading loads packages/rcf-lite/package.json, src/ruleset/ruleset.json and node_modules/@stravica-ai/rcf-schemas/package.json. --status is a read-only branch that never runs gates. Admissibility refusal is informational per ADR-4124. The freeze-record schema fix requires an override field (nullable): validator throws on missing key, loader defaults missing keys to null on read for backward compatibility, saveFreezeRecord's own validate step catches a caller that forgets to write override.",
23
+ "contextRequirements": {
24
+ "tacIds": ["TAC-4124-define-freeze"],
25
+ "adrIds": ["ADR-4124-define-freeze-verb"]
26
+ },
27
+ "deliverables": [
28
+ "src/cli/freeze.js: HELP, main; --ack (multiple) / --reason (multiple) / --note / --litmus-attested / --status / --json / --help flags; runWithAdmissibilityGate wrap; section 2.5 summary line and --json envelope; counts derivation",
29
+ "src/define/freeze-record.js: validateFreezeRecord requires override (nullable); loadFreezeRecord defaults missing override to null; saveFreezeRecord unchanged (still validates first, which now catches missing override)",
30
+ "src/cli/readiness.js: stage header line uses ': ' between stage / gate / state (no ' -- ')",
31
+ "CHANGELOG.md: TODO regex line rewritten to use ': ' instead of ' -- ', plus slice-3 entries under [Unreleased]",
32
+ "bin/rcf.js: GROUPS.define.freeze wired to freezeMain",
33
+ "src/cli/help.js: HELP as FREEZE_HELP imported; HELP_MAP.define.freeze wired; DEFINE_HELP listing extended",
34
+ "test/cli/freeze.test.js: CLI tests covering AC-17601-1..6 and AC-17601-8",
35
+ "test/define/freeze-record.test.js: extension test covering AC-17601-7 (override required, loader defaults)"
36
+ ],
37
+ "riskLevel": "low",
38
+ "domain": "defineDetection",
39
+ "estimatedSize": "medium",
40
+ "estimatedHours": 4,
41
+ "notes": "Depth-2 slice: no sub-agents. Chain first, code next, tests last. Dogfood is NOT frozen in the repo (a committed freeze.json would be a product decision); prove the verb on scratch trees and run --status on the dogfood chain as evidence."
42
+ }
@@ -0,0 +1,59 @@
1
+ {
2
+ "createdAt": "2026-10-01T14:30:00Z",
3
+ "updatedAt": "2026-10-01T14:30:00Z",
4
+ "acIds": [
5
+ "AC-17402-1",
6
+ "AC-17402-2",
7
+ "AC-17402-3",
8
+ "AC-17402-4",
9
+ "AC-17402-5",
10
+ "AC-17402-6",
11
+ "AC-17402-7",
12
+ "AC-17403-1",
13
+ "AC-17403-2",
14
+ "AC-17403-3",
15
+ "AC-17403-4",
16
+ "AC-17403-5",
17
+ "AC-17403-6",
18
+ "AC-17403-7",
19
+ "AC-17403-8",
20
+ "AC-17502-1",
21
+ "AC-17502-2",
22
+ "AC-17502-3",
23
+ "AC-17502-4",
24
+ "AC-17502-5",
25
+ "AC-17502-6",
26
+ "AC-17502-7",
27
+ "AC-17502-8"
28
+ ],
29
+ "fbsId": "FBS-199",
30
+ "prdId": "PRD-001",
31
+ "bsId": "BS-001",
32
+ "buildOrder": 199,
33
+ "executionStatus": "complete",
34
+ "title": "DEFINE step 2 (0.29.0) PR A: persona tags on every gate check and two readiness levels (ADR-4126)",
35
+ "summary": "Ship the compute layer for ADR-4126: CHECK_PERSONA / CHECK_QUESTION maps and persona + question on every stages[].checks[] entry; split skeleton:reqFields into skeleton:reqIntent + skeleton:reqShape and decisions:allAnswered into decisions:wellFormed + decisions:allAnswered; add the new D3 shapes:draftSettled check and the parseInterfaceDraft helper; fold levels (intentComplete, readyToBuild) and personas (productOwner, engineer) on the computeReadiness result; extend deriveNextAction with an optional persona filter; add formatVerdictLines shared by the CLI (PR B) and the Readiness tab (PR C). All additions are strictly additive; the 0.28.4 top-level shape is preserved and rcf define readiness default behaviour / exit codes are unchanged.",
36
+ "dependsOnFbsIds": ["FBS-197"],
37
+ "approach": "One pass through src/query/gates.js adds the persona + question maps and plumbs them through makeCheck; the two splits are per-REQ / per-entry loops that evaluate every item independently so one failure never masks another; the shapes:draftSettled check parses the leading bracket marker on interface descriptions (whitespace tolerated). src/query/readiness.js folds levels + personas from stages[].checks[] after the eight stage functions run; deriveNextAction gains an optional persona argument; formatVerdictLines builds the two shared verdict strings. The CLI flags (--level, --persona) and the viewer tab land in PRs B and C of the same train and are out of scope here.",
38
+ "contextRequirements": {
39
+ "tacIds": [
40
+ "TAC-4122-define-gates",
41
+ "TAC-4123-define-readiness"
42
+ ],
43
+ "adrIds": [
44
+ "ADR-4126-persona-tagged-blockers-two-levels"
45
+ ]
46
+ },
47
+ "deliverables": [
48
+ "src/query/gates.js: CHECK_PERSONA + CHECK_QUESTION + STAGE_FALLBACK_PERSONA maps; checkPersona / checkQuestion / parseInterfaceDraft helpers; split skeleton:reqIntent / skeleton:reqShape; new shapes:draftSettled; split decisions:wellFormed / decisions:allAnswered; makeCheck adds persona + question on every emitted check; D3 doc comment fix for TAD.dataArchitecture.coreEntities",
49
+ "src/query/readiness.js: levels (intentComplete, readyToBuild) and personas (productOwner, engineer) fold; deriveNextAction gains an optional persona argument; formatVerdictLines builds the two shared verdict strings",
50
+ "src/query/index.js: re-export the new helpers (CHECK_PERSONA / CHECK_QUESTION / STAGE_FALLBACK_PERSONA / parseInterfaceDraft / deriveLevels / derivePersonas / formatVerdictLines)",
51
+ "test/query/gates.test.js and test/query/readiness.test.js: new cases covering AC-17402-*, AC-17403-* and AC-17502-*",
52
+ "CHANGELOG [Unreleased] entry describing the additive compute changes"
53
+ ],
54
+ "riskLevel": "low",
55
+ "domain": "defineDetection",
56
+ "estimatedSize": "medium",
57
+ "estimatedHours": 4,
58
+ "notes": "PR B (CLI --level / --persona + text report) and PR C (Readiness viewer tab) are the remaining 0.29.0 step-2 PRs under REQ-175 / REQ-180 / REQ-181. No file under rcf/ is created or modified by any rcf define readiness invocation; the levels and personas folds are read-only derivations over stages[].checks[]."
59
+ }