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
@@ -0,0 +1,54 @@
1
+ {
2
+ "createdAt": "2026-10-02T20:00:00Z",
3
+ "updatedAt": "2026-10-02T20:00:00Z",
4
+ "tacId": "TAC-4134-wespa-host-fixture",
5
+ "prdId": "PRD-001",
6
+ "tadId": "TAD-001",
7
+ "version": "0.1.0",
8
+ "status": "draft",
9
+ "name": "Wespa host fixture: /test-host.html and the three embedding lints",
10
+ "purpose": "Serve a same-origin test-host fixture page that mimics the wespa shell (a 56px header, a resizable 64/200-400px sidebar, a content pane carrying `<iframe src=\"./?embed=1&theme=light\">`) and ship three CI lints (framing headers, `target=\"_top\"` grep, localStorage namespace grep) that keep wespa's embedding contract honest over time. The fixture is off the default route surface so wespa's reverse-proxy allow-list is unaffected; it is gated on a `--test-host` CLI flag or the `RCF_VIEW_TEST_HOST=1` env var and never served under production use.",
11
+ "responsibilities": [
12
+ "src/view/test-host/fixture.js: `renderTestHostPage()` returns the HTML for the fixture (56px header with Light/Dark/Auto theme toggle buttons, a resizable sidebar with a drag handle and a Collapse/Expand control, a content pane containing the single `<iframe id=\"rcf-test-host-iframe\" src=\"./?embed=1&theme=light\">` sized to 100% of its box). No inline script; the page references `./test-host.js` as a relative script.",
13
+ "src/view/test-host/embed-client.js: classic (non-module) browser script that wires the theme toggle buttons to `iframe.contentWindow.postMessage({ type: \"rcf-view-theme\", theme }, window.location.origin)`, the sidebar drag handle to a live width update (clamped to 64-400px) and the Collapse/Expand button to a 64px <-> 200px snap. The script posts nothing beyond `rcf-view-theme`, does not read event.origin itself (the viewer does), and writes nothing to localStorage so a passing run proves the iframe honours the message.",
14
+ "src/view/test-host/lints.js: `assertFramingHeaders(response)` scans a GET / response for `X-Frame-Options`, CSP `frame-ancestors` and `X-Content-Type-Options` oddities (any present or any `frame-ancestors` directive forbidding `self` fails); `assertNoTargetTop(renderedHtml)` scans the HTML for any `target=\"_top\"` or `target='_top'` occurrence and refuses on a non-zero count; `assertLocalStorageNamespace(sourceTree)` scans every `.js` file under `src/view/**` (not vendored, not `.min.js`) for `localStorage.(setItem|getItem|removeItem)(` and `storage.(setItem|getItem|removeItem)(` call sites and refuses on any key literal that does not start with `rcf-view:v1:`.",
15
+ "src/server/routes.js: when `deps.testHost === true`, register `GET /test-host.html` returning `renderTestHostPage()` with `content-type: text/html` and no framing-blocking header; register `GET /test-host.js` returning the embed-client script as `application/javascript` with no framing-blocking header. Off the default route surface: both routes 404 unless `testHost` is on.",
16
+ "src/server/index.js: plumb an optional `testHost: boolean` option through `startServer(args)` into the router; default false. Wire the embed-client asset at startup via `loadStaticAsset`, same discipline as `./live-client.js`.",
17
+ "src/cli/view.js: parse `--test-host` into `opts.testHost`; precedence is flag beats `RCF_VIEW_TEST_HOST=1` env beats default (false). Pass `testHost` through to `startServer`. Help text names the flag and marks it a test-suite fixture, not a shipped UI.",
18
+ "test/view/wespa-host-fixture.test.js: end-to-end node-level checks that boot the router with `testHost: true` over `http.createServer`, GET /, GET /test-host.html, GET /test-host.js, assert the three lints green, parse the iframe `src` from the fixture HTML and assert `./?embed=1&theme=light` exactly, assert the fixture carries no inline `<script>` block, assert the viewer's rendered HTML carries `<html data-embed=\"1\">` wiring (via page-init.js) and that the fixture page does not persist theme to localStorage."
19
+ ],
20
+ "internalStructure": "Three composition seams. (1) `renderTestHostPage()` is a pure function (no reads, no I/O) that emits the host HTML and references the relative embed-client script; swap the host markup in one place. (2) The embed-client script is served as a snapshotted asset at startup; it is the only client-side JS the fixture carries. (3) `src/view/test-host/lints.js` exports three pure assertions keyed on their inputs (response object, HTML string, source tree root) so each lint composes into any test that needs it and the test file is the sole caller.",
21
+ "interfaces": [
22
+ {
23
+ "name": "GET /test-host.html",
24
+ "kind": "httpRoute",
25
+ "description": "[draft] Returns the host fixture HTML (`renderTestHostPage()`). Served only when `startServer({ testHost: true })` is on (CLI `--test-host` or env `RCF_VIEW_TEST_HOST=1`); 404 otherwise. No `X-Frame-Options`, no CSP `frame-ancestors` directive. Relative script `./test-host.js` is the only client-side JS. Not under the production root; the viewer's `/` surface is untouched."
26
+ },
27
+ {
28
+ "name": "GET /test-host.js",
29
+ "kind": "httpRoute",
30
+ "description": "[draft] Returns the embed-client script that wires the theme toggle, sidebar drag and Collapse/Expand to postMessage and sidebar width updates. `application/javascript`; snapshotted at startup. Same `testHost` gate as the HTML route."
31
+ },
32
+ {
33
+ "name": "assertFramingHeaders",
34
+ "kind": "moduleApi",
35
+ "description": "[draft] `assertFramingHeaders(response)` on a `GET /` response. Refuses if `X-Frame-Options` is present, if a CSP `frame-ancestors` directive forbids `self`, or if `X-Content-Type-Options: nosniff` is set in a way that breaks the fixture (today it does not; the lint still records absence). Returns `{ ok: true }` or throws with the first failure."
36
+ },
37
+ {
38
+ "name": "assertNoTargetTop",
39
+ "kind": "moduleApi",
40
+ "description": "[draft] `assertNoTargetTop(renderedHtml)` greps the server-rendered HTML for `target=\"_top\"` and `target='_top'` and refuses on any match. Returns `{ ok: true, count: 0 }` or `{ ok: false, count: n, matches: [...] }`."
41
+ },
42
+ {
43
+ "name": "assertLocalStorageNamespace",
44
+ "kind": "moduleApi",
45
+ "description": "[draft] `assertLocalStorageNamespace(sourceTreeRoot)` walks every `.js` file under `src/view/**` (excluding vendored and `.min.js`), finds every `localStorage.(setItem|getItem|removeItem)(KEY)` and `storage.(setItem|getItem|removeItem)(KEY)` call site, and asserts that the key literal starts with `rcf-view:v1:` (or references `STORAGE_NS` which equals `rcf-view:v1:`). Returns `{ ok: true, scanned: n }` or `{ ok: false, violations: [...] }`."
46
+ },
47
+ {
48
+ "name": "renderTestHostPage",
49
+ "kind": "moduleApi",
50
+ "description": "[draft] Pure function that emits the fixture HTML (56px header, resizable 64/200-400px sidebar, iframe content pane). No inline script; references `./test-host.js` as the single client-side JS."
51
+ }
52
+ ],
53
+ "notes": "Depends on PR 1's `embed` and `theme` contract (page-init.js stamping `<html data-embed=\"1\">` and `<html data-theme>`, origin-checked `rcf-view-theme` listener, hash navigation preserving the host query string), on PR 1's relative-script policy (no inline script, no leading-slash references) and on live-client.js's existing `STORAGE_NS = 'rcf-view:v1:'` namespace. The test-host route surface is behind `--test-host` / `RCF_VIEW_TEST_HOST=1`; the release notes mark it as a test-suite fixture, not a shipped UI, so wespa's proxy allow-list is unaffected. The three lints are called from the viewer's test suite; wespa smoke on the live wespa shell is Dex's side."
54
+ }
@@ -14,9 +14,9 @@
14
14
  {
15
15
  "id": "TC-016-tools-list-structured-schemas",
16
16
  "acId": "AC-601-1",
17
- "description": "an MCP client listing tools sees all eleven rcf tools with input and output schemas",
17
+ "description": "an MCP client listing tools sees all fourteen rcf tools with input and output schemas",
18
18
  "status": "pending",
19
- "testPointer": "test/mcp/stdio.e2e.test.js::e2e: tools/list returns all eleven tools with schemas"
19
+ "testPointer": "test/mcp/stdio.e2e.test.js::e2e: tools/list returns all fourteen tools with schemas"
20
20
  },
21
21
  {
22
22
  "id": "TC-016-mcp-coverage-cli-parity",
@@ -34,4 +34,4 @@
34
34
  }
35
35
  ],
36
36
  "status": "draft"
37
- }
37
+ }
@@ -1,17 +1,35 @@
1
1
  {
2
2
  "createdAt": "2026-09-24T12:00:00Z",
3
- "updatedAt": "2026-09-24T12:00:00Z",
4
- "purpose": "Cover the four sidecar ledgers, the rcf define ledger CLI (add / resolve / list with --json) and the walker-invisibility invariant on rcf/define/ against AC-17301-1..4 on US-17301.",
3
+ "updatedAt": "2026-10-02T16:40:00Z",
4
+ "purpose": "Cover the four sidecar ledgers, the rcf define ledger CLI (add / resolve / list with --json) and the walker-invisibility invariant on rcf/define/ (AC-17301-1..4 on US-17301), the update subverb and the closed resolvedBy pointer grammar (AC-17302-1..6 on US-17302), the statement-file markers (AC-18701-1..6 on US-18701) and the scan wiring (AC-18702-1..6 on US-18702).",
5
5
  "testLevel": "integration",
6
6
  "acIds": [
7
7
  "AC-17301-1",
8
8
  "AC-17301-2",
9
9
  "AC-17301-3",
10
- "AC-17301-4"
10
+ "AC-17301-4",
11
+ "AC-17302-1",
12
+ "AC-17302-2",
13
+ "AC-17302-3",
14
+ "AC-17302-4",
15
+ "AC-17302-5",
16
+ "AC-17302-6",
17
+ "AC-18701-1",
18
+ "AC-18701-2",
19
+ "AC-18701-3",
20
+ "AC-18701-4",
21
+ "AC-18701-5",
22
+ "AC-18701-6",
23
+ "AC-18702-1",
24
+ "AC-18702-2",
25
+ "AC-18702-3",
26
+ "AC-18702-4",
27
+ "AC-18702-5",
28
+ "AC-18702-6"
11
29
  ],
12
30
  "id": "TS-215",
13
31
  "usId": "US-17301",
14
- "title": "Sidecar ledgers, rcf define ledger and walker invisibility",
32
+ "title": "Sidecar ledgers, rcf define ledger and walker invisibility (extended for update + intake markers + scans)",
15
33
  "testCases": [
16
34
  {
17
35
  "id": "TC-215-brief-add-text",
@@ -61,6 +79,132 @@
61
79
  "description": "walkTree run over a project seeded with rcf/define/freeze.json, the four ledger files and a bug-bait req-999.json under rcf/define/ never surfaces any rcf/define/ path in errors or byId.",
62
80
  "status": "pending",
63
81
  "testPointer": "test/store/walker-invisible-define.test.js::walkTree never surfaces rcf/define/ files as documents in byId"
82
+ },
83
+ {
84
+ "id": "TC-215-brief-update-fields-and-preserve-id",
85
+ "acId": "AC-17302-1",
86
+ "description": "updateEntry patches brief fields (kind, resolvedBy) and preserves id and addedAt; the CLI brief update subverb returns 0 and the write lands on the ledger with the patched fields.",
87
+ "status": "pending",
88
+ "testPointer": "test/define/ledgers.test.js::updateEntry (AC-17302-1): patches brief fields and preserves id / addedAt"
89
+ },
90
+ {
91
+ "id": "TC-215-decisions-update-wellformed",
92
+ "acId": "AC-17302-2",
93
+ "description": "decisions update patches options and default so decisions:wellFormed shape passes (two options + a default).",
94
+ "status": "pending",
95
+ "testPointer": "test/define/ledgers.test.js::updateEntry (AC-17302-2): decisions update patches options and default and passes wellFormed shape"
96
+ },
97
+ {
98
+ "id": "TC-215-resolvedby-grammar-each-form",
99
+ "acId": "AC-17302-3",
100
+ "description": "Each resolvedBy pointer form (REQ-nnn, TAD.entity:<name>, PRD.user:<name>, TAD.system:<name>, TAC-nnnn, omitted:<reason>) resolves on the fixture and D2's skeleton:resolvedBy passes it.",
101
+ "status": "pending",
102
+ "testPointer": "test/query/gates.test.js::gates (REQ-173, AC-17302-3): each pointer form resolves on the fixture"
103
+ },
104
+ {
105
+ "id": "TC-215-update-refuses-nongrammar",
106
+ "acId": "AC-17302-4",
107
+ "description": "brief update --resolved-by with a free-text pointer exits 2 naming the grammar and the ledger is unchanged.",
108
+ "status": "pending",
109
+ "testPointer": "test/cli/ledger.test.js::ledger CLI (AC-17302-4): brief update --resolved-by outside the grammar exits 2 and writes nothing"
110
+ },
111
+ {
112
+ "id": "TC-215-d2-dangling-pointer-fails",
113
+ "acId": "AC-17302-5",
114
+ "description": "A statement with resolvedBy REQ-999 on a tree with no REQ-999 fails skeleton:resolvedBy with 'pointer does not resolve'.",
115
+ "status": "pending",
116
+ "testPointer": "test/query/gates.test.js::gates (REQ-173, AC-17302-5): REQ-999 fails with \"pointer does not resolve\""
117
+ },
118
+ {
119
+ "id": "TC-215-d2-title-hit-dropped",
120
+ "acId": "AC-17302-6",
121
+ "description": "In 0.30.0 skeleton:resolvedBy no longer passes a statement on a REQ-title text hit alone; a resolvedBy pointer is required.",
122
+ "status": "pending",
123
+ "testPointer": "test/query/gates.test.js::gates (REQ-173, AC-17302-6): a text-title hit alone does NOT pass in 0.30.0"
124
+ },
125
+ {
126
+ "id": "TC-215-markers-kind-and-source",
127
+ "acId": "AC-18701-1",
128
+ "description": "parseBriefFromFile parses a leading [kind] and a trailing (source: ...) marker; the CLI brief add --from mints a statement with that kind, text and source.",
129
+ "status": "pending",
130
+ "testPointer": "test/define/ledgers.test.js::parseBriefFromFile (AC-18701-1): leading [kind] and trailing (source: ...) markers mint one statement"
131
+ },
132
+ {
133
+ "id": "TC-215-defaults-from-flags",
134
+ "acId": "AC-18701-2",
135
+ "description": "A line without markers inherits --kind and --source from CLI flags.",
136
+ "status": "pending",
137
+ "testPointer": "test/define/ledgers.test.js::parseBriefFromFile (AC-18701-2): a line without markers inherits --kind and --source"
138
+ },
139
+ {
140
+ "id": "TC-215-question-heuristic",
141
+ "acId": "AC-18701-3",
142
+ "description": "A trailing '?' or a TBC/TBD/Open:/Question: prefix with no [kind] marker kinds the statement openQuestion.",
143
+ "status": "pending",
144
+ "testPointer": "test/define/ledgers.test.js::parseBriefFromFile (AC-18701-3): a question-mark trailing line is kinded openQuestion"
145
+ },
146
+ {
147
+ "id": "TC-215-029-line-per-statement-unchanged",
148
+ "acId": "AC-18701-4",
149
+ "description": "A 0.29.0 line-per-statement file (no markers) parses to the same drafts as the 0.29.0 code path produced.",
150
+ "status": "pending",
151
+ "testPointer": "test/define/ledgers.test.js::parseBriefFromFile (AC-18701-4): a 0.29.0 line-per-statement file parses unchanged"
152
+ },
153
+ {
154
+ "id": "TC-215-unknown-kind-exits-2",
155
+ "acId": "AC-18701-5",
156
+ "description": "A line with an unknown [kind] exits 2 naming the accepted kinds and writes nothing to the ledger.",
157
+ "status": "pending",
158
+ "testPointer": "test/cli/ledger.test.js::ledger CLI (AC-18701-5): brief add --from with an unknown [kind] exits 2 before writing"
159
+ },
160
+ {
161
+ "id": "TC-215-dry-run-no-write",
162
+ "acId": "AC-18701-6",
163
+ "description": "brief add --from --dry-run never creates or modifies rcf/define/brief-ledger.json.",
164
+ "status": "pending",
165
+ "testPointer": "test/cli/ledger.test.js::ledger CLI (AC-18701-6, --dry-run): writes nothing"
166
+ },
167
+ {
168
+ "id": "TC-215-scan-mints-openquestion",
169
+ "acId": "AC-18702-1",
170
+ "description": "A new statement that the contradiction scan flags against an existing statement adds one openQuestion statement with source scan:contradiction:<id>,<id>.",
171
+ "status": "pending",
172
+ "testPointer": "test/cli/ledger.test.js::ledger CLI (AC-18702-1): mechanical scan on brief add mints an openQuestion with scan: source"
173
+ },
174
+ {
175
+ "id": "TC-215-findings-mints-openquestions",
176
+ "acId": "AC-18702-2",
177
+ "description": "--findings <path> accepts rcf discover intake --input shape and mints one openQuestion per finding with source scan:<name>.",
178
+ "status": "pending",
179
+ "testPointer": "test/cli/ledger.test.js::ledger CLI (AC-18702-2): --findings file mints one openQuestion per finding with scan: source"
180
+ },
181
+ {
182
+ "id": "TC-215-scans-compare-every-existing",
183
+ "acId": "AC-18702-3",
184
+ "description": "runIntakeScansOnDelta compares every new statement against every existing statement (the frozen set is every statement).",
185
+ "status": "pending",
186
+ "testPointer": "test/intake/validate.test.js::runIntakeScansOnDelta (AC-18702-3): on a frozen set the comparison set is every existing statement"
187
+ },
188
+ {
189
+ "id": "TC-215-json-emits-added-and-findings",
190
+ "acId": "AC-18702-4",
191
+ "description": "brief add --json emits { added: [...], findings: [...] } on stdout.",
192
+ "status": "pending",
193
+ "testPointer": "test/cli/ledger.test.js::ledger CLI (AC-18702-4, --json): emits { added, findings }"
194
+ },
195
+ {
196
+ "id": "TC-215-no-scan-plus-findings-exits-2",
197
+ "acId": "AC-18702-5",
198
+ "description": "--no-scan combined with --findings exits 2 naming the conflict.",
199
+ "status": "pending",
200
+ "testPointer": "test/cli/ledger.test.js::ledger CLI (AC-18702-5): --no-scan with --findings exits 2"
201
+ },
202
+ {
203
+ "id": "TC-215-text-runs-no-scan",
204
+ "acId": "AC-18702-6",
205
+ "description": "brief add --text runs no scan and appends no openQuestion statement.",
206
+ "status": "pending",
207
+ "testPointer": "test/cli/ledger.test.js::ledger CLI (AC-18702-6): --text runs no scan and appends no openQuestion"
64
208
  }
65
209
  ],
66
210
  "status": "draft"
@@ -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
  "purpose": "Cover the DEFINE stage-gate check functions D1..D8 (AC-17401-1..8) with unit tests over hand-built TreeModel and ledger fixtures.",
5
5
  "testLevel": "unit",
6
6
  "acIds": [
@@ -11,7 +11,9 @@
11
11
  "AC-17401-5",
12
12
  "AC-17401-6",
13
13
  "AC-17401-7",
14
- "AC-17401-8"
14
+ "AC-17401-8",
15
+ "AC-17401-9",
16
+ "AC-17401-10"
15
17
  ],
16
18
  "id": "TS-216",
17
19
  "usId": "US-17401",
@@ -72,7 +74,21 @@
72
74
  "description": "checkD8Freeze asserts prior stages passed/acknowledged, every AC owned by exactly one FBS, computeQueue nextActionable not null, validateErrors empty.",
73
75
  "status": "pending",
74
76
  "testPointer": "test/query/gates.test.js::gates: D8 tree-wide freeze checks"
77
+ },
78
+ {
79
+ "id": "TC-216-d2-data-architecture",
80
+ "acId": "AC-17401-9",
81
+ "description": "checkD2Skeleton reads tad.dataArchitecture.{dataStores,coreEntities} per rcf-schemas 0.6.3; a tree with populated dataArchitecture passes skeleton:tadPersistence and empty/missing/wrong-top-level trees fail with the schema-anchored ids.",
82
+ "status": "pending",
83
+ "testPointer": "test/query/gates.test.js::gates: D2 skeleton:tadPersistence reads tad.dataArchitecture.* per schema 0.6.3"
84
+ },
85
+ {
86
+ "id": "TC-216-identity-seed-surface",
87
+ "acId": "AC-17401-10",
88
+ "description": "IDENTITY_TEMPLATE carries a '## Surface' section between '## Register' and '## Project-scoped notes' naming viewer/runningApp/prDiff and seeded to 'prDiff'; writeIdentityTemplate on a fresh dir seeds a profile that satisfies checkD1Brief surface markers; an existing profile.md is left byte-identical (slice-1 'kept' contract).",
89
+ "status": "pending",
90
+ "testPointer": "test/setup/identity-register.test.js::IDENTITY_TEMPLATE carries a ## Surface heading between ## Register and ## Project-scoped notes"
75
91
  }
76
92
  ],
77
93
  "status": "draft"
78
- }
94
+ }
@@ -0,0 +1,78 @@
1
+ {
2
+ "createdAt": "2026-09-24T16:33:15Z",
3
+ "updatedAt": "2026-09-24T16:33:15Z",
4
+ "purpose": "Cover rcf define freeze (AC-17601-1..8) with CLI spawn tests over an initProject scratch tree; add a targeted test for the freeze-record override-nullable-required contract; add a targeted test that CHANGELOG.md and the readiness CLI stage header no longer carry the ' -- ' double-dash pattern this slice replaces.",
5
+ "testLevel": "unit",
6
+ "acIds": [
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-7",
14
+ "AC-17601-8"
15
+ ],
16
+ "id": "TS-218",
17
+ "usId": "US-17601",
18
+ "title": "rcf define freeze CLI + freeze-record override + hygiene",
19
+ "testCases": [
20
+ {
21
+ "id": "TC-218-happy",
22
+ "acId": "AC-17601-1",
23
+ "description": "On a scratch project seeded so computeReadiness returns freezeable=true (initProject + a minimal brief statement + profile markers + one deploy ADR + one REQ with US, AC classes and TAC + one FBS at the queue head), rcf define freeze exits 0, writes rcf/define/freeze.json with the required shape, and a follow-up computeDelta over the live tree + new record reports every list empty.",
24
+ "status": "pending",
25
+ "testPointer": "test/cli/freeze.test.js::freeze cli: happy path writes freeze.json and produces an empty delta"
26
+ },
27
+ {
28
+ "id": "TC-218-refuse",
29
+ "acId": "AC-17601-2",
30
+ "description": "On a scratch project that fails D1 (no brief statement), rcf define freeze exits 4, writes no freeze.json, and prints the failing-stage block + rcf define readiness --check brief hint on stderr.",
31
+ "status": "pending",
32
+ "testPointer": "test/cli/freeze.test.js::freeze cli: refuses with exit 4 on any failing stage and writes nothing"
33
+ },
34
+ {
35
+ "id": "TC-218-ack",
36
+ "acId": "AC-17601-3",
37
+ "description": "--ack define.shapes --reason 'templates deferred' is accepted, --ack define.brief --reason 'x' is a usage refusal (exit 2 with a message naming the accepted set), --ack without --reason is a usage refusal, and an acked D3 lands in freeze.gates as { state: 'acknowledged', at.hash: <currentTreeHash>, at.reason: 'templates deferred', failing: [...] } which the next readiness run reports as 'acknowledged'.",
38
+ "status": "pending",
39
+ "testPointer": "test/cli/freeze.test.js::freeze cli: --ack only accepts D3/D5/D6 and persists as acknowledged at hash"
40
+ },
41
+ {
42
+ "id": "TC-218-summary",
43
+ "acId": "AC-17601-4",
44
+ "description": "First-freeze summary matches 'first freeze at <shortHash>: <req> REQ, <us> stories, <ac> criteria, <interfaces> interfaces, <tac> TAC, <adr> ADR, <fbs> FBS.'; incremental-freeze summary (a second freeze after editing one US) matches 'frozen at <shortHash>: 0 REQ, 0 stories, 0 criteria, 0 interfaces added; <US-id> amended; 0 re-execute.'; --json emits { record, summary, delta }.",
45
+ "status": "pending",
46
+ "testPointer": "test/cli/freeze.test.js::freeze cli: summary line follows section 2.5 for first and incremental freezes"
47
+ },
48
+ {
49
+ "id": "TC-218-status",
50
+ "acId": "AC-17601-5",
51
+ "description": "--status on a never-frozen project prints 'never frozen' and exits 0 (--json: record null, delta unfrozen); --status on a frozen project prints the record block + delta summary line; --status runs no gates and never writes the record (mtime unchanged after --status).",
52
+ "status": "pending",
53
+ "testPointer": "test/cli/freeze.test.js::freeze cli: --status is read-only and reports the record + live delta"
54
+ },
55
+ {
56
+ "id": "TC-218-admissibility",
57
+ "acId": "AC-17601-6",
58
+ "description": "When runWithAdmissibilityGate returns 'refused-admissibility' (simulated by a chain-rulesetVersion mismatch or a construct-time refusal fixture), the CLI still runs the freeze compute and writes the record on freezeable=true; the refusal is a stderr [warn] line and never sets exit 4 on its own.",
59
+ "status": "pending",
60
+ "testPointer": "test/cli/freeze.test.js::freeze cli: admissibility refusal is informational, never a freeze refusal"
61
+ },
62
+ {
63
+ "id": "TC-218-override",
64
+ "acId": "AC-17601-7",
65
+ "description": "validateFreezeRecord({ ...validRecord, override: undefined }) throws FreezeRecordError with field 'override'; loadFreezeRecord defaults a missing override key to null on read; saveFreezeRecord refuses to write a body that omits override.",
66
+ "status": "pending",
67
+ "testPointer": "test/define/freeze-record.test.js::freeze-record: override is required (nullable) and the loader defaults missing keys to null"
68
+ },
69
+ {
70
+ "id": "TC-218-hygiene",
71
+ "acId": "AC-17601-8",
72
+ "description": "The readiness CLI stage header line uses a colon between stage id and state ('D1 (define.brief): failing') and never a ' -- ' double-dash; the CHANGELOG.md line for the TODO regex is likewise colon-punctuated; a grep for ' -- ' in the two touched files scoped to the slice-added lines returns no matches.",
73
+ "status": "pending",
74
+ "testPointer": "test/cli/freeze.test.js::freeze cli: readiness stage header and CHANGELOG no longer use ' -- '"
75
+ }
76
+ ],
77
+ "status": "draft"
78
+ }
@@ -0,0 +1,70 @@
1
+ {
2
+ "createdAt": "2026-10-01T14:30:00Z",
3
+ "updatedAt": "2026-10-01T14:30:00Z",
4
+ "purpose": "Cover US-17402: every entry in stages[].checks[] carries persona (productOwner | engineer) and a non-empty question string; CHECK_PERSONA / CHECK_QUESTION / STAGE_FALLBACK_PERSONA maps are total; the notApplicable placeholder uses the stage fallback (ADR-4126).",
5
+ "testLevel": "unit",
6
+ "acIds": [
7
+ "AC-17402-1",
8
+ "AC-17402-2",
9
+ "AC-17402-3",
10
+ "AC-17402-4",
11
+ "AC-17402-5",
12
+ "AC-17402-6",
13
+ "AC-17402-7"
14
+ ],
15
+ "id": "TS-219",
16
+ "usId": "US-17402",
17
+ "title": "Persona tag + question on every gate check",
18
+ "testCases": [
19
+ {
20
+ "id": "TC-219-every-check-has-persona-and-question",
21
+ "acId": "AC-17402-1",
22
+ "description": "For every stage function, every entry in checks[] carries persona (productOwner|engineer) and a non-empty question string.",
23
+ "status": "pending",
24
+ "testPointer": "test/query/gates.test.js::gates (ADR-4126, AC-17402-1): every check carries persona + question"
25
+ },
26
+ {
27
+ "id": "TC-219-d1-personas",
28
+ "acId": "AC-17402-2",
29
+ "description": "The four D1 check names (brief:sinceFreeze, brief:kinds, brief:openQuestions, brief:profile) carry persona 'productOwner' in CHECK_PERSONA.",
30
+ "status": "pending",
31
+ "testPointer": "test/query/gates.test.js::gates (ADR-4126): CHECK_PERSONA and CHECK_QUESTION cover every check name"
32
+ },
33
+ {
34
+ "id": "TC-219-d2-personas",
35
+ "acId": "AC-17402-3",
36
+ "description": "D2 personas: skeleton:resolvedBy + skeleton:reqIntent are productOwner; skeleton:reqShape, skeleton:tadPersistence, skeleton:deployAdr are engineer.",
37
+ "status": "pending",
38
+ "testPointer": "test/query/gates.test.js::gates (ADR-4126): CHECK_PERSONA and CHECK_QUESTION cover every check name"
39
+ },
40
+ {
41
+ "id": "TC-219-d4-d7-personas",
42
+ "acId": "AC-17402-4",
43
+ "description": "D4 personas: stories:reqHasUs productOwner, stories:usFloors engineer. D7 personas: decisions:wellFormed productOwner, decisions:allAnswered engineer.",
44
+ "status": "pending",
45
+ "testPointer": "test/query/gates.test.js::gates (ADR-4126): CHECK_PERSONA and CHECK_QUESTION cover every check name"
46
+ },
47
+ {
48
+ "id": "TC-219-engineer-stages",
49
+ "acId": "AC-17402-5",
50
+ "description": "D3 (shapes:*), D5 (crosscut:*), D6 (consistency:*) and D8 (freeze:*) checks are all engineer in CHECK_PERSONA.",
51
+ "status": "pending",
52
+ "testPointer": "test/query/gates.test.js::gates (ADR-4126): CHECK_PERSONA and CHECK_QUESTION cover every check name"
53
+ },
54
+ {
55
+ "id": "TC-219-persona-vocabulary-closed",
56
+ "acId": "AC-17402-6",
57
+ "description": "No check carries a persona value other than 'productOwner' or 'engineer', and no failing { id, why } entry carries its own persona field.",
58
+ "status": "pending",
59
+ "testPointer": "test/query/gates.test.js::gates (ADR-4126, AC-17402-1): every check carries persona + question"
60
+ },
61
+ {
62
+ "id": "TC-219-not-applicable-placeholder-persona",
63
+ "acId": "AC-17402-7",
64
+ "description": "A notApplicable stage emits one stage:<D>:scope placeholder check with ok true and persona equal to STAGE_FALLBACK_PERSONA[D].",
65
+ "status": "pending",
66
+ "testPointer": "test/query/gates.test.js::gates (ADR-4126, AC-17402-7): notApplicable placeholder carries stage fallback persona and ok true"
67
+ }
68
+ ],
69
+ "status": "draft"
70
+ }
@@ -0,0 +1,78 @@
1
+ {
2
+ "createdAt": "2026-10-01T14:30:00Z",
3
+ "updatedAt": "2026-10-01T14:30:00Z",
4
+ "purpose": "Cover US-17403: the skeleton:reqFields split into reqIntent + reqShape, the decisions:allAnswered split into wellFormed + allAnswered, and the new D3 shapes:draftSettled check for interface descriptions carrying the [draft] marker (ADR-4126).",
5
+ "testLevel": "unit",
6
+ "acIds": [
7
+ "AC-17403-1",
8
+ "AC-17403-2",
9
+ "AC-17403-3",
10
+ "AC-17403-4",
11
+ "AC-17403-5",
12
+ "AC-17403-6",
13
+ "AC-17403-7",
14
+ "AC-17403-8"
15
+ ],
16
+ "id": "TS-220",
17
+ "usId": "US-17403",
18
+ "title": "Split checks and the D3 draft marker",
19
+ "testCases": [
20
+ {
21
+ "id": "TC-220-todo-no-shapes-fails-both",
22
+ "acId": "AC-17403-1",
23
+ "description": "A REQ with a TODO description and no shapeClassification fails skeleton:reqIntent for the description AND skeleton:reqShape for the missing shapes.",
24
+ "status": "pending",
25
+ "testPointer": "test/query/gates.test.js::gates (ADR-4126, AC-17403-1): TODO description + missing shapes fails BOTH reqIntent AND reqShape on same REQ"
26
+ },
27
+ {
28
+ "id": "TC-220-shapes-no-domain-fails-req-intent-only",
29
+ "acId": "AC-17403-2",
30
+ "description": "A REQ with description and shapes but no domain fails skeleton:reqIntent (domain missing) and passes skeleton:reqShape.",
31
+ "status": "pending",
32
+ "testPointer": "test/query/gates.test.js::gates (ADR-4126, AC-17403-2): shapes present + no domain fails reqIntent only"
33
+ },
34
+ {
35
+ "id": "TC-220-draft-fails-draft-settled",
36
+ "acId": "AC-17403-3",
37
+ "description": "A TAC whose only interface description starts with [draft] passes shapes:tacHasInterface and fails shapes:draftSettled with id <tacId>:<name>.",
38
+ "status": "pending",
39
+ "testPointer": "test/query/gates.test.js::gates (ADR-4126, AC-17403-3 / 4): draft interface fails draftSettled, passes tacHasInterface"
40
+ },
41
+ {
42
+ "id": "TC-220-marker-removed-passes-draft-settled",
43
+ "acId": "AC-17403-4",
44
+ "description": "After the [draft] marker is removed from the interface description, shapes:draftSettled passes it.",
45
+ "status": "pending",
46
+ "testPointer": "test/query/gates.test.js::gates (ADR-4126, AC-17403-3 / 4): draft interface fails draftSettled, passes tacHasInterface"
47
+ },
48
+ {
49
+ "id": "TC-220-draft-kind-vocabulary-still-applies",
50
+ "acId": "AC-17403-5",
51
+ "description": "A [draft] interface whose kind is not in INTERFACE_KINDS fails shapes:kindVocabulary exactly as a settled interface would.",
52
+ "status": "pending",
53
+ "testPointer": "test/query/gates.test.js::gates (ADR-4126, AC-17403-5): kindVocabulary applies to drafts just like settled interfaces"
54
+ },
55
+ {
56
+ "id": "TC-220-enumerated-passes-well-formed-fails-all-answered",
57
+ "acId": "AC-17403-6",
58
+ "description": "An open decision with a question, two options and a default naming one of them passes decisions:wellFormed and fails decisions:allAnswered.",
59
+ "status": "pending",
60
+ "testPointer": "test/query/gates.test.js::gates (ADR-4126, AC-17403-6): enumerated open decision passes wellFormed, fails allAnswered"
61
+ },
62
+ {
63
+ "id": "TC-220-one-option-no-default-fails-well-formed",
64
+ "acId": "AC-17403-7",
65
+ "description": "A decisions-ledger entry with one option and no default fails decisions:wellFormed with 'decision is not enumerated (question, two or more options, a default)'.",
66
+ "status": "pending",
67
+ "testPointer": "test/query/gates.test.js::gates (ADR-4126, AC-17403-7): one option, no default fails wellFormed"
68
+ },
69
+ {
70
+ "id": "TC-220-no-req-fields-emitted",
71
+ "acId": "AC-17403-8",
72
+ "description": "No check named skeleton:reqFields is emitted; the stage envelope shape (stage, gate, state, checks) is unchanged.",
73
+ "status": "pending",
74
+ "testPointer": "test/query/gates.test.js::gates (ADR-4126, AC-17403-8): no check named skeleton:reqFields is emitted"
75
+ }
76
+ ],
77
+ "status": "draft"
78
+ }
@@ -0,0 +1,78 @@
1
+ {
2
+ "createdAt": "2026-10-01T14:30:00Z",
3
+ "updatedAt": "2026-10-01T14:30:00Z",
4
+ "purpose": "Cover US-17502: computeReadiness folds levels.intentComplete and levels.readyToBuild plus personas.productOwner and personas.engineer from stages[].checks[]; the folds are additive and no file under rcf/ is written (ADR-4126).",
5
+ "testLevel": "unit",
6
+ "acIds": [
7
+ "AC-17502-1",
8
+ "AC-17502-2",
9
+ "AC-17502-3",
10
+ "AC-17502-4",
11
+ "AC-17502-5",
12
+ "AC-17502-6",
13
+ "AC-17502-7",
14
+ "AC-17502-8"
15
+ ],
16
+ "id": "TS-221",
17
+ "usId": "US-17502",
18
+ "title": "Two readiness levels folded on one object",
19
+ "testCases": [
20
+ {
21
+ "id": "TC-221-po-ok-engineer-failing",
22
+ "acId": "AC-17502-1",
23
+ "description": "A tree where every productOwner check is ok and at least one engineer check fails has levels.intentComplete.ok true and levels.readyToBuild.ok false.",
24
+ "status": "pending",
25
+ "testPointer": "test/query/readiness.test.js::readiness (ADR-4126, AC-17502-1): PO ok + engineer failing => L1 ok, L2 not ok"
26
+ },
27
+ {
28
+ "id": "TC-221-freezeable-implies-l1",
29
+ "acId": "AC-17502-2",
30
+ "description": "A tree where freezeable is true has levels.readyToBuild.ok true and levels.intentComplete.ok true.",
31
+ "status": "pending",
32
+ "testPointer": "test/query/readiness.test.js::readiness: freezeable is true on a well-formed tree (every stage passed / notApplicable)"
33
+ },
34
+ {
35
+ "id": "TC-221-brief-profile-l1-blocker",
36
+ "acId": "AC-17502-3",
37
+ "description": "A tree where brief:profile fails has levels.intentComplete.ok false and a single blocker for D1 brief:profile with persona productOwner and ids profile:surface and profile:register.",
38
+ "status": "pending",
39
+ "testPointer": "test/query/readiness.test.js::readiness (ADR-4126, AC-17502-3): brief:profile failing yields L1 blocker and PO next action"
40
+ },
41
+ {
42
+ "id": "TC-221-acknowledged-absent-from-l2",
43
+ "acId": "AC-17502-4",
44
+ "description": "An engineer failure inside a D3 stage acknowledged at the current hash is absent from levels.readyToBuild.blockedBy.",
45
+ "status": "pending",
46
+ "testPointer": "test/query/readiness.test.js::readiness (ADR-4126, AC-17502-4): acknowledged D3 engineer failure is absent from readyToBuild.blockedBy"
47
+ },
48
+ {
49
+ "id": "TC-221-personas-mirror-levels",
50
+ "acId": "AC-17502-5",
51
+ "description": "personas.productOwner.blockers deep-equals levels.intentComplete.blockedBy and levels.readyToBuild.nextAction deep-equals nextAction.",
52
+ "status": "pending",
53
+ "testPointer": "test/query/readiness.test.js::readiness (ADR-4126, AC-17502-5): personas.productOwner.blockers deep-equals L1 blockedBy; readyToBuild.nextAction equals nextAction"
54
+ },
55
+ {
56
+ "id": "TC-221-persona-next-action-picks-first-failing-stage",
57
+ "acId": "AC-17502-6",
58
+ "description": "With engineer failures in D2 and D4 and a PO failure in D4 only, personas.productOwner.nextAction names D4 and personas.engineer.nextAction names D2.",
59
+ "status": "pending",
60
+ "testPointer": "test/query/readiness.test.js::readiness (ADR-4126, AC-17502-6): PO-nextAction prefers first PO-failing stage; engineer-nextAction prefers first engineer-failing stage"
61
+ },
62
+ {
63
+ "id": "TC-221-no-write-on-invocation",
64
+ "acId": "AC-17502-7",
65
+ "description": "readiness cli (text and --json) does not create or modify any file under rcf/; the existing readiness cli test suite TS-217 continues to pass unchanged.",
66
+ "status": "pending",
67
+ "testPointer": "test/cli/readiness.test.js::readiness cli: AC-17502-7 rcf/ tree is byte-stable across a readiness run (no mutation)"
68
+ },
69
+ {
70
+ "id": "TC-221-backwards-compat-fields",
71
+ "acId": "AC-17502-8",
72
+ "description": "Every 0.28.4 top-level field (tree, delta, stages, nextAction, coverage, decisions, freezeable) is present on the 0.29.0 result with its 0.28.4 type.",
73
+ "status": "pending",
74
+ "testPointer": "test/query/readiness.test.js::readiness (ADR-4126, AC-17502-8): 0.28.4 fields present with their types"
75
+ }
76
+ ],
77
+ "status": "draft"
78
+ }