rcf-lite 0.32.4 → 0.33.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 (90) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/fixtures/canary-manifest.json +9 -9
  3. package/guidance/discovery/README.md +22 -0
  4. package/guidance/discovery/discovery-viewer-command-page-1-layout.html +191 -0
  5. package/guidance/discovery/discovery-viewer-command-page-2-coverage.html +193 -0
  6. package/guidance/discovery/discovery-viewer-command-page-3-trace-matrix.html +195 -0
  7. package/guidance/discovery/discovery-viewer-command-page-4-tables.html +196 -0
  8. package/guidance/discovery/discovery-viewer-command-page-5-subtabs.html +224 -0
  9. package/guidance/discovery/discovery-viewer-command-page-6-one-page.html +280 -0
  10. package/guidance/discovery/discovery-viewer-command-page.md +301 -0
  11. package/package.json +1 -1
  12. package/rcf/adrs/adr-4139-readiness-tables-read-only-no-commands.json +30 -0
  13. package/rcf/adrs/adr-4140-view-query-routes-per-pivot-matrix-no-mermaid.json +30 -0
  14. package/rcf/adrs/adr-4141-verify-modes.json +25 -0
  15. package/rcf/code-nodes/cn-771.json +3 -2
  16. package/rcf/code-nodes/cn-779.json +19 -0
  17. package/rcf/code-nodes/cn-780.json +14 -0
  18. package/rcf/code-nodes/cn-781.json +14 -0
  19. package/rcf/code-nodes/cn-782.json +15 -0
  20. package/rcf/code-nodes/cn-783.json +17 -0
  21. package/rcf/code-nodes/cn-784.json +20 -0
  22. package/rcf/code-nodes/cn-785.json +14 -0
  23. package/rcf/code-nodes/cn-786.json +14 -0
  24. package/rcf/code-nodes/cn-787.json +18 -0
  25. package/rcf/code-nodes/cn-788.json +14 -0
  26. package/rcf/code-nodes/cn-789.json +14 -0
  27. package/rcf/code-nodes/cn-790.json +15 -0
  28. package/rcf/code-nodes/cn-791.json +14 -0
  29. package/rcf/code-nodes/cn-792.json +17 -0
  30. package/rcf/code-nodes/cn-793.json +17 -0
  31. package/rcf/code-nodes/cn-794.json +18 -0
  32. package/rcf/code-nodes/cn-795.json +15 -0
  33. package/rcf/code-nodes/cn-796.json +14 -0
  34. package/rcf/code-nodes/cn-797.json +14 -0
  35. package/rcf/code-nodes/cn-798.json +14 -0
  36. package/rcf/define/brief-ledger.json +47 -0
  37. package/rcf/define/decisions-ledger.json +113 -0
  38. package/rcf/fbs/fbs-204.json +46 -0
  39. package/rcf/fbs/fbs-205.json +46 -0
  40. package/rcf/fbs/fbs-206.json +49 -0
  41. package/rcf/fbs/fbs-207.json +43 -0
  42. package/rcf/fbs/fbs-208.json +47 -0
  43. package/rcf/fbs/fbs-209.json +22 -0
  44. package/rcf/requirements/req-002.json +5 -2
  45. package/rcf/requirements/req-180.json +6 -3
  46. package/rcf/tacs/tac-4127-readiness-view.json +2 -2
  47. package/rcf/tacs/tac-4133-readiness-po-layer.json +2 -2
  48. package/rcf/tacs/tac-4135-readiness-command-page.json +94 -0
  49. package/rcf/tacs/tac-4136-view-query-routes.json +68 -0
  50. package/rcf/tacs/tac-4141-verify-modes.json +25 -0
  51. package/rcf/test-suites/ts-223.json +7 -7
  52. package/rcf/test-suites/ts-237.json +78 -0
  53. package/rcf/test-suites/ts-238.json +70 -0
  54. package/rcf/test-suites/ts-239.json +78 -0
  55. package/rcf/test-suites/ts-240.json +70 -0
  56. package/rcf/test-suites/ts-241.json +70 -0
  57. package/rcf/test-suites/ts-242.json +46 -0
  58. package/rcf/user-stories/us-16503.json +51 -0
  59. package/rcf/user-stories/us-18001.json +4 -4
  60. package/rcf/user-stories/us-18003.json +79 -0
  61. package/rcf/user-stories/us-18004.json +70 -0
  62. package/rcf/user-stories/us-18005.json +79 -0
  63. package/rcf/user-stories/us-208.json +74 -0
  64. package/rcf/user-stories/us-209.json +70 -0
  65. package/releases/releases.yaml +18 -1
  66. package/src/cli/finalise.js +141 -2
  67. package/src/cli/view.js +13 -1
  68. package/src/define/ledgers.js +9 -1
  69. package/src/finalise/spawn.js +2 -0
  70. package/src/server/index.js +104 -39
  71. package/src/server/routes.js +169 -0
  72. package/src/verify/cli/run.js +40 -0
  73. package/src/verify/engine/deterministic.js +150 -0
  74. package/src/verify/engine/index.js +27 -4
  75. package/src/view/doc-renderers/req.js +11 -9
  76. package/src/view/html-page.js +15 -11
  77. package/src/view/index.js +7 -1
  78. package/src/view/live-client.js +4 -0
  79. package/src/view/page-init.js +842 -1
  80. package/src/view/readiness/composite-id.js +35 -0
  81. package/src/view/readiness/coverage-summary.js +293 -0
  82. package/src/view/readiness/delta-counts.js +156 -0
  83. package/src/view/readiness/grid.js +175 -0
  84. package/src/view/readiness/po-layer.js +110 -220
  85. package/src/view/readiness/tables.js +500 -0
  86. package/src/view/readiness/thin-reqs.js +237 -0
  87. package/src/view/readiness/trace-matrix.js +392 -0
  88. package/src/view/readiness.js +359 -370
  89. package/src/view/style.css +594 -0
  90. package/src/watch/index.js +75 -17
@@ -0,0 +1,70 @@
1
+ {
2
+ "createdAt": "2026-10-07T13:47:06.367Z",
3
+ "updatedAt": "2026-10-08T18:05:44.868Z",
4
+ "purpose": "Cover every acceptance criterion of US-208 with one node:test case each in test/view/query-routes.test.js; DEFINE lands the named declarations flagged not yet built so the strict coverage audit binds each criterion, and BUILD (FBS-207) removes the flags as it makes them pass.",
5
+ "testLevel": "integration",
6
+ "acIds": [
7
+ "AC-208-1",
8
+ "AC-208-2",
9
+ "AC-208-3",
10
+ "AC-208-4",
11
+ "AC-208-5",
12
+ "AC-208-6",
13
+ "AC-208-7"
14
+ ],
15
+ "testCases": [
16
+ {
17
+ "id": "TC-240-208-1-happy",
18
+ "acId": "AC-208-1",
19
+ "description": "[happy] Given a running viewer and a known id, when GET \"./trace.json?id=<id>&direction=forward\" is requested, then the response is application/json carrying the computeTrace result for that pivot (pivot, direction, found, nodes, edges), computed from the current state and served with \"cache-control: no-store\" relative to the viewer mount.",
20
+ "status": "pending",
21
+ "testPointer": "test/view/query-routes.test.js::AC-208-1 happy: a running viewer and a known id"
22
+ },
23
+ {
24
+ "id": "TC-240-208-2-happy",
25
+ "acId": "AC-208-2",
26
+ "description": "[happy] Given a running viewer and a known id, when GET \"./impact.json?id=<id>\" is requested, then the response is application/json carrying the computeImpact result (pivot, found, nodes with actionNeeded per node, edges) with \"cache-control: no-store\".",
27
+ "status": "pending",
28
+ "testPointer": "test/view/query-routes.test.js::AC-208-2 happy: a running viewer and a known id"
29
+ },
30
+ {
31
+ "id": "TC-240-208-3-happy",
32
+ "acId": "AC-208-3",
33
+ "description": "[happy] Given a running viewer, when GET \"./coverage.json\" is requested with no scope, then the response is application/json carrying the strict computeCoverage result for the whole tree (totals, requirements, unresolvedTestPointers); given \"?scope=<id>\" naming a PRD, REQ or US, the result is narrowed to that subtree as the CLI positional narrows it.",
34
+ "status": "pending",
35
+ "testPointer": "test/view/query-routes.test.js::AC-208-3 happy: a running viewer"
36
+ },
37
+ {
38
+ "id": "TC-240-208-4-failure",
39
+ "acId": "AC-208-4",
40
+ "description": "[failure] Given an unknown id, when trace or impact is requested, then the response is 404 application/json with QueryRouteError.error \"unknown-id\" and QueryRouteError.id echoing the request; given a direction outside forward, back and both, the response is 400 with QueryRouteError.error \"bad-direction\"; given a below-AC or unknown scope on coverage, the response is 400 with QueryRouteError.error \"bad-scope\".",
41
+ "status": "pending",
42
+ "testPointer": "test/view/query-routes.test.js::AC-208-4 failure: an unknown id"
43
+ },
44
+ {
45
+ "id": "TC-240-208-5-mustnot",
46
+ "acId": "AC-208-5",
47
+ "description": "[must-not] Given any request to the three routes, when the server handles it, then runWithAdmissibilityGate is not called (the routes bypass the gate the way src/cli/coverage.js and src/cli/impact.js do) and nothing under rcf/ is written.",
48
+ "status": "pending",
49
+ "testPointer": "test/view/query-routes.test.js::AC-208-5 must-not: any request to the three routes"
50
+ },
51
+ {
52
+ "id": "TC-240-208-6-edge",
53
+ "acId": "AC-208-6",
54
+ "description": "[edge] Given a rewalk that publishes a new state.version, when a route is requested, then the served result reflects the new tree and the memo entries of the previous version are discarded; within one version a repeated request for the same pivot and direction is served from the memo without recomputing.",
55
+ "status": "pending",
56
+ "testPointer": "test/view/query-routes.test.js::AC-208-6 edge: a rewalk that publishes a new stateversion"
57
+ },
58
+ {
59
+ "id": "TC-240-208-7-failure",
60
+ "acId": "AC-208-7",
61
+ "description": "[failure] Given the server before the first walk completes, when a trace, impact or coverage request arrives, then the response is 503 text \"view server initialising\", as ./index.json answers today.",
62
+ "status": "pending",
63
+ "testPointer": "test/view/query-routes.test.js::AC-208-7 failure: the server before the first walk completes"
64
+ }
65
+ ],
66
+ "id": "TS-240",
67
+ "usId": "US-208",
68
+ "title": "US-208 command page suite (query-routes)",
69
+ "status": "draft"
70
+ }
@@ -0,0 +1,70 @@
1
+ {
2
+ "createdAt": "2026-10-07T13:47:07.194Z",
3
+ "updatedAt": "2026-10-09T13:40:25.258Z",
4
+ "purpose": "Cover every acceptance criterion of US-209 with one node:test case each in test/view/trace-matrix.test.js; DEFINE lands the named declarations flagged not yet built so the strict coverage audit binds each criterion, and BUILD (FBS-208) removes the flags as it makes them pass.",
5
+ "testLevel": "unit",
6
+ "acIds": [
7
+ "AC-209-1",
8
+ "AC-209-2",
9
+ "AC-209-3",
10
+ "AC-209-4",
11
+ "AC-209-5",
12
+ "AC-209-6",
13
+ "AC-209-7"
14
+ ],
15
+ "testCases": [
16
+ {
17
+ "id": "TC-241-209-1-happy",
18
+ "acId": "AC-209-1",
19
+ "description": "[happy] Given the Trace sub-tab and a pivot id in the hash, when the client fetches \"./trace.json\" for it, then a matrix renders with one TraceMatrixRow per story and criterion under the pivot and columns for suites, cases, build specs and components, each TraceMatrixCell.reached true where the forward trace reaches the column from the row's criterion.",
20
+ "status": "pending",
21
+ "testPointer": "test/view/trace-matrix.test.js::AC-209-1 happy: the trace subtab and a pivot id in the hash"
22
+ },
23
+ {
24
+ "id": "TC-241-209-2-happy",
25
+ "acId": "AC-209-2",
26
+ "description": "[happy] Given coverage data for the pivot's criteria, when a cell renders, then TraceMatrixCell.resolution is \"resolving\" on the --sv-success token, \"unresolved\" on the --sv-warning token or \"none\" on the --sv-muted token, with no new colour token introduced.",
27
+ "status": "pending",
28
+ "testPointer": "test/view/trace-matrix.test.js::AC-209-2 happy: coverage data for the pivots criteria"
29
+ },
30
+ {
31
+ "id": "TC-241-209-3-happy",
32
+ "acId": "AC-209-3",
33
+ "description": "[happy] Given any id rendered in the questions, blocking, thin-requirements or coverage tables, when the row renders, then it carries a \"Trace\" action linking to \"#tab=readiness&sub=trace&entity=<id>\", and a lookup modal hit on a readiness row navigates to the same hash preserving embed and theme.",
34
+ "status": "pending",
35
+ "testPointer": "test/view/trace-matrix.test.js::AC-209-3 happy: any id rendered in the questions blocking thinre"
36
+ },
37
+ {
38
+ "id": "TC-241-209-4-edge",
39
+ "acId": "AC-209-4",
40
+ "description": "[edge] Given an SSE tree-update that swaps #rcf-live-content while the Trace sub-tab shows a matrix, when the swap lands, then the matrix is re-rendered from the client cache keyed by state.version and marked stale until the next fetch completes, never dropped.",
41
+ "status": "pending",
42
+ "testPointer": "test/view/trace-matrix.test.js::AC-209-4 edge: an sse treeupdate that swaps rcflivecontent whil"
43
+ },
44
+ {
45
+ "id": "TC-241-209-5-mustnot",
46
+ "acId": "AC-209-5",
47
+ "description": "[must-not] Given the Requirements tab, when a requirement renders, then no Mermaid slice diagram is rendered for it (the per-requirement slice and its details element are gone) and no Mermaid is rendered anywhere on the Readiness tab.",
48
+ "status": "pending",
49
+ "testPointer": "test/view/trace-matrix.test.js::AC-209-5 must-not: the requirements tab"
50
+ },
51
+ {
52
+ "id": "TC-241-209-6-failure",
53
+ "acId": "AC-209-6",
54
+ "description": "[failure] Given a pivot the route reports with found false, when the Trace sub-tab renders, then an empty state names the id and offers the lookup modal, and no partial matrix is drawn.",
55
+ "status": "pending",
56
+ "testPointer": "test/view/trace-matrix.test.js::AC-209-6 failure: a pivot the route reports with found false"
57
+ },
58
+ {
59
+ "id": "TC-241-209-7-edge",
60
+ "acId": "AC-209-7",
61
+ "description": "[edge] Given a pivot whose forward trace yields more than 200 TraceMatrixRow entries, when the matrix renders, then a row filter by story id or criterion id is shown, the full TraceMatrixRow.cells set is retained in memory and nothing is truncated silently.",
62
+ "status": "pending",
63
+ "testPointer": "test/view/trace-matrix.test.js::AC-209-7 edge: a pivot whose forward trace yields more than 200"
64
+ }
65
+ ],
66
+ "id": "TS-241",
67
+ "usId": "US-209",
68
+ "title": "US-209 command page suite (trace-matrix)",
69
+ "status": "draft"
70
+ }
@@ -0,0 +1,46 @@
1
+ {
2
+ "createdAt": "2026-10-08T15:50:28.920Z",
3
+ "updatedAt": "2026-10-08T15:50:43.321Z",
4
+ "purpose": "Cover the --mode flag on rcf verify run and rcf build finalise, the deterministic engine output shape (findings/blockedAcs/runStats), the finalise preseed partial-report fallback, and the ADR-4112 deterministic-mode refusal line.",
5
+ "testLevel": "unit",
6
+ "acIds": [
7
+ "AC-16503-1",
8
+ "AC-16503-2",
9
+ "AC-16503-3",
10
+ "AC-16503-4"
11
+ ],
12
+ "id": "TS-242",
13
+ "usId": "US-16503",
14
+ "title": "Verify-modes CLI + deterministic engine + preseed partial report",
15
+ "testCases": [
16
+ {
17
+ "id": "TC-242-16503-1-happy",
18
+ "acId": "AC-16503-1",
19
+ "description": "run --mode deterministic emits BLOCKED with critique-only blockedAcs on every testable AC",
20
+ "status": "pending",
21
+ "testPointer": "test/verify/cli/run-mode-deterministic.test.js::run --mode deterministic: BLOCKED with critique-only blockedAcs on every AC"
22
+ },
23
+ {
24
+ "id": "TC-242-16503-2-refuse",
25
+ "acId": "AC-16503-2",
26
+ "description": "finalise refuses promotion on a deterministic PASS with skipped>0, naming the counts line and ADR-4112",
27
+ "status": "pending",
28
+ "testPointer": "test/cli/finalise-deterministic-mode.test.js::finalise: deterministic-mode PASS with skipped>0 is REFUSED (never silently promotes)"
29
+ },
30
+ {
31
+ "id": "TC-242-16503-3-abort",
32
+ "acId": "AC-16503-3",
33
+ "description": "finalise overwrites the preseed stub with a status: aborted record when verify exits non-zero without writing",
34
+ "status": "pending",
35
+ "testPointer": "test/cli/finalise-deterministic-mode.test.js::finalise: verify exits non-zero without writing report -> partial `aborted` record overwrites the preseed stub"
36
+ },
37
+ {
38
+ "id": "TC-242-16503-4-usage",
39
+ "acId": "AC-16503-4",
40
+ "description": "verify run --mode and finalise --mode refuse an unknown value with exit 2",
41
+ "status": "pending",
42
+ "testPointer": "test/cli/finalise-deterministic-mode.test.js::finalise: --mode unknown value is a usage error (exit 2)"
43
+ }
44
+ ],
45
+ "status": "draft"
46
+ }
@@ -0,0 +1,51 @@
1
+ {
2
+ "createdAt": "2026-10-08T15:39:52.219Z",
3
+ "updatedAt": "2026-10-08T15:40:58.645Z",
4
+ "asA": "operator running `rcf build finalise` from a dispatched worker that may not spawn the agent CLI",
5
+ "iWant": "a `--mode deterministic` option on `rcf verify run` and `rcf build finalise` that runs the gate in-process with a per-AC skip ledger, and a partial-report fallback that names the mode and the reason when verify exits without writing a report",
6
+ "soThat": "the finalise gate always surfaces a readable report, deterministic runs never silently promote to verified (ADR-4112), and the parent-session `agentScreenshotCritique` mode is unchanged for operators who can spawn the agent CLI",
7
+ "usId": "US-16503",
8
+ "prdId": "PRD-001",
9
+ "reqId": "REQ-165",
10
+ "version": "0.1.0",
11
+ "status": "draft",
12
+ "title": "US-16503: a dispatched worker can run the finalise gate without spawning the agent CLI",
13
+ "acceptanceCriteria": [
14
+ {
15
+ "id": "AC-16503-1",
16
+ "description": "rcf verify run --mode deterministic produces a BLOCKED report with runStats.mode='deterministic' and a per-AC critique-only blockedAcs ledger when every AC in the chain requires critique.",
17
+ "testable": true,
18
+ "given": "a scaffolded RCF chain whose user stories carry acceptance criteria but no per-AC deterministic probe shape",
19
+ "when": "rcf verify run --repo <chain> --profile ci --url http://localhost:3000 --out <path> --mode deterministic --provision-mode skip is invoked",
20
+ "then": "the exit code is 5 (BLOCKED trips the default severity gate), the written report has verdict 'BLOCKED', run.runStats.mode='deterministic', run.runStats.counts.total matches the number of testable ACs with counts.verified=0 and counts.skipped=counts.total, and every entry in blockedAcs carries reason matching /critique-only/ and mode='deterministic'",
21
+ "scope": "runtime"
22
+ },
23
+ {
24
+ "id": "AC-16503-2",
25
+ "description": "placeholder",
26
+ "testable": true,
27
+ "given": "an FBS at status 'complete' and a verify report whose run.runStats.mode='deterministic' and counts.skipped>0",
28
+ "when": "rcf build finalise <fbsId> --url ... is invoked",
29
+ "then": "the exit code is 4, the FBS stays at 'complete', and stderr matches /deterministic mode verified \\d+ of \\d+ ACs/ and /ADR-4112/"
30
+ },
31
+ {
32
+ "id": "AC-16503-3",
33
+ "description": "placeholder",
34
+ "testable": true,
35
+ "given": "an FBS at status 'complete' and a spawnVerify seam that returns exit code 1 WITHOUT writing to --out",
36
+ "when": "rcf build finalise <fbsId> --url ... --mode deterministic is invoked",
37
+ "then": "the exit code is non-zero, the --out file is readable, run.runStats.mode='deterministic', run.runStats.status='aborted', run.runStats.exitCode=1, launchFailure.status='aborted', and the FBS stays at 'complete'"
38
+ },
39
+ {
40
+ "id": "AC-16503-4",
41
+ "description": "placeholder",
42
+ "testable": true,
43
+ "given": "any scaffold",
44
+ "when": "rcf verify run --mode foo or rcf build finalise <fbsId> --url ... --mode foo is invoked",
45
+ "then": "the exit code is 2 and stderr matches /--mode must be one of/"
46
+ }
47
+ ],
48
+ "tacIds": [
49
+ "TAC-4141-verify-modes"
50
+ ]
51
+ }
@@ -22,12 +22,12 @@
22
22
  },
23
23
  {
24
24
  "id": "AC-18001-3",
25
- "description": "[happy] Given personas.productOwner.blockers non-empty, when the tab renders, then each blocker is a findings list headed by its question with its ids as anchor links into the document tabs.",
25
+ "description": "[happy] Given personas.productOwner.blockers non-empty, when the tab renders, then each PO blocker id appears in the questions table under its question group with the id as an anchor link into the document tabs.",
26
26
  "testable": true
27
27
  },
28
28
  {
29
29
  "id": "AC-18001-4",
30
- "description": "[happy] Given a profile register of productOwner, when the tab renders, then the product-owner group is expanded first and the engineer group is collapsed with its count visible.",
30
+ "description": "[happy] Given a profile register of productOwner, when the tab first renders, then the questions table precedes the blocking table.",
31
31
  "testable": true
32
32
  },
33
33
  {
@@ -37,7 +37,7 @@
37
37
  },
38
38
  {
39
39
  "id": "AC-18001-6",
40
- "description": "[failure] Given a tree where levels.readyToBuild.ok is false, when the tab renders, then the Freeze now control is disabled and names the failing gates from levels.readyToBuild.blockedBy.",
40
+ "description": "[failure] Given a tree where levels.readyToBuild.ok is false, when the tab renders, then the freeze state block names the failing gates from levels.readyToBuild.blockedBy in plain words and no freeze control is rendered.",
41
41
  "testable": true
42
42
  },
43
43
  {
@@ -56,5 +56,5 @@
56
56
  ],
57
57
  "tags": [],
58
58
  "createdAt": "2026-10-01T18:00:00Z",
59
- "updatedAt": "2026-10-06T12:00:00Z"
59
+ "updatedAt": "2026-10-08T16:43:30.032Z"
60
60
  }
@@ -0,0 +1,79 @@
1
+ {
2
+ "createdAt": "2026-10-07T13:46:47.389Z",
3
+ "updatedAt": "2026-10-08T16:43:22.541Z",
4
+ "description": "User story under REQ-180 for the command page (discovery-viewer-command-page sections 4 rank 1, 2 and 16; FBS-204). The question cards and the blocker cards become two tables over readiness.questions[] and stages[].checks[].failing[]: every row carries the item id, the plain-English ask or finding, where it lives on the chain, a link that opens the item in full context, and what resolved looks like. Composite finding ids split on the first colon so every link resolves. No row cap. The questions table carries a one-line copy handle (id plus ask) for briefing an agent; no CLI command is rendered anywhere on the page and the Freeze now button is gone (Q1 and Q4 rulings, ADR-4139). First paint keeps the profile register ordering (product owner first unless the profile says engineer).",
5
+ "asA": "a product owner or an engineer opening the Readiness tab",
6
+ "iWant": "every question waiting on me and every blocking item as a table row I can sort, count and open where it lives",
7
+ "soThat": "I can brief my agent from the row without reading prose or a terminal",
8
+ "tacIds": [
9
+ "TAC-4135-readiness-command-page"
10
+ ],
11
+ "acceptanceCriteria": [
12
+ {
13
+ "id": "AC-18003-1",
14
+ "description": "[happy] Given readiness.questions is non-empty, when the questions sub-view renders, then it is one table with one QuestionRow per question carrying QuestionRow.number, QuestionRow.ask, QuestionRow.location as a link that opens the item in full context, QuestionRow.settles in plain words and QuestionRow.state, and the group label is a sortable column rather than a heading.",
15
+ "testable": true,
16
+ "ownerRef": {
17
+ "tacId": "TAC-4135-readiness-command-page",
18
+ "field": "interfaces[renderQuestionsTable]"
19
+ }
20
+ },
21
+ {
22
+ "id": "AC-18003-2",
23
+ "description": "[edge] Given a question whose itemId is not a document id (a brief statement such as \"brief-ledger\" or a profile field such as \"profile:surface\"), when the row renders, then QuestionRow.locationHref is \"#tab=readiness&sub=questions&entity=<itemId>\" and the router lands on that row, so the page never emits a dead anchor.",
24
+ "testable": true,
25
+ "ownerRef": {
26
+ "tacId": "TAC-4135-readiness-command-page",
27
+ "field": "interfaces[QuestionRow]"
28
+ }
29
+ },
30
+ {
31
+ "id": "AC-18003-3",
32
+ "description": "[happy] Given every failing check across stages, when the blocking sub-view renders, then it is one table with one BlockingRow per failing item carrying BlockingRow.stage, BlockingRow.check, BlockingRow.docId as a link, BlockingRow.why from the gate and BlockingRow.resolved in plain words, with no cap on the number of rows and a FilterBar by stage and persona.",
33
+ "testable": true,
34
+ "ownerRef": {
35
+ "tacId": "TAC-4135-readiness-command-page",
36
+ "field": "interfaces[renderBlockingTable]"
37
+ }
38
+ },
39
+ {
40
+ "id": "AC-18003-4",
41
+ "description": "[edge] Given a composite failing id such as \"AC-060-3:userID\" or \"TAC-4122-define-gates:checkPersona\", when its row renders, then BlockingRow.docId is the text before the first colon, BlockingRow.fragment is the remainder and BlockingRow.href targets the document id so the link resolves through findByDocId.",
42
+ "testable": true,
43
+ "ownerRef": {
44
+ "tacId": "TAC-4135-readiness-command-page",
45
+ "field": "interfaces[splitCompositeId]"
46
+ }
47
+ },
48
+ {
49
+ "id": "AC-18003-5",
50
+ "description": "[happy] Given a question row, when the copy control renders, then QuestionRow.briefHandle is one line holding the item id and the plain-English ask, the control is labelled \"Copy for your agent\" and copies that line through the existing toast feedback, and the line holds no command text.",
51
+ "testable": true,
52
+ "ownerRef": {
53
+ "tacId": "TAC-4135-readiness-command-page",
54
+ "field": "interfaces[BlockingRow]"
55
+ }
56
+ },
57
+ {
58
+ "id": "AC-18003-6",
59
+ "description": "[failure] Given readiness could not be computed (the readiness object is null), when the Readiness tab renders, then the existing \"could not be computed\" placeholder is shown and no table is rendered.",
60
+ "testable": true
61
+ },
62
+ {
63
+ "id": "AC-18003-7",
64
+ "description": "[must-not] Given any register and any tree, when the panel renders for the command page, then the viewer emits no shell command text: no code element carries a command, no Run or Freeze-now affordance exists; chain ids are content, rendered as a prefix link with a plain-English label from the chain, and the full composite id stays in the DOM in a data attribute.",
65
+ "testable": true
66
+ },
67
+ {
68
+ "id": "AC-18003-8",
69
+ "description": "[happy] Given the profile register is \"engineer\", when the tab first paints, then the blocking table precedes the questions table; given \"productOwner\" or no profile, the questions table precedes the blocking table; in both cases both tables are present in the DOM.",
70
+ "testable": true
71
+ }
72
+ ],
73
+ "usId": "US-18003",
74
+ "prdId": "PRD-001",
75
+ "reqId": "REQ-180",
76
+ "version": "0.1.0",
77
+ "status": "draft",
78
+ "title": "the Readiness tab lists questions and blocking items as linked tables, read-only, with no command text"
79
+ }
@@ -0,0 +1,70 @@
1
+ {
2
+ "createdAt": "2026-10-07T13:46:49.207Z",
3
+ "updatedAt": "2026-10-07T13:46:49.207Z",
4
+ "description": "User story under REQ-180 for the command page (discovery sections 4 rank 3, 4 and 14; FBS-205). The Coverage block that prints blanks (it reads pass and total, the result carries totals) is replaced by a coverage summary: family counts as stat tiles, the three class totals as one stacked bar with the percentage covered, and an unresolved-pointers table with the reason the CLI prints. The thin-requirements table keeps its shape and widens its feed to every flavour the Q3 ruling names: zero criteria, criteria with no resolving test, D4 floor failures, plus no story and no plain description. The verdict card counts become links into the tables they count and the What happens next paragraph folds into the cards.",
5
+ "asA": "an engineer or product owner reading the Readiness tab",
6
+ "iWant": "to see how much of the chain is covered by resolving tests and which requirements are thin, as numbers and rows with links",
7
+ "soThat": "I can see the traceability reach without the CLI and open a thin requirement where it lives",
8
+ "tacIds": [
9
+ "TAC-4135-readiness-command-page"
10
+ ],
11
+ "acceptanceCriteria": [
12
+ {
13
+ "id": "AC-18004-1",
14
+ "description": "[happy] Given readiness.coverage.tree carries totals, when the coverage sub-view renders, then CoverageSummary.totals shows requirements, covered, coveredUnresolved and uncovered as numbers and CoverageSummary.percentCovered as a percentage, never a blank value.",
15
+ "testable": true,
16
+ "ownerRef": {
17
+ "tacId": "TAC-4135-readiness-command-page",
18
+ "field": "interfaces[renderCoverageSummary]"
19
+ }
20
+ },
21
+ {
22
+ "id": "AC-18004-2",
23
+ "description": "[happy] Given the tree model, when the coverage sub-view renders, then CoverageSummary.families lists the document counts per family (requirements, stories, criteria, suites, cases, build specs) as stat tiles and one stacked bar whose three widths are the three class totals, using only the --sv-success, --sv-warning and --sv-danger tokens on --sv-surface.",
24
+ "testable": true,
25
+ "ownerRef": {
26
+ "tacId": "TAC-4135-readiness-command-page",
27
+ "field": "interfaces[CoverageSummary]"
28
+ }
29
+ },
30
+ {
31
+ "id": "AC-18004-3",
32
+ "description": "[happy] Given coverage.tree.unresolvedTestPointers is non-empty, when the coverage sub-view renders, then an unresolved-pointers table lists each pointer with its suite id as a link, its case id, the pointer text and the reason word the CLI prints (for example \"test-missing\" or \"file-missing\").",
33
+ "testable": true
34
+ },
35
+ {
36
+ "id": "AC-18004-4",
37
+ "description": "[happy] Given a requirement that fails at least one thin reason from the list [no story | zero criteria on a story | a criterion with no resolving test | a story failing the D4 floors | no plain description], when the thin-requirements table renders, then it carries one ThinReqRow for that requirement with ThinReqRow.stories, ThinReqRow.criteria, ThinReqRow.covered, ThinReqRow.thinReason, ThinReqRow.openHref and ThinReqRow.traceHref.",
38
+ "testable": true,
39
+ "ownerRef": {
40
+ "tacId": "TAC-4135-readiness-command-page",
41
+ "field": "interfaces[renderThinReqsTable]"
42
+ }
43
+ },
44
+ {
45
+ "id": "AC-18004-5",
46
+ "description": "[happy] Given the two verdict cards, when the overview sub-view renders, then the question count on the Ready for engineers card is a link to the questions table, the engineer item count on the Ready to build card is a link to the blocking table, and the former What happens next paragraph is folded into the cards as one sentence each.",
47
+ "testable": true,
48
+ "ownerRef": {
49
+ "tacId": "TAC-4135-readiness-command-page",
50
+ "field": "interfaces[ThinReqRow]"
51
+ }
52
+ },
53
+ {
54
+ "id": "AC-18004-6",
55
+ "description": "[failure] Given a coverage result with no totals (a partial tree or an older compute), when the coverage sub-view renders, then it shows the words \"coverage unavailable\" and the rest of the panel still renders.",
56
+ "testable": true
57
+ },
58
+ {
59
+ "id": "AC-18004-7",
60
+ "description": "[must-not] Given any tree, when the coverage sub-view renders, then it never prints an empty number: a value the coverage result does not carry renders as \"coverage unavailable\", not as a blank.",
61
+ "testable": true
62
+ }
63
+ ],
64
+ "usId": "US-18004",
65
+ "prdId": "PRD-001",
66
+ "reqId": "REQ-180",
67
+ "version": "0.1.0",
68
+ "status": "draft",
69
+ "title": "the Readiness tab shows a coverage summary with real numbers and a thin-requirements table fed by every signal"
70
+ }
@@ -0,0 +1,79 @@
1
+ {
2
+ "createdAt": "2026-10-07T13:46:51.015Z",
3
+ "updatedAt": "2026-10-07T13:46:51.015Z",
4
+ "description": "User story under REQ-180 for the command page (discovery sections 4 rank 5, 6, 11 and 14; FBS-206). The chip row and the stage detail become one stage grid above the fold (D1 to D8 by tree and delta scope, pass/total per cell, failing count linked into the blocking table). The panel is split into five sub-tabs through the shared SubTabStrip with sub= in the hash, restored after an SSE swap. The delta on an unfrozen tree is counts with an on-demand per-document list (Q2). The For-engineers DocRow wrapper is removed and every engineer item survives in a named table or block. The freeze block shows the state and what resolves it in words (Q4). Sub-tabs are the designed shape; one long page with anchor navigation is the named alternative ruled on the rendered sketches (Q5).",
5
+ "asA": "an engineer opening the Readiness tab on a large unfrozen tree",
6
+ "iWant": "the stage states as a grid above the fold, the page split into sub-views, and the delta as counts rather than every document in the tree",
7
+ "soThat": "the command page loads light, reads top-down and never buries the failing ids under a thousand delta rows",
8
+ "tacIds": [
9
+ "TAC-4135-readiness-command-page"
10
+ ],
11
+ "acceptanceCriteria": [
12
+ {
13
+ "id": "AC-18005-1",
14
+ "description": "[happy] Given readiness.stages, when the overview sub-view renders, then a stage grid shows each stage as a row and the scopes \"tree\" and \"delta\" as columns, each VerdictGridCell carrying VerdictGridCell.pass, VerdictGridCell.total and VerdictGridCell.state, with VerdictGridCell.failing rendered as a link into the blocking table filtered to that stage.",
15
+ "testable": true,
16
+ "ownerRef": {
17
+ "tacId": "TAC-4135-readiness-command-page",
18
+ "field": "interfaces[renderVerdictGrid]"
19
+ }
20
+ },
21
+ {
22
+ "id": "AC-18005-2",
23
+ "description": "[happy] Given the Readiness tab, when it renders, then a SubTabStrip offers \"Overview\", \"Questions\", \"Blocking\", \"Coverage\" and \"Trace\", the active key is written into the hash as sub=, and the router restores it on load and after an SSE innerHTML swap of #rcf-live-content.",
24
+ "testable": true,
25
+ "ownerRef": {
26
+ "tacId": "TAC-4135-readiness-command-page",
27
+ "field": "interfaces[readinessSubTabs]"
28
+ }
29
+ },
30
+ {
31
+ "id": "AC-18005-3",
32
+ "description": "[happy] Given an unfrozen tree, when the delta block renders, then DeltaCounts.changed, DeltaCounts.added, DeltaCounts.removed, DeltaCounts.briefSince, DeltaCounts.impacted and DeltaCounts.impactedFbs render as numbers and the per-document list with its diff widgets renders only after the reader expands the details element (DeltaCounts.expanded true).",
33
+ "testable": true,
34
+ "ownerRef": {
35
+ "tacId": "TAC-4135-readiness-command-page",
36
+ "field": "interfaces[renderDeltaCounts]"
37
+ }
38
+ },
39
+ {
40
+ "id": "AC-18005-4",
41
+ "description": "[happy] Given the profile register is \"engineer\", when the tab renders, then the For-engineers DocRow wrapper is absent and every engineer item (failing ids with why, next action, stage states, coverage counts, decisions outstanding, freeze state) is present in a named table or block of the sub-views.",
42
+ "testable": true,
43
+ "ownerRef": {
44
+ "tacId": "TAC-4135-readiness-command-page",
45
+ "field": "interfaces[VerdictGridCell]"
46
+ }
47
+ },
48
+ {
49
+ "id": "AC-18005-5",
50
+ "description": "[happy] Given ready-to-build is \"no\", when the freeze block renders, then it names each failing gate in plain words with what resolves it, with no button and no command text; given ready-to-build is \"yes\", it states that the tree can be frozen and what a freeze would record.",
51
+ "testable": true,
52
+ "ownerRef": {
53
+ "tacId": "TAC-4135-readiness-command-page",
54
+ "field": "interfaces[DeltaCounts]"
55
+ }
56
+ },
57
+ {
58
+ "id": "AC-18005-6",
59
+ "description": "[edge] Given a stage acknowledged at the current tree hash, when the grid renders, then VerdictGridCell.state is \"acknowledged\" and the reason shows on hover, read from stages[].state and one reason helper rather than from freezeRecord.gates directly.",
60
+ "testable": true
61
+ },
62
+ {
63
+ "id": "AC-18005-7",
64
+ "description": "[must-not] Given embed mode (data-embed=\"1\") and a viewport narrower than 720px, when the Readiness tab renders, then no table forces horizontal page scroll: tables collapse to stacked rows and the SubTabStrip stays inside the panel.",
65
+ "testable": true
66
+ },
67
+ {
68
+ "id": "AC-18005-8",
69
+ "description": "[failure] Given a hash whose sub= value is not a known readiness sub-tab key, when the router runs, then the overview sub-view is activated and the unknown value is dropped from the hash.",
70
+ "testable": true
71
+ }
72
+ ],
73
+ "usId": "US-18005",
74
+ "prdId": "PRD-001",
75
+ "reqId": "REQ-180",
76
+ "version": "0.1.0",
77
+ "status": "draft",
78
+ "title": "the Readiness tab is laid out as a stage grid with sub-tabs and delta counts, the For-engineers row retired"
79
+ }
@@ -0,0 +1,74 @@
1
+ {
2
+ "createdAt": "2026-10-07T13:46:52.774Z",
3
+ "updatedAt": "2026-10-07T13:46:52.774Z",
4
+ "description": "User story under REQ-002 for the query routes (discovery section 4 rank 7, server half; FBS-207; TAC-4136, ADR-4140). Three GET routes on the viewer server expose computeTrace, computeImpact and computeCoverage per pivot from the current walked state, memoised by state.version, relative to the mount and release-noted so host proxies allow-list them as they did ./index.json and ./page-init.js. The routes bypass runWithAdmissibilityGate exactly as the CLI coverage, impact and trace verbs do (issues 316 and 317). GET and HEAD only; nothing is written under rcf/.",
5
+ "asA": "an engineer or an embedding host using the viewer",
6
+ "iWant": "trace, impact and coverage for any id as JSON from the running viewer, computed from the same tree the page shows",
7
+ "soThat": "the viewer can render traceability on demand and an agent or host can read the same numbers without a terminal",
8
+ "tacIds": [
9
+ "TAC-4136-view-query-routes"
10
+ ],
11
+ "acceptanceCriteria": [
12
+ {
13
+ "id": "AC-208-1",
14
+ "description": "[happy] Given a running viewer and a known id, when GET \"./trace.json?id=<id>&direction=forward\" is requested, then the response is application/json carrying the computeTrace result for that pivot (pivot, direction, found, nodes, edges), computed from the current state and served with \"cache-control: no-store\" relative to the viewer mount.",
15
+ "testable": true,
16
+ "ownerRef": {
17
+ "tacId": "TAC-4136-view-query-routes",
18
+ "field": "interfaces[GET /trace.json]"
19
+ }
20
+ },
21
+ {
22
+ "id": "AC-208-2",
23
+ "description": "[happy] Given a running viewer and a known id, when GET \"./impact.json?id=<id>\" is requested, then the response is application/json carrying the computeImpact result (pivot, found, nodes with actionNeeded per node, edges) with \"cache-control: no-store\".",
24
+ "testable": true,
25
+ "ownerRef": {
26
+ "tacId": "TAC-4136-view-query-routes",
27
+ "field": "interfaces[GET /impact.json]"
28
+ }
29
+ },
30
+ {
31
+ "id": "AC-208-3",
32
+ "description": "[happy] Given a running viewer, when GET \"./coverage.json\" is requested with no scope, then the response is application/json carrying the strict computeCoverage result for the whole tree (totals, requirements, unresolvedTestPointers); given \"?scope=<id>\" naming a PRD, REQ or US, the result is narrowed to that subtree as the CLI positional narrows it.",
33
+ "testable": true,
34
+ "ownerRef": {
35
+ "tacId": "TAC-4136-view-query-routes",
36
+ "field": "interfaces[GET /coverage.json]"
37
+ }
38
+ },
39
+ {
40
+ "id": "AC-208-4",
41
+ "description": "[failure] Given an unknown id, when trace or impact is requested, then the response is 404 application/json with QueryRouteError.error \"unknown-id\" and QueryRouteError.id echoing the request; given a direction outside forward, back and both, the response is 400 with QueryRouteError.error \"bad-direction\"; given a below-AC or unknown scope on coverage, the response is 400 with QueryRouteError.error \"bad-scope\".",
42
+ "testable": true,
43
+ "ownerRef": {
44
+ "tacId": "TAC-4136-view-query-routes",
45
+ "field": "interfaces[QueryRouteError]"
46
+ }
47
+ },
48
+ {
49
+ "id": "AC-208-5",
50
+ "description": "[must-not] Given any request to the three routes, when the server handles it, then runWithAdmissibilityGate is not called (the routes bypass the gate the way src/cli/coverage.js and src/cli/impact.js do) and nothing under rcf/ is written.",
51
+ "testable": true
52
+ },
53
+ {
54
+ "id": "AC-208-6",
55
+ "description": "[edge] Given a rewalk that publishes a new state.version, when a route is requested, then the served result reflects the new tree and the memo entries of the previous version are discarded; within one version a repeated request for the same pivot and direction is served from the memo without recomputing.",
56
+ "testable": true,
57
+ "ownerRef": {
58
+ "tacId": "TAC-4136-view-query-routes",
59
+ "field": "interfaces[queryCache]"
60
+ }
61
+ },
62
+ {
63
+ "id": "AC-208-7",
64
+ "description": "[failure] Given the server before the first walk completes, when a trace, impact or coverage request arrives, then the response is 503 text \"view server initialising\", as ./index.json answers today.",
65
+ "testable": true
66
+ }
67
+ ],
68
+ "usId": "US-208",
69
+ "prdId": "PRD-001",
70
+ "reqId": "REQ-002",
71
+ "version": "0.1.0",
72
+ "status": "draft",
73
+ "title": "the viewer serves trace, impact and coverage for a selected node as JSON routes computed from the current tree"
74
+ }