rcf-lite 0.30.0 → 0.31.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 (52) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/fixtures/canary-manifest.json +9 -9
  3. package/guidance/define-draft-shapes.md +15 -10
  4. package/package.json +1 -1
  5. package/rcf/adrs/adr-4131-gates-bite-ack-recorded-override.json +3 -3
  6. package/rcf/adrs/adr-4137-standalone-theme-persistence.json +30 -0
  7. package/rcf/adrs/adr-4138-tree-wide-checks-before-scope-shortcircuit.json +35 -0
  8. package/rcf/code-nodes/cn-771.json +14 -0
  9. package/rcf/code-nodes/cn-772.json +14 -0
  10. package/rcf/code-nodes/cn-773.json +16 -0
  11. package/rcf/code-nodes/cn-774.json +20 -0
  12. package/rcf/code-nodes/cn-775.json +15 -0
  13. package/rcf/code-nodes/cn-776.json +17 -0
  14. package/rcf/code-nodes/cn-777.json +21 -0
  15. package/rcf/fbs/fbs-202.json +18 -2
  16. package/rcf/fbs/fbs-203.json +12 -4
  17. package/rcf/requirements/req-002.json +2 -2
  18. package/rcf/requirements/req-173.json +2 -2
  19. package/rcf/requirements/req-174.json +2 -2
  20. package/rcf/tacs/tac-4122-define-gates.json +7 -2
  21. package/rcf/test-suites/ts-007.json +1 -1
  22. package/rcf/test-suites/ts-215.json +64 -1
  23. package/rcf/test-suites/ts-216.json +18 -2
  24. package/rcf/test-suites/ts-219.json +10 -2
  25. package/rcf/test-suites/ts-220.json +18 -2
  26. package/rcf/test-suites/ts-225.json +10 -2
  27. package/rcf/test-suites/ts-229.json +49 -3
  28. package/rcf/test-suites/ts-230.json +26 -2
  29. package/rcf/test-suites/ts-231.json +16 -1
  30. package/rcf/test-suites/ts-236.json +44 -0
  31. package/rcf/user-stories/us-17302.json +36 -1
  32. package/rcf/user-stories/us-17401.json +11 -1
  33. package/rcf/user-stories/us-17402.json +6 -1
  34. package/rcf/user-stories/us-17403.json +11 -1
  35. package/rcf/user-stories/us-17404.json +16 -1
  36. package/rcf/user-stories/us-17405.json +7 -2
  37. package/rcf/user-stories/us-205.json +6 -1
  38. package/rcf/user-stories/us-206.json +25 -4
  39. package/rcf/user-stories/us-207.json +36 -0
  40. package/releases/releases.yaml +11 -1
  41. package/src/cli/create.js +22 -2
  42. package/src/cli/ledger.js +96 -4
  43. package/src/cli/readiness.js +15 -1
  44. package/src/core/errors/index.js +7 -1
  45. package/src/core/store/writer.js +181 -13
  46. package/src/define/ledgers.js +86 -7
  47. package/src/mcp/tools.js +1 -1
  48. package/src/query/gates.js +383 -150
  49. package/src/view/html-page.js +14 -2
  50. package/src/view/page-init.js +149 -8
  51. package/src/view/style.css +97 -18
  52. package/src/view/view-index.js +22 -0
@@ -15,7 +15,7 @@
15
15
  "acId": "AC-302-2",
16
16
  "description": "create with a conflicting id returns a clear conflict error and writes nothing",
17
17
  "status": "pending",
18
- "testPointer": "test/core/store/writer.test.js::createDocument refuses on id collision (exit 2) and writes nothing (AC-302-2)"
18
+ "testPointer": "test/core/store/writer.test.js::createDocument refuses on id collision with different content (exit 3 conflict) and writes nothing (AC-302-2 / R1 extension 2026-10-05)"
19
19
  },
20
20
  {
21
21
  "id": "TC-007-create-writes-validating-child",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "createdAt": "2026-09-24T12:00:00Z",
3
- "updatedAt": "2026-10-02T16:40:00Z",
3
+ "updatedAt": "2026-10-05T19:00:00Z",
4
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": [
@@ -14,6 +14,13 @@
14
14
  "AC-17302-4",
15
15
  "AC-17302-5",
16
16
  "AC-17302-6",
17
+ "AC-17302-7",
18
+ "AC-17302-8",
19
+ "AC-17302-9",
20
+ "AC-17302-10",
21
+ "AC-17302-11",
22
+ "AC-17302-12",
23
+ "AC-17302-13",
17
24
  "AC-18701-1",
18
25
  "AC-18701-2",
19
26
  "AC-18701-3",
@@ -205,6 +212,62 @@
205
212
  "description": "brief add --text runs no scan and appends no openQuestion statement.",
206
213
  "status": "pending",
207
214
  "testPointer": "test/cli/ledger.test.js::ledger CLI (AC-18702-6): --text runs no scan and appends no openQuestion"
215
+ },
216
+ {
217
+ "id": "TC-215-r1-add-same-id-same-content-unchanged",
218
+ "acId": "AC-17302-7",
219
+ "description": "brief add --id 3 with identical content on a ledger whose entry 3 already matches exits 0 and prints 'unchanged'; --json emits {status:unchanged,id:3}; the ledger is not rewritten.",
220
+ "status": "pending",
221
+ "testPointer": "test/cli/ledger.test.js::ledger CLI (R1, AC-17302-7): add --id on same-content is unchanged exit 0"
222
+ },
223
+ {
224
+ "id": "TC-215-r1-add-same-id-diff-content-exit-3",
225
+ "acId": "AC-17302-8",
226
+ "description": "brief add --id 3 with different content exits 3; stderr names the id and the differing fields; the ledger is not rewritten.",
227
+ "status": "pending",
228
+ "testPointer": "test/cli/ledger.test.js::ledger CLI (R1, AC-17302-8): add --id on different-content exits 3 naming fields"
229
+ },
230
+ {
231
+ "id": "TC-215-r1-add-no-id-mints-next",
232
+ "acId": "AC-17302-9",
233
+ "description": "brief add --text with no --id mints the next id (idempotency opt-in is id-carried; the harness threads --id back on replay).",
234
+ "status": "pending",
235
+ "testPointer": "test/cli/ledger.test.js::ledger CLI (R1, AC-17302-9): add without --id mints next id"
236
+ },
237
+ {
238
+ "id": "TC-215-r1-create-ac-id-unchanged-and-conflict",
239
+ "acId": "AC-17302-10",
240
+ "description": "rcf define create ac --parent US-101 --id AC-101-1 replayed with identical content exits 0 printing 'AC-101-1: unchanged (rcf/user-stories/us-101.json)' and leaves the US file byte-identical; the same verb with a different --description exits 3 naming AC-101-1 and description and leaves the file byte-identical.",
241
+ "status": "pending",
242
+ "testPointer": "test/cli/create.test.js::create CLI (R1 extension, AC-17302-10): create ac --id replay is unchanged exit 0, different content exits 3"
243
+ },
244
+ {
245
+ "id": "TC-215-r1-create-tc-id-unchanged-and-conflict",
246
+ "acId": "AC-17302-11",
247
+ "description": "rcf define create tc --id replayed with identical content exits 0 printing the unchanged line and leaves the TS file byte-identical; a different --description exits 3 naming description; a derived-slug collision without --id still exits 2.",
248
+ "status": "pending",
249
+ "testPointer": "test/cli/create.test.js::create CLI (R1 extension, AC-17302-11): create tc --id replay is unchanged exit 0, different content exits 3"
250
+ },
251
+ {
252
+ "id": "TC-215-r1-create-cn-id-unchanged-and-conflict",
253
+ "acId": "AC-17302-12",
254
+ "description": "rcf define create cn --id replayed with identical content exits 0 printing the unchanged line and leaves the CN file byte-identical; a different --path exits 3 naming path.",
255
+ "status": "pending",
256
+ "testPointer": "test/cli/create.test.js::create CLI (R1 extension, AC-17302-12): create cn --id replay is unchanged exit 0, different content exits 3"
257
+ },
258
+ {
259
+ "id": "TC-215-r1-create-req-verbatim-replay-unchanged",
260
+ "acId": "AC-17302-13",
261
+ "description": "rcf define create req --id REQ-050 replayed verbatim after the classifier stamped shapeClassification exits 0 printing the unchanged line; a different --description exits 3 naming description.",
262
+ "status": "pending",
263
+ "testPointer": "test/cli/create.test.js::create CLI (R1 extension, AC-17302-13): create req --id verbatim replay is unchanged despite classifier stamp"
264
+ },
265
+ {
266
+ "id": "TC-215-r1-create-tac-id-unchanged-and-conflict",
267
+ "acId": "AC-17302-13",
268
+ "description": "rcf define create tac --id replayed with identical content exits 0 printing the unchanged line; a different --purpose exits 3 naming purpose (document-kind path, no post-create side effect).",
269
+ "status": "pending",
270
+ "testPointer": "test/cli/create.test.js::create CLI (R1 extension, AC-17302-13): create tac --id replay is unchanged exit 0, different content exits 3"
208
271
  }
209
272
  ],
210
273
  "status": "draft"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "createdAt": "2026-09-24T14:30:00Z",
3
- "updatedAt": "2026-10-01T13:12:16Z",
3
+ "updatedAt": "2026-10-05T18:00:00Z",
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": [
@@ -13,7 +13,9 @@
13
13
  "AC-17401-7",
14
14
  "AC-17401-8",
15
15
  "AC-17401-9",
16
- "AC-17401-10"
16
+ "AC-17401-10",
17
+ "AC-17401-11",
18
+ "AC-17401-12"
17
19
  ],
18
20
  "id": "TS-216",
19
21
  "usId": "US-17401",
@@ -88,6 +90,20 @@
88
90
  "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
91
  "status": "pending",
90
92
  "testPointer": "test/setup/identity-register.test.js::IDENTITY_TEMPLATE carries a ## Surface heading between ## Register and ## Project-scoped notes"
93
+ },
94
+ {
95
+ "id": "TC-216-r13-crosscut-security-tree-wide",
96
+ "acId": "AC-17401-11",
97
+ "description": "A D5 scope narrowed so no REQ is in scope but the tree carries an auth or httpApi REQ with TAD.securityArchitecture empty still fails crosscut:securityArchitecture; stage state is failing (not notApplicable) via the ADR-4138 shared helper.",
98
+ "status": "pending",
99
+ "testPointer": "test/query/gates.test.js::gates (R13, AC-17401-11): crosscut:securityArchitecture runs tree-wide under narrowed D5 scope"
100
+ },
101
+ {
102
+ "id": "TC-216-r13-crosscut-operational-tree-wide",
103
+ "acId": "AC-17401-12",
104
+ "description": "A D5 scope narrowed so no REQ is in scope but the tree carries an AC with the '[deployed]' marker and TAD.operationalConcerns empty still fails crosscut:operationalConcerns; stage state is failing (not notApplicable) via the ADR-4138 shared helper.",
105
+ "status": "pending",
106
+ "testPointer": "test/query/gates.test.js::gates (R13, AC-17401-12): crosscut:operationalConcerns runs tree-wide under narrowed D5 scope"
91
107
  }
92
108
  ],
93
109
  "status": "draft"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "createdAt": "2026-10-01T14:30:00Z",
3
- "updatedAt": "2026-10-01T14:30:00Z",
3
+ "updatedAt": "2026-10-05T18:00:00Z",
4
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
5
  "testLevel": "unit",
6
6
  "acIds": [
@@ -10,7 +10,8 @@
10
10
  "AC-17402-4",
11
11
  "AC-17402-5",
12
12
  "AC-17402-6",
13
- "AC-17402-7"
13
+ "AC-17402-7",
14
+ "AC-17402-8"
14
15
  ],
15
16
  "id": "TS-219",
16
17
  "usId": "US-17402",
@@ -64,6 +65,13 @@
64
65
  "description": "A notApplicable stage emits one stage:<D>:scope placeholder check with ok true and persona equal to STAGE_FALLBACK_PERSONA[D].",
65
66
  "status": "pending",
66
67
  "testPointer": "test/query/gates.test.js::gates (ADR-4126, AC-17402-7): notApplicable placeholder carries stage fallback persona and ok true"
68
+ },
69
+ {
70
+ "id": "TC-219-r13-deploy-adr-tree-wide",
71
+ "acId": "AC-17402-8",
72
+ "description": "A D2 scope narrowed so no REQ, PRD, TAD or resolving brief statement is in scope but no Deploy ADR exists tree-wide still fails skeleton:deployAdr; stage state is failing (not notApplicable) via the ADR-4138 shared helper.",
73
+ "status": "pending",
74
+ "testPointer": "test/query/gates.test.js::gates (R13, AC-17402-8): skeleton:deployAdr runs tree-wide under narrowed D2 scope"
67
75
  }
68
76
  ],
69
77
  "status": "draft"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "createdAt": "2026-10-01T14:30:00Z",
3
- "updatedAt": "2026-10-01T14:30:00Z",
3
+ "updatedAt": "2026-10-05T18:00:00Z",
4
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
5
  "testLevel": "unit",
6
6
  "acIds": [
@@ -11,7 +11,9 @@
11
11
  "AC-17403-5",
12
12
  "AC-17403-6",
13
13
  "AC-17403-7",
14
- "AC-17403-8"
14
+ "AC-17403-8",
15
+ "AC-17403-9",
16
+ "AC-17403-10"
15
17
  ],
16
18
  "id": "TS-220",
17
19
  "usId": "US-17403",
@@ -72,6 +74,20 @@
72
74
  "description": "No check named skeleton:reqFields is emitted; the stage envelope shape (stage, gate, state, checks) is unchanged.",
73
75
  "status": "pending",
74
76
  "testPointer": "test/query/gates.test.js::gates (ADR-4126, AC-17403-8): no check named skeleton:reqFields is emitted"
77
+ },
78
+ {
79
+ "id": "TC-220-r2-draft-tree-wide-under-narrowed-scope",
80
+ "acId": "AC-17403-9",
81
+ "description": "A D3 scope that excludes every TAC and shaped REQ still reports a [draft] marker on a TAC OUTSIDE the narrowed scope through shapes:draftSettled (stage state failing, not notApplicable) via the ADR-4138 shared tree-wide-before-scope helper; the same test asserted against pre-R2 gates.js (origin/main d8adedff^) returns notApplicable instead.",
82
+ "status": "pending",
83
+ "testPointer": "test/query/gates.test.js::gates (R2, AC-17403-9): draftSettled runs tree-wide under narrowed D3 scope"
84
+ },
85
+ {
86
+ "id": "TC-220-r13-failing-envelope-reason-drops",
87
+ "acId": "AC-17403-10",
88
+ "description": "The ADR-4138 helper returns a failing envelope with no reason field; the readiness CLI prints 'D3 (define.shapes): failing' without a '(no TAC ... in scope)' trailer when a tree-wide check fails under a scope-empty stage.",
89
+ "status": "pending",
90
+ "testPointer": "test/query/gates.test.js::gates (PR 292 follow-up, AC-17403-10): failing envelope carries no notApplicable reason text"
75
91
  }
76
92
  ],
77
93
  "status": "draft"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "createdAt": "2026-10-03T00:00:00Z",
3
- "updatedAt": "2026-10-03T00:00:00Z",
3
+ "updatedAt": "2026-10-05T12:30:00Z",
4
4
  "purpose": "Cover US-205 (engineer jumps to any document or AC by id): id-first ranking (exact / prefix / contains), word-match title above snippet, single-char ids-only, hash pick lands and expands the entity, mount URL round-trip, embed/theme preservation, empty-state on fetch failure, no outbound postMessage / storage / cookies. Points at the 22 new unit tests under test/view/id-lookup.test.js.",
5
5
  "testLevel": "unit",
6
6
  "acIds": [
@@ -11,7 +11,8 @@
11
11
  "AC-205-5",
12
12
  "AC-205-6",
13
13
  "AC-205-7",
14
- "AC-205-8"
14
+ "AC-205-8",
15
+ "AC-205-9"
15
16
  ],
16
17
  "id": "TS-225",
17
18
  "usId": "US-205",
@@ -72,6 +73,13 @@
72
73
  "description": "wireLookup never calls window.postMessage, never writes to localStorage / sessionStorage / document.cookie, and makes no outbound fetch other than `./index.json`; asserted by a source-level scan of page-init.js (no postMessage, no storage, no cookie writes in wireLookup).",
73
74
  "status": "pending",
74
75
  "testPointer": "test/view/id-lookup.test.js::page-init.js does not add outbound postMessage, localStorage, sessionStorage or cookies in the lookup wiring (AC-205-8)"
76
+ },
77
+ {
78
+ "id": "TC-225-search-button-contrast",
79
+ "acId": "AC-205-9",
80
+ "description": "The WCAG 2.1 AA contrast audit (test/view/contrast-aa.test.js) requires a `.rcf-search-btn` pair for each of hover, focus-visible and active (state rules merged over the base rule) in both the light and dark token sets and asserts >= 4.5:1 for the button text and >= 3:1 for the focus ring against the surface it sits on. A missing state pair fails the test (PR 291 landing review F3).",
81
+ "status": "pending",
82
+ "testPointer": "test/view/contrast-aa.test.js::.rcf-search-btn passes WCAG 2.1 AA in both themes across every state (AC-205-9)"
75
83
  }
76
84
  ],
77
85
  "status": "draft"
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "createdAt": "2026-10-03T09:55:00Z",
3
- "updatedAt": "2026-10-03T10:00:00Z",
4
- "purpose": "Cover US-206 (wespa's embedding contract is proved by a CI host fixture): the fixture renders a 56px header + resizable sidebar around an iframe pointed at ./?embed=1&theme=light with no inline script (AC-206-1), theme flips via postMessage without a reload (AC-206-2, source invariants + Playwright live proof in the lane evidence), embed and theme survive a hash-only in-iframe navigation (AC-206-3, source invariants + Playwright live proof), cross-origin messages are ignored by the viewer listener (AC-206-4), the three lints keep framing headers, target=_top and localStorage namespace in place (AC-206-5), and no new outbound postMessage shape is introduced by the viewer or the fixture (AC-206-6). All TCs resolve to node tests under test/view/wespa-host-fixture.test.js.",
3
+ "updatedAt": "2026-10-05T12:30:00Z",
4
+ "purpose": "Cover US-206 (wespa's embedding contract is proved by a CI host fixture): the fixture renders a 56px header + resizable sidebar around an iframe pointed at ./?embed=1&theme=light with no inline script (AC-206-1), theme flips via postMessage without a reload (AC-206-2, source invariants + Playwright live proof in the lane evidence), embed and theme survive a hash-only in-iframe navigation (AC-206-3, source invariants + Playwright live proof), cross-origin messages are ignored by the viewer listener (AC-206-4), the three lints keep framing headers, target=_top and localStorage namespace in place (AC-206-5), and no new outbound postMessage shape is introduced by the viewer or the fixture (AC-206-6). 2026-10-04 (w-2026-10-04-dave-001): extends coverage to the in-viewer three-state theme control (AC-206-7..10 under ADR-4137). All TCs resolve to node tests under test/view/wespa-host-fixture.test.js and test/view/theme-control.test.js. 2026-10-05 (PR 291 landing review F1): the boot theme is applied once; a `rcfPage.init()` re-run after an SSE swap never overrides a host postMessage theme or a theme-control choice.",
5
5
  "testLevel": "unit",
6
6
  "acIds": [
7
7
  "AC-206-1",
@@ -9,7 +9,11 @@
9
9
  "AC-206-3",
10
10
  "AC-206-4",
11
11
  "AC-206-5",
12
- "AC-206-6"
12
+ "AC-206-6",
13
+ "AC-206-7",
14
+ "AC-206-8",
15
+ "AC-206-9",
16
+ "AC-206-10"
13
17
  ],
14
18
  "id": "TS-229",
15
19
  "usId": "US-206",
@@ -77,6 +81,48 @@
77
81
  "description": "A grep over src/view/** (excluding test-host/embed-client.js, the sanctioned emitter) finds zero .postMessage( call sites; the embed-client itself posts exactly one shape, 'rcf-view-theme'.",
78
82
  "status": "pending",
79
83
  "testPointer": "test/view/wespa-host-fixture.test.js::AC-206-6: no outbound postMessage shape beyond rcf-view-theme is introduced by the viewer or the fixture"
84
+ },
85
+ {
86
+ "id": "TC-229-theme-control-renders-non-embed",
87
+ "acId": "AC-206-7",
88
+ "description": "renderPage renders a `[data-rcf-theme-control]` group with three buttons (Light, Dark, Auto; `aria-pressed`) right of the SearchButton in `.tools` when `data-embed` is absent; a click on a theme button sets `<html data-theme>` live and flips `aria-pressed` across the three.",
89
+ "status": "pending",
90
+ "testPointer": "test/view/theme-control.test.js::AC-206-7: renderPage includes the three-state theme control in non-embed; applyThemeControl updates data-theme and aria-pressed on click"
91
+ },
92
+ {
93
+ "id": "TC-229-theme-control-persists",
94
+ "acId": "AC-206-8",
95
+ "description": "In non-embed mode, selecting a theme writes `rcf-view:v1:theme` as `light`/`dark`/`auto` and the stored value is reapplied on the next boot; a `rcf-view-theme` postMessage still applies live but does not write the stored key; the boot precedence is `?theme=` -> stored -> auto.",
96
+ "status": "pending",
97
+ "testPointer": "test/view/theme-control.test.js::AC-206-8: non-embed persistence under rcf-view:v1:theme; postMessage path writes nothing"
98
+ },
99
+ {
100
+ "id": "TC-229-theme-control-absent-embed",
101
+ "acId": "AC-206-9",
102
+ "description": "renderPage with `data-embed=\"1\"` does not emit any `[data-rcf-theme-control]` markup; wireThemeControl under embed never reads or writes `rcf-view:v1:theme` on load, on a postMessage, or on any user action; the key is zero-touched (localStorage spy sees no setItem/getItem call for the key under embed).",
103
+ "status": "pending",
104
+ "testPointer": "test/view/theme-control.test.js::AC-206-9: embed=1 omits the control markup and does not touch rcf-view:v1:theme"
105
+ },
106
+ {
107
+ "id": "TC-229-theme-control-query-wins",
108
+ "acId": "AC-206-10",
109
+ "description": "In non-embed mode with a stored value `dark`, when the URL carries `?theme=light`, boot resolves to `light` (explicit wins), the Light button is pressed and the stored value is NOT overwritten (next load without a query reuses `dark`).",
110
+ "status": "pending",
111
+ "testPointer": "test/view/theme-control.test.js::AC-206-10: explicit ?theme= beats the stored value and leaves the key as-is"
112
+ },
113
+ {
114
+ "id": "TC-229-reinit-keeps-host-theme",
115
+ "acId": "AC-206-2",
116
+ "description": "Boot `?embed=1` with no `?theme=`, post `{ type: \"rcf-view-theme\", theme: \"dark\" }`, then call `rcfPage.init()` (the live-client SSE re-run): `<html data-theme>` stays `dark` and no storage is touched.",
117
+ "status": "pending",
118
+ "testPointer": "test/view/theme-control.test.js::PR 291 F1 regression: embed=1 host theme survives an rcfPage.init() re-run"
119
+ },
120
+ {
121
+ "id": "TC-229-reinit-keeps-control-choice",
122
+ "acId": "AC-206-10",
123
+ "description": "Boot `?theme=light` in non-embed mode, click Dark, then call `rcfPage.init()`: `<html data-theme>` stays `dark` and the Dark button stays pressed.",
124
+ "status": "pending",
125
+ "testPointer": "test/view/theme-control.test.js::PR 291 F1 regression: standalone control choice survives an rcfPage.init() re-run with ?theme= in the URL"
80
126
  }
81
127
  ],
82
128
  "status": "draft"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "createdAt": "2026-10-03T10:50:00Z",
3
- "updatedAt": "2026-10-03T10:50:00Z",
3
+ "updatedAt": "2026-10-05T18:00:00Z",
4
4
  "purpose": "Cover US-17404 (D3 bites): the three D3 bite checks shapes:templateMarkers, shapes:entityJoin and shapes:pathsResolve each have pass, fail, notApplicable, id and why strings; drafts are included in templateMarkers; the readiness CLI --check shapes exits 4 on an unacknowledged D3 failure and 0 when acked at the current hash; ackable() is exactly D3, D5, D6; --ack on D1, D2, D4, D7 or D8 exits 2 unchanged.",
5
5
  "testLevel": "unit",
6
6
  "acIds": [
@@ -9,7 +9,10 @@
9
9
  "AC-17404-3",
10
10
  "AC-17404-4",
11
11
  "AC-17404-5",
12
- "AC-17404-6"
12
+ "AC-17404-6",
13
+ "AC-17404-7",
14
+ "AC-17404-8",
15
+ "AC-17404-9"
13
16
  ],
14
17
  "id": "TS-230",
15
18
  "usId": "US-17404",
@@ -70,6 +73,27 @@
70
73
  "description": "A [draft] recordShape without fields: fails shapes:templateMarkers exactly as a settled one; this completes AC-18801-4 from PR 3.",
71
74
  "status": "pending",
72
75
  "testPointer": "test/query/gates.test.js::gates (REQ-188, AC-18801-4): draft recordShape without fields fails templateMarkers (lifted by PR 5 ADR-4131)"
76
+ },
77
+ {
78
+ "id": "TC-230-r5-entityjoin-under-narrowed-scope",
79
+ "acId": "AC-17404-7",
80
+ "description": "A D3 scope narrowed so no TAC and no shaped REQ is in scope but a coreEntity has no record shape anywhere tree-wide still fails shapes:entityJoin (stage state failing, not notApplicable) via the ADR-4138 helper.",
81
+ "status": "pending",
82
+ "testPointer": "test/query/gates.test.js::gates (R5, AC-17404-7): entityJoin runs tree-wide under narrowed D3 scope"
83
+ },
84
+ {
85
+ "id": "TC-230-r6-bare-paths-whitelist",
86
+ "acId": "AC-17404-8",
87
+ "description": "extractInterfacePathTokens treats Dockerfile, Makefile, LICENSE, Procfile, Containerfile, Justfile, Rakefile, Gemfile and CODEOWNERS as candidate tokens; shapes:pathsResolve fails a path: Dockerfile when not in resolvedPaths and passes when resolved. The exported BARE_PATH_WHITELIST drives both.",
88
+ "status": "pending",
89
+ "testPointer": "test/query/gates.test.js::gates (R6, AC-17404-8): bare path whitelist is checked by pathsResolve"
90
+ },
91
+ {
92
+ "id": "TC-230-r13-helper-foldstate-delegation",
93
+ "acId": "AC-17404-9",
94
+ "description": "treeWideFailureEnvelope returns null when every tree-wide check passes under a scope-empty stage; on D3 with a failing tree-wide check and a freeze.gates ack at the currentTreeHash it folds through foldState to state 'acknowledged'; on D2 (blocking) with a failing tree-wide check it stays 'failing'.",
95
+ "status": "pending",
96
+ "testPointer": "test/query/gates.test.js::gates (PR 292 follow-up, AC-17404-9): treeWideFailureEnvelope helper semantics"
73
97
  }
74
98
  ],
75
99
  "status": "draft"
@@ -9,7 +9,8 @@
9
9
  "AC-17405-3",
10
10
  "AC-17405-4",
11
11
  "AC-17405-5",
12
- "AC-17405-6"
12
+ "AC-17405-6",
13
+ "AC-17405-9"
13
14
  ],
14
15
  "id": "TS-231",
15
16
  "usId": "US-17405",
@@ -98,6 +99,20 @@
98
99
  "description": "R11 refuses dotted grammar; rcf define validate reports the finding naming the dotted field.",
99
100
  "status": "passing",
100
101
  "testPointer": "test/define/validate-findings.test.js::validate findings (PR 9, R11): ownerRef uses the widened grammar; deliveredBy object form is checked"
102
+ },
103
+ {
104
+ "id": "TC-231-r8-standards-applied-waived-or-cited",
105
+ "acId": "AC-17405-5",
106
+ "description": "A concern-ledger entry concern 'standards:<pack>' with disposition 'applied' satisfies skeleton:standardsCited (R8 2026-10-05); 'waived' also satisfies it; neither nor cited, the pack fails standards:<pack>.",
107
+ "status": "pending",
108
+ "testPointer": "test/query/gates.test.js::gates (R8, AC-17405-5): applied disposition satisfies standardsCited alongside waived and citation"
109
+ },
110
+ {
111
+ "id": "TC-231-r7-standards-under-narrowed-d2-scope",
112
+ "acId": "AC-17405-9",
113
+ "description": "A D2 scope narrowed so no REQ, PRD, TAD or brief statement is in scope but a registered standards pack is neither cited nor waived tree-wide still fails skeleton:standardsCited (stage state failing, not notApplicable) via the ADR-4138 helper.",
114
+ "status": "pending",
115
+ "testPointer": "test/query/gates.test.js::gates (R7, AC-17405-9): standardsCited runs tree-wide under narrowed D2 scope"
101
116
  }
102
117
  ],
103
118
  "status": "draft"
@@ -0,0 +1,44 @@
1
+ {
2
+ "createdAt": "2026-10-04T14:00:00Z",
3
+ "updatedAt": "2026-10-05T12:30:00Z",
4
+ "purpose": "Cover US-207 (every viewer text and control colour pair meets WCAG 2.1 AA in both themes): a static CSS-contrast audit parses `src/view/style.css`, resolves the `--sv-*` tokens for the light (`:root`) and dark (`:root[data-theme=\"dark\"]`) blocks, enumerates every rule that sets `color` paired with a reachable background, walks state variants (default, :hover, :focus, :focus-visible, :active, [aria-pressed=true], [aria-selected=true], .is-active, :disabled) and asserts the WCAG 2.1 AA thresholds (>= 4.5:1 for text, >= 3:1 for large text and non-text UI boundaries); the test exits non-zero on any failure, naming selector, state, theme, foreground, background, computed ratio and threshold. Points at test/view/contrast-aa.test.js and the BEFORE/AFTER report at ./output/contrast-report.md captured during the lane work (w-2026-10-04-dave-001). 2026-10-05 (PR 291 landing review F2, F3): state rules are merged over their base selector before pairing, border and outline colours are enumerated against the adjacent surface at 3:1, and the SearchButton and theme-control states are required to exist and pass in both themes.",
5
+ "testLevel": "unit",
6
+ "acIds": [
7
+ "AC-207-1",
8
+ "AC-207-2"
9
+ ],
10
+ "id": "TS-236",
11
+ "usId": "US-207",
12
+ "title": "WCAG 2.1 AA contrast audit across the viewer stylesheet, both themes, every state",
13
+ "testCases": [
14
+ {
15
+ "id": "TC-236-aa-enumerates-all-pairs",
16
+ "acId": "AC-207-1",
17
+ "description": "The audit parses `src/view/style.css`, enumerates every selector that sets `color` with every reachable background (own rule, ancestor surface token, page background `--sv-canvas`) in each state (default, :hover, :focus, :focus-visible, :active, [aria-pressed=true], [aria-selected=true], .is-active, :disabled) in both the light and dark token sets, computes the WCAG relative-luminance ratio and asserts >= 4.5:1 for normal text and >= 3:1 for large text and non-text UI boundaries (WCAG 1.4.3 and 1.4.11).",
18
+ "status": "pending",
19
+ "testPointer": "test/view/contrast-aa.test.js::enumerates every color/background pair and asserts WCAG 2.1 AA in both themes (AC-207-1)"
20
+ },
21
+ {
22
+ "id": "TC-236-aa-failure-message",
23
+ "acId": "AC-207-2",
24
+ "description": "When a contrast pair is below the threshold, the test failure message names the selector, state, theme, foreground colour, background colour, computed ratio and applied threshold; the test exits non-zero so the suite blocks a merge that drops below AA.",
25
+ "status": "pending",
26
+ "testPointer": "test/view/contrast-aa.test.js::failure message names selector/state/theme/fg/bg/ratio/threshold and exits non-zero (AC-207-2)"
27
+ },
28
+ {
29
+ "id": "TC-236-state-merge-and-boundaries",
30
+ "acId": "AC-207-1",
31
+ "description": "A state rule that changes only the background (the original `.rcf-search-btn:hover` defect) is merged over its base selector and paired with the inherited colour; `border` / `border-color` and `outline` / `outline-color` are enumerated against the adjacent surface at the 3:1 non-text threshold; run against the pre-amendment stylesheet the helper reports the dark `.rcf-search-btn:hover` failure.",
32
+ "status": "pending",
33
+ "testPointer": "test/view/contrast-aa.test.js::state rules merge over their base; borders and outlines are enumerated as 3:1 pairs (AC-207-1)"
34
+ },
35
+ {
36
+ "id": "TC-236-theme-btn-states",
37
+ "acId": "AC-207-1",
38
+ "description": "`.rcf-theme-btn` hover, focus-visible and active pairs exist and pass in both themes, and its focus ring clears 3:1 against the surface it sits on.",
39
+ "status": "pending",
40
+ "testPointer": "test/view/contrast-aa.test.js::.rcf-theme-btn passes WCAG 2.1 AA in both themes across hover, focus-visible and active (AC-207-1)"
41
+ }
42
+ ],
43
+ "status": "draft"
44
+ }
@@ -39,6 +39,41 @@
39
39
  "id": "AC-17302-6",
40
40
  "description": "[must-not] given a statement whose text contains an existing REQ title and no resolvedBy, when D2 runs in 0.30.0, then skeleton:resolvedBy does not pass it on the title hit.",
41
41
  "testable": true
42
+ },
43
+ {
44
+ "id": "AC-17302-7",
45
+ "description": "[happy] (R1 2026-10-05) given rcf define ledger brief add --id 3 --text \"foo\" --kind capability on a ledger whose entry 3 already carries kind capability and text foo, when the verb runs, then it exits 0 and stdout reads 'brief-ledger: unchanged 3' (with --json, {\"status\":\"unchanged\",\"id\":3}); the file is not rewritten.",
46
+ "testable": true
47
+ },
48
+ {
49
+ "id": "AC-17302-8",
50
+ "description": "[failure] (R1 2026-10-05) given rcf define ledger brief add --id 3 --text \"bar\" --kind constraint on a ledger whose entry 3 carries kind capability and text foo, when the verb runs, then it exits 3 and stderr names the id and the differing fields (text, kind); the file is not rewritten.",
51
+ "testable": true
52
+ },
53
+ {
54
+ "id": "AC-17302-9",
55
+ "description": "[happy] (R1 2026-10-05) given rcf define ledger brief add --text \"foo\" with no --id on an empty ledger, when the verb runs, then it mints id 1 as before (idempotency opt-in is id-carried; the harness threads --id back on replay).",
56
+ "testable": true
57
+ },
58
+ {
59
+ "id": "AC-17302-10",
60
+ "description": "[happy] (R1 create extension 2026-10-05, PR 292 follow-up; amended on the PR 293 landing review) given rcf define create ac --parent US-1 --id AC-1-1 --description \"foo\" on a tree where US-1 already carries AC-1-1 with description foo and testable true and no other fields, when the verb runs, then it exits 0 and stdout reads 'AC-1-1: unchanged (rcf/user-stories/us-1.json)'; the parent US file is not rewritten; and given the same verb with --description \"bar\" instead, it exits 3, stderr names the id and the differing field (description), and the file is not rewritten. rcf define create has no --json flag; the stdout line is the whole output (suppressed by --quiet).",
61
+ "testable": true
62
+ },
63
+ {
64
+ "id": "AC-17302-11",
65
+ "description": "[happy] (R1 create extension, PR 293 landing review) given rcf define create tc --parent TS-1 --id TC-1-foo --ac AC-1-1 --description \"foo\" --test-pointer t.test.js::foo on a tree where TS-1 already carries TC-1-foo with the same acId, description, testPointer and status pending, when the verb runs, then it exits 0 and stdout reads 'TC-1-foo: unchanged (rcf/test-suites/ts-1.json)' and the file is not rewritten; given the same verb with --description \"bar\", it exits 3 naming the id and the differing field (description) and the file is not rewritten. Idempotency is id-carried: without --id, a derived-slug collision still refuses with exit 2 and the 'supply --slug explicitly' message.",
66
+ "testable": true
67
+ },
68
+ {
69
+ "id": "AC-17302-12",
70
+ "description": "[happy] (R1 create extension, PR 293 landing review) given rcf define create cn --id CN-1 --path src/a.js --acs AC-1-1 on a tree where CN-1 already carries path src/a.js, implementsAcIds [AC-1-1], dependencies [], version 0.1.0 and status draft, when the verb runs, then it exits 0 and stdout reads 'CN-1: unchanged (rcf/code-nodes/cn-1.json)' and the file is not rewritten; given the same verb with --path src/b.js, it exits 3 naming the id and the differing field (path) and the file is not rewritten.",
71
+ "testable": true
72
+ },
73
+ {
74
+ "id": "AC-17302-13",
75
+ "description": "[happy] (R1 create extension, PR 293 landing review) given rcf define create req --parent PRD-001 --id REQ-050 --title T --description D whose first run persisted a classifier-owned shapeClassification block, when the identical command is replayed, then it exits 0 and stdout reads 'REQ-050: unchanged (rcf/requirements/req-050.json)' and the file is not rewritten: the replay compare ignores every writer- and classifier-owned field (createdAt, updatedAt, shapeClassification; one exported REPLAY_IGNORE_FIELDS list in src/core/store/writer.js); given the same verb with a different --description, it exits 3 naming description and the file is not rewritten.",
76
+ "testable": true
42
77
  }
43
78
  ],
44
79
  "tacIds": [
@@ -46,5 +81,5 @@
46
81
  ],
47
82
  "tags": [],
48
83
  "createdAt": "2026-10-02T16:40:00Z",
49
- "updatedAt": "2026-10-02T16:40:00Z"
84
+ "updatedAt": "2026-10-05T19:00:00Z"
50
85
  }
@@ -59,6 +59,16 @@
59
59
  "id": "AC-17401-10",
60
60
  "description": "src/setup/identity-seed.js IDENTITY_TEMPLATE seeds a '## Surface' section containing one line that is one of 'viewer' | 'runningApp' | 'prDiff' (default 'prDiff' with explanatory text matching the Register section's style) so that a project immediately after 'rcf init' passes checkD1Brief's profile:surface check without further operator action. The seed stays idempotent (an existing profile.md is left byte-identical, per the slice-1 'kept' contract).",
61
61
  "testable": true
62
+ },
63
+ {
64
+ "id": "AC-17401-11",
65
+ "description": "[happy] (R13 2026-10-05) given a D5 scope narrowed so no REQ is in scope but the tree has an auth or httpApi REQ and TAD.securityArchitecture is empty, when D5 runs, then crosscut:securityArchitecture still fails TAD.securityArchitecture and the stage state is failing (not notApplicable) through the shared tree-wide-before-scope helper (ADR-4138 extended).",
66
+ "testable": true
67
+ },
68
+ {
69
+ "id": "AC-17401-12",
70
+ "description": "[happy] (R13 2026-10-05) given a D5 scope narrowed so no REQ is in scope but the tree carries a US with an AC description that contains the '[deployed]' marker and TAD.operationalConcerns is empty, when D5 runs, then crosscut:operationalConcerns still fails TAD.operationalConcerns and the stage state is failing (not notApplicable) through the shared tree-wide-before-scope helper (ADR-4138 extended).",
71
+ "testable": true
62
72
  }
63
73
  ],
64
74
  "tacIds": [
@@ -66,5 +76,5 @@
66
76
  ],
67
77
  "tags": [],
68
78
  "createdAt": "2026-09-24T14:30:00Z",
69
- "updatedAt": "2026-10-01T13:03:38Z"
79
+ "updatedAt": "2026-10-05T18:00:00Z"
70
80
  }
@@ -44,6 +44,11 @@
44
44
  "id": "AC-17402-7",
45
45
  "description": "[failure] Given a notApplicable stage, when readiness is computed, then its stage:<D>:scope placeholder check carries the stage's STAGE_FALLBACK_PERSONA and ok true.",
46
46
  "testable": true
47
+ },
48
+ {
49
+ "id": "AC-17402-8",
50
+ "description": "[happy] (R13 2026-10-05) given a D2 scope narrowed so no REQ, PRD, TAD or resolving brief statement is in scope but the tree has zero Deploy target or Deploy deferral ADRs (or two or more), when D2 runs, then skeleton:deployAdr still fails ADR:deploy and the stage state is failing (not notApplicable) through the shared tree-wide-before-scope helper (ADR-4138 extended).",
51
+ "testable": true
47
52
  }
48
53
  ],
49
54
  "tacIds": [
@@ -51,5 +56,5 @@
51
56
  ],
52
57
  "tags": [],
53
58
  "createdAt": "2026-10-01T14:30:00Z",
54
- "updatedAt": "2026-10-01T14:30:00Z"
59
+ "updatedAt": "2026-10-05T18:00:00Z"
55
60
  }
@@ -49,6 +49,16 @@
49
49
  "id": "AC-17403-8",
50
50
  "description": "[must-not] Given any tree, when D2 or D7 runs, then no check named skeleton:reqFields is emitted and the stage envelope shape (stage, gate, state, checks) is unchanged.",
51
51
  "testable": true
52
+ },
53
+ {
54
+ "id": "AC-17403-9",
55
+ "description": "[happy] (R2 2026-10-05) given a D3 scope that excludes every TAC and shaped REQ (no TAC, no httpApi/persistence/auth REQ in scope) but a [draft] marker exists on a TAC OUTSIDE the narrowed scope, when D3 runs, then shapes:draftSettled still fails the <tacId>:<name> finding and the stage state is failing (not notApplicable) through the shared tree-wide-before-scope helper (ADR-4138); the same test asserted against pre-R2 gates.js (origin/main d8adedff^) returns notApplicable instead.",
56
+ "testable": true
57
+ },
58
+ {
59
+ "id": "AC-17403-10",
60
+ "description": "[happy] (PR 292 follow-up 2026-10-05) given a scope-empty D3 with a failing shapes:draftSettled tree-wide, when the failing envelope the ADR-4138 helper returns is rendered by src/cli/readiness.js, then the printed D3 line reads 'D3 (define.shapes): failing' without the pre-R13 '(no TAC ... in scope)' notApplicable reason trailer; the envelope omits the reason field (foldState delegation inside the helper carries no reason text).",
61
+ "testable": true
52
62
  }
53
63
  ],
54
64
  "tacIds": [
@@ -56,5 +66,5 @@
56
66
  ],
57
67
  "tags": [],
58
68
  "createdAt": "2026-10-01T14:30:00Z",
59
- "updatedAt": "2026-10-01T14:30:00Z"
69
+ "updatedAt": "2026-10-05T18:00:00Z"
60
70
  }
@@ -39,6 +39,21 @@
39
39
  "id": "AC-17404-6",
40
40
  "description": "[must-not] given --ack on D1, D2, D4, D7 or D8, when freeze runs, then it exits 2 unchanged from 0.29.0.",
41
41
  "testable": true
42
+ },
43
+ {
44
+ "id": "AC-17404-7",
45
+ "description": "[happy] (R5 2026-10-05) given a D3 scope narrowed so no recordShape is in scope but a coreEntity has no record shape anywhere tree-wide, when D3 runs, then shapes:entityJoin fails TAD.entity:<name> and the stage state is failing (not notApplicable); the shared tree-wide-before-scope helper (ADR-4138) governs the ordering.",
46
+ "testable": true
47
+ },
48
+ {
49
+ "id": "AC-17404-8",
50
+ "description": "[happy] (R6 2026-10-05) given an interface description with path: Dockerfile and no entry for Dockerfile in resolvedPaths, when D3 runs, then shapes:pathsResolve fails it; given resolvedPaths contains Dockerfile, then it passes. The whitelist exported from gates.js names Dockerfile, Makefile, LICENSE, Procfile, Containerfile, Justfile, Rakefile, Gemfile and CODEOWNERS; a bare word outside the list (foo) still skips as before.",
51
+ "testable": true
52
+ },
53
+ {
54
+ "id": "AC-17404-9",
55
+ "description": "[happy] (PR 292 follow-up 2026-10-05) given treeWideFailureEnvelope invoked on a scope-empty stage with every tree-wide check passing, when the helper runs, then it returns null (the stage proceeds to its own notApplicable envelope); given at least one failing tree-wide check on an ackable stage (D3) with a freeze.gates acknowledgement whose at.hash equals the currentTreeHash, then the helper returns an envelope with state 'acknowledged' through foldState delegation (the helper does not re-implement ack-at-current-hash); given the same shape on D2 (blocking), then the helper never folds to acknowledged.",
56
+ "testable": true
42
57
  }
43
58
  ],
44
59
  "tacIds": [
@@ -47,5 +62,5 @@
47
62
  ],
48
63
  "tags": [],
49
64
  "createdAt": "2026-10-03T10:50:00Z",
50
- "updatedAt": "2026-10-03T10:50:00Z"
65
+ "updatedAt": "2026-10-05T18:00:00Z"
51
66
  }
@@ -32,7 +32,7 @@
32
32
  },
33
33
  {
34
34
  "id": "AC-17405-5",
35
- "description": "[happy] given a registered standards pack cited in an ADR, when D2 runs, then skeleton:standardsCited passes; uncited and unwaived, it fails standards:<pack>.",
35
+ "description": "[happy] (R8 2026-10-05) given a registered standards pack cited in an ADR, when D2 runs, then skeleton:standardsCited passes; uncited and unwaived, it fails standards:<pack>; given a concern-ledger entry concern 'standards:<pack>' with disposition 'applied' or 'waived', it passes (the check question reads 'cited, applied or waived').",
36
36
  "testable": true
37
37
  },
38
38
  {
@@ -49,6 +49,11 @@
49
49
  "id": "AC-17405-8",
50
50
  "description": "[must-not] (PR 9 R11) given an ownerRef whose field uses dotted grammar (interfaces.loan, responsibilities.audit), when D4 or rcf define validate runs, then it fails with the finding naming the dotted field so the author can rewrite to bracket grammar.",
51
51
  "testable": true
52
+ },
53
+ {
54
+ "id": "AC-17405-9",
55
+ "description": "[happy] (R7 2026-10-05) given a D2 scope narrowed so no REQ, PRD, TAD or brief statement is in scope but a registered standards pack is neither cited nor waived tree-wide, when D2 runs, then skeleton:standardsCited fails standards:<pack> and the stage state is failing (not notApplicable); the shared tree-wide-before-scope helper (ADR-4138) governs the ordering.",
56
+ "testable": true
52
57
  }
53
58
  ],
54
59
  "tacIds": [
@@ -57,5 +62,5 @@
57
62
  ],
58
63
  "tags": [],
59
64
  "createdAt": "2026-10-03T13:30:00Z",
60
- "updatedAt": "2026-10-03T20:30:00Z"
65
+ "updatedAt": "2026-10-05T12:00:00Z"
61
66
  }