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
package/CHANGELOG.md CHANGED
@@ -6,6 +6,48 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.33.0] - 2026-10-09
10
+
11
+ 0.33.0 makes the viewer's Readiness tab the command page: questions, blocking items, a coverage summary, a stage grid with sub-tabs, delta counts and a trace matrix, backed by three new trace, impact and coverage JSON routes with a per-version memo on the viewer server. `rcf verify run` and `rcf build finalise` gain a deterministic mode so a dispatched worker that cannot spawn the agent CLI can still produce a report and refuse promotion honestly. Two watcher and server fixes make the live viewer survive write-temp-then-rename saves and never silently drop a change that lands mid-rewalk. breaking: false; every change is additive on the surfaces consumers run (new routes, new flags, new sub-views, a new verify mode, watcher and rewalk fixes); the `@stravica-ai/rcf-schemas` 0.6.3 pin is unchanged. minAgentAction: null.
12
+
13
+ ### Added
14
+
15
+ - **Readiness tab as the command page: Questions and Blocking tables (FBS-204, US-18003 under REQ-180, PR 332).** The Readiness tabpanel is rebuilt as two linked, read-only command-page tables (TAC-4135 `renderQuestionsTable`, `renderBlockingTable`, `splitCompositeId`; ADR-4139). Questions and Blocking are paired tables with a shared filter bar (stage and persona filters), a copy-for-your-agent control through the shared toast with a textarea fallback, and a `#tab=readiness&...&entity=<itemId>` hash scheme that lands on a non-document row. The engineer blocker cards and the 20-id slice retire; the freeze control is replaced by a plain-words freeze state line that names failing gates and what resolves them. `src/view/readiness/composite-id.js`, `src/view/readiness/tables.js`, updates in `src/view/readiness.js`, `src/view/readiness/po-layer.js`, `src/view/page-init.js` and `src/view/style.css`. AC-18003-1 to AC-18003-8; AC-18001-3, -4 and -6 amended. New table styles sit on existing `--sv-*` tokens so the contrast audit stays green.
16
+ - **Trace, impact and coverage JSON routes with per-version memo (FBS-207, US-208 under REQ-002, PR 335).** Three new viewer routes: `GET /trace.json?id=<id>&direction=<forward|back|both>`, `GET /impact.json?id=<id>` and `GET /coverage.json?scope=<id>`. Each reads the walked tree from server state, calls the pure compute and serves `application/json` with `cache-control: no-store`. A `queryCache` keyed by `${state.version}:${route}:${pivot}:${direction|scope}` is replaced wholesale on every rewalk, so a new tree version never serves a previous version's bytes. The three routes do not call `runWithAdmissibilityGate` so a tree that fails admissibility still answers them; nothing is written under `rcf/`. Error shape: 503 before the first walk completes, 404 `{error:"unknown-id"}` for a missing pivot, 400 `{error:"bad-direction"}` or `{error:"bad-scope"}` on invalid parameters, 405 `Allow: GET, HEAD` for other methods. `renderModelToPage` additionally returns `testPointers` so the three routes share one tree and one resolved pointer map with the rendered page. AC-208-1 to AC-208-7.
17
+ - **Readiness coverage summary and thin-requirements table (FBS-205, US-18004 under REQ-180, PR 338).** New `src/view/readiness/coverage-summary.js` reads `coverage.tree.totals` and `unresolvedTestPointers` and emits a stat line (every slot a number or `coverage unavailable`, never a blank), a stacked bar on `--sv-success` / `--sv-warning` / `--sv-danger` over `--sv-surface`, six family stat tiles, and (when non-empty) an unresolved-pointers table. New `src/view/readiness/thin-reqs.js` widens the former `buildReqWorkRows` to five reasons (`reqHasUs`, `usFloors`, `reqIntent`, `zeroCriteria`, `uncoveredAc`) plus the retained `resolvedBy` signal; each row carries `stories`, `criteria`, `covered`, `thinReason`, `openHref` and `traceHref`. Verdict-card counts on the PO layer become links to the Questions and Blocking tables and the "What happens next" copy folds to one sentence per card. The engineer body no longer renders the old coverage block (it had read `coverage.tree.pass`/`.total`, which the real compute never produces, so it had painted blanks on every live tree). AC-18004-1 to AC-18004-7.
18
+ - **Readiness layout: stage grid, sub-tabs and delta counts (FBS-206, US-18005 under REQ-180, PR 339).** A `SubTabStrip` across Overview, Questions, Blocking, Coverage and Trace carries `sub=` in the hash, restored on load and after an SSE innerHTML swap of `#rcf-live-content`; unknown `sub=` drops to Overview and is cleaned from the hash via `history.replaceState`. `renderVerdictGrid` builds a stage by (tree, delta) grid in Overview; each cell carries pass, total, state and a failing-count link into the Blocking sub-tab filtered to that stage. `renderDeltaCounts` emits six count tiles (`changed`, `added`, `removed`, `briefSince`, `impacted`, `impactedFbs`); the per-document list with its diff widgets sits inside a collapsed `<details>` and only renders when expanded. The For-engineers DocRow wrapper, the stage chips and the stage-detail block retire; freeze state renders in plain words with the "On me" / "On engineers" vocabulary and names each failing gate and what resolves it, or (when ready-to-build) what a freeze would record. CLI `verdictLines` render as a muted parity block in Overview so AC-18001-7 and AC-18002-3 ("every id in the DOM") stay true across sub-views. AC-18005-1 to AC-18005-8.
19
+ - **Trace matrix sub-view (FBS-208, US-209 under REQ-002, PR 340).** The Readiness Trace sub-shell is replaced by a per-pivot matrix with rows per US and AC under the pivot and columns Suites, Cases, Build specs and Components. Cells carry reach and resolution (resolving on `--sv-success`, unresolved on `--sv-warning`, none on `--sv-muted`; no new palette token). `wireTraceMatrix` fetches `./trace.json?id=<pivot>&includeCode=1` and `./coverage.json`, caches per `state.version`, marks the current render stale after an SSE swap and refetches; a row filter kicks in past 200 rows and the empty state offers the lookup. The Questions and Blocking tables and the unresolved-pointers table gain Trace action columns that deep-link into the matrix. The per-REQ Mermaid slice on the Requirements tab retires (the generator in `src/view/mermaid-diagram.js` stays while AC-201-1 binds its unit tests; no user-facing surface renders it any more). AC-209-1 to AC-209-7.
20
+ - **Deterministic verify mode so dispatched workers can run finalise (issue 330, PR 331).** `rcf verify run --mode <agentScreenshotCritique|deterministic>` and the same flag on `rcf build finalise`, defaulting to the pre-existing agent mode so existing runs are unchanged. `src/verify/engine/deterministic.js` is an in-process verifier that probes HTTP reachability and records every testable AC on `blockedAcs[]` as `critique-only`, with `runStats.counts = { verified, failed, skipped, total }`; no chain-level per-AC probe shape exists yet, so BLOCKED is the honest outcome. `src/cli/finalise.js` preseeds the `--out` report with a stub before spawning verify; overwrites it with `{ status: 'aborted', exitCode }` naming the mode when verify exits non-zero without writing (closing the ENOENT the issue cited); refuses promotion on any deterministic-mode run with `counts.skipped > 0` or `counts.verified < counts.total`, referencing ADR-4112; and treats a preseed-only report after a passing exit as unreadable. New ADR-4141, TAC-4141, US-16503 with AC-16503-1 to AC-16503-4, FBS-209 wiring the ACs, and TS-242 binding each AC to its real test pointer; `rcf audit coverage` now exits 0 (119/119 REQ covered). `docs/verify-reference.md` adds Verify modes, the ADR-4112 refusal, the partial-report fallback and a worked example of the forward checkable-AC shape.
21
+
22
+ ### Changed
23
+
24
+ - **Viewer command-page DEFINE chain lands end to end (PR 326).** TAC-4135-readiness-command-page, TAC-4136-view-query-routes, ADR-4139 (viewer read-only, no CLI commands) and ADR-4140 (view query routes per pivot, matrix not Mermaid); US-18003, US-18004 and US-18005 under REQ-180; US-208 and US-209 under REQ-002; TS-237 to TS-241 bound to the five USes; FBS-204 to FBS-208 at build-order 204 to 208 with their AC lists; decisions-ledger Q1 to Q5 resolved; brief-ledger id 1 updated to the DEFINE-stage text. No `src/` changes in this entry; two Q5 render sketches (`5-subtabs`, `6-one-page`) land under `packages/rcf-lite/guidance/discovery/`. The DEFINE additions do not change any pre-existing readiness state.
25
+ - **`/trace.json` additive opt-in `?includeCode=1` (PR 340).** Default behaviour is unchanged for every pre-FBS-208 caller; the `queryCache` key keys on the flag so a mix never serves wrong bytes.
26
+ - **Dogfood suite expectations rise with the FBS-204 to FBS-208 chain adds.** `test/rcf-tree.test.js` codeNode count 348 to 354 for the FBS-208 code-node mints, with proportional bumps as each FBS-204 to FBS-207 PR landed; `test/view/fixtures/phase-3-6-static.html` and `test/build/fixtures/queue.{md,json}` are regenerated as the chain and view-shape changes land; `test/query/fixtures/{coverage,trace,impact}.{json,mmd,table.txt}` are regenerated after the new USes and the TC-description refresh.
27
+
28
+ ### Fixed
29
+
30
+ - **Live viewer survives write-temp-then-rename saves (issue 336, PR 337).** On Linux, Node's recursive `fs.watch` reports the first rename over a file then goes permanently blind to that path, so editors that save by write-temp-then-rename (vim `backupcopy=no`, JetBrains safe-write) silently stall the live viewer with no error and keep it stale until restart. `src/watch/index.js` now re-arms the affected base on a `rename` event: it closes the stale `fs.watch` handle and opens a new one, which re-registers inotify descriptors against the current inodes. The re-arm coalesces onto the existing debounce window, so a burst of renames yields one re-arm per flush. Plain `change` events do not re-arm. The primitive accepts an optional `fsWatchImpl` override as a determinism seam for tests; production callers never pass it.
31
+ - **Mid-rewalk changes coalesce into one trailing walk, and fatal watcher and walker errors always reach stderr (issue 333 items 1 and 2, PR 334).** `src/server/index.js` rewalk previously returned the in-flight walk when a change arrived while a walk was running, silently dropping the change until the next event. A change that arrives mid-rewalk now sets a trailing flag; when the in-flight walk settles, exactly one trailing rewalk runs and picks up the final on-disk state. Any number of concurrent calls collapse onto that single trailing walk; a trailing walk that itself coincides with another change queues one more after it. `startServer` now takes a `logError` option alongside `log`. `log` stays verbose-gated (chatty per-event lines keep flowing through it only when `--verbose` is on); `logError` is unconditional and receives `[server] walker failed` and `[watch] <error>`. `src/cli/view.js` wires `logError` to always write to stderr so a host that spawned `rcf audit view` as a supervised child without `--verbose` still sees a dead watcher instead of silently continuing to appear alive. A caller that passes only `log` keeps the pre-fix one-sink behaviour.
32
+
33
+ ### Notes
34
+
35
+ - Discovery brief and infographics for the viewer command-page restructure land under `packages/rcf-lite/guidance/discovery/`, inside the home carved out at 0.32.5 (PR 323). Chain-first via three brief-ledger statements under `rcf/define/`; two resolve to REQ-180 (command page / readiness) and one to REQ-002 (viewer exposes trace, impact, coverage).
36
+ - One pre-existing env-dependent skip remains (`TC-119 real-account-gated-url-skipped`); eight pre-existing scaffold TODO notices from `rcf define validate` (TAC-4122, FBS-198, TS-216, TS-218, TS-220) are unchanged.
37
+
38
+ ### For embedders
39
+
40
+ Three new viewer routes (`/trace.json`, `/impact.json`, `/coverage.json`) must be added to the reverse-proxy allow-list for `/rcf-viewer/*` before the version pin bump; without the allow-list the new Readiness Trace sub-view cannot fetch its data. The embed contract and the `rcf-view-theme` postMessage are unchanged. Under `embed=1` the standalone theme control stays absent and the `rcf-view:v1:theme` key is never read or written.
41
+
42
+ ## [0.32.5] - 2026-10-07
43
+
44
+ 0.32.5 ships two chain-shape fixes surfaced by Dex on branch `dex/discovery-viewer-command-page` (reporter), closing issues 321 and 322. The dogfood walker in `test/rcf-tree.test.js` now mirrors the sidecar-ledger carve-out from `src/define/ledgers.js` and ignores `rcf/define/`, so the first `pnpm rcf define ledger brief add` on a fresh tree no longer blows up three dogfood assertions. A new `packages/rcf-lite/guidance/discovery/` (and companion `packages/rcf-lite/docs/discovery/`) subdir gives project discovery artefacts a predictable home outside the locked methodology inventories. The three locked slug lists in `test/guidance/inventory.test.js`, `test/mcp/resources.test.js` and `test/docs/links.test.js` are untouched and `guidance/manifest.json` is untouched, so an in-package methodology addition still requires a coordinated test-code change. breaking: false; the 0.32.1 through 0.32.4 fixes carry forward unchanged. minAgentAction: null.
45
+
46
+ ### Fixed
47
+
48
+ - **Dogfood walker ignores `rcf/define/` ledgers (issue 321, reporter Dex, w-2026-10-07-dave-006).** `src/define/ledgers.js` exports the new `DEFINE_RELATIVE_DIR` constant; `test/rcf-tree.test.js:walk()` imports it and skips the directory the exact same way the ledger module writes to it, so the four sidecar ledgers (`brief-ledger.json`, `decisions-ledger.json`, `concern-ledger.json`, `probe-ledger.json`) plus the freeze record never surface to `classify()` or `loadAll()`. `loadAll()` additionally takes an optional project-root override so the carve-out works regardless of where the caller rooted the walk. Regression fixture seeds the four ledgers plus a bug-bait REQ-shaped file under `rcf/define/` and proves none of them surface, while a real chain document outside the carve-out does.
49
+ - **Project discovery home carved out of the locked inventories (issue 322, reporter Dex, w-2026-10-07-dave-006).** `packages/rcf-lite/guidance/discovery/` and `packages/rcf-lite/docs/discovery/` are the new home for DISCOVERY-stage artefacts: discovery briefs, prototype notes, exploratory write-ups, infographic sketches. The subdirs sit outside the top-level non-recursive readdir enumerations the methodology locks use, so a first-time contributor can land a discovery brief without touching the methodology lock or the pack manifest. The guidance posture (no em-dash, no non-canonical external URLs, filename stem is a well-formed slug) still runs over the subdir via a new `test/guidance/discovery-home.test.js`. CONTRIBUTING.md documents the home under chain-first discipline.
50
+
9
51
  ## [0.32.4] - 2026-10-07
10
52
 
11
53
  0.32.4 is the stop-word follow-up to 0.32.3 after Dex's second-consumer check of PR 318 on WESPA main 34ebceba (2026-10-07T10:38Z, issue 319). 0.32.3 moved the English stop-word skip onto the pattern 4 (dot-notation) branch but left patterns 2 and 3 (prose `<name> field` and `fields: <name>`) with no stop-word filter at all; the AC-130-1 then-clause `declares NO join-shaped fields: the earlier jurisdiction ...` fed the word `the` to the extractor and false-failed D6 on WESPA (Ready-to-build no on 0.32.3 against yes on 0.31.0). breaking: false; the 0.32.1, 0.32.2 and 0.32.3 fixes carry forward unchanged. minAgentAction: null.
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "registerCanary": [
3
3
  {
4
- "id": "rc-2026-10-07-001",
5
- "createdAt": "2026-10-07T11:27:52.587Z",
6
- "buildVersion": "0.32.4-mockdriver",
4
+ "id": "rc-2026-10-09-001",
5
+ "createdAt": "2026-10-09T16:13:02.682Z",
6
+ "buildVersion": "0.33.0-mockdriver",
7
7
  "fixturePromptId": "canary-prompt-01",
8
8
  "responseWordCount": 55,
9
9
  "grades": {
@@ -34,9 +34,9 @@
34
34
  "shipDespiteFailReason": "mock canary driver used; no real subagent was dispatched. This record verifies canary infrastructure only, not the register itself."
35
35
  },
36
36
  {
37
- "id": "rc-2026-10-07-002",
38
- "createdAt": "2026-10-07T11:27:52.588Z",
39
- "buildVersion": "0.32.4-mockdriver",
37
+ "id": "rc-2026-10-09-002",
38
+ "createdAt": "2026-10-09T16:13:02.682Z",
39
+ "buildVersion": "0.33.0-mockdriver",
40
40
  "fixturePromptId": "canary-prompt-02",
41
41
  "responseWordCount": 55,
42
42
  "grades": {
@@ -67,9 +67,9 @@
67
67
  "shipDespiteFailReason": "mock canary driver used; no real subagent was dispatched. This record verifies canary infrastructure only, not the register itself."
68
68
  },
69
69
  {
70
- "id": "rc-2026-10-07-003",
71
- "createdAt": "2026-10-07T11:27:52.588Z",
72
- "buildVersion": "0.32.4-mockdriver",
70
+ "id": "rc-2026-10-09-003",
71
+ "createdAt": "2026-10-09T16:13:02.682Z",
72
+ "buildVersion": "0.33.0-mockdriver",
73
73
  "fixturePromptId": "canary-prompt-03",
74
74
  "responseWordCount": 55,
75
75
  "grades": {
@@ -0,0 +1,22 @@
1
+ # guidance/discovery/
2
+
3
+ Home for project discovery artefacts: discovery briefs, prototype
4
+ notes, exploratory write-ups, and anything else that belongs to a
5
+ specific DISCOVERY-stage effort rather than the methodology pack
6
+ itself.
7
+
8
+ Files directly under `guidance/` are the methodology inventory,
9
+ locked by `test/guidance/inventory.test.js` and `test/mcp/resources.test.js`
10
+ and reachable through `rcf://docs/<slug>`. New additions there require a
11
+ coordinated test-code change and a manifest update.
12
+
13
+ Files here, under `guidance/discovery/<slug>.md`, do NOT need a manifest
14
+ update and are not served through the methodology-doc URIs. They still
15
+ carry the guidance posture (no em-dash, no non-canonical external URLs,
16
+ filename stem is a well-formed slug of lowercase letters, digits and
17
+ hyphens); `test/guidance/discovery-home.test.js` enforces that.
18
+
19
+ Companion home for engineer-facing docs: `docs/discovery/`.
20
+
21
+ Issue 322 carved out this subdir so a first-time contributor can land a
22
+ discovery brief without touching the methodology lock.
@@ -0,0 +1,191 @@
1
+ <!doctype html>
2
+ <html lang="en-GB">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <title>Discovery sketch: 1-layout</title>
7
+ <style>
8
+ <!-- F7-note: these --sv-* hex tokens are the LIGHT-mode palette only; the dark-mode block lives in src/view/style.css under html[data-theme="dark"] (and its auto variant) and is covered pair-by-pair by test/view/contrast-aa.test.js. The sketches set color-scheme: light to keep OS dark-mode from re-inking them; the viewer runtime switches tokens by data-theme, not by color-scheme. -->
9
+ :root {
10
+ --sv-canvas: #F6F8FC;
11
+ --sv-surface: #FFFFFF;
12
+ --sv-raised: #EEF2F8;
13
+ --sv-ink: #111927;
14
+ --sv-muted: #536176;
15
+ --sv-border: #D8DFEA;
16
+ --sv-control: #738198;
17
+ --sv-link: #2447EB;
18
+ --sv-hover: #1737C7;
19
+ --sv-active: #E9EEFF;
20
+ --sv-button: #2447EB;
21
+ --sv-onbutton: #FFFFFF;
22
+ --sv-code: #EEF2F8;
23
+ --sv-success: #116B4D;
24
+ --sv-successbg: #E7F4ED;
25
+ --sv-warning: #895000;
26
+ --sv-warningbg: #FFF3DC;
27
+ --sv-danger: #B4233B;
28
+ --sv-dangerbg: #FDECF0;
29
+ --sv-focus: #2447EB;
30
+ --sv-font: Arial, Helvetica, sans-serif;
31
+ --sv-mono: ui-monospace, SFMono-Regular, Consolas, "Liberation Mono", monospace;
32
+ color-scheme: light;
33
+ }
34
+ * { box-sizing: border-box; }
35
+ body { background: var(--sv-canvas); color: var(--sv-ink); font-family: var(--sv-font); margin: 0; }
36
+ main { max-width: 1100px; margin: 0 auto; padding: 30px 16px 22px; }
37
+ p { margin: 0; }
38
+ a { color: var(--sv-link); text-decoration: none; }
39
+ a:hover { color: var(--sv-hover); text-decoration: underline; }
40
+ a:focus-visible, button:focus-visible { outline: 2px solid var(--sv-focus); outline-offset: 4px; }
41
+ .intro { max-width: 980px; margin-bottom: 24px; font-size: 16px; line-height: 1.6; }
42
+ .verdicts { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; margin-bottom: 22px; }
43
+ .card { background: var(--sv-surface); border: 1px solid var(--sv-border); border-radius: 8px; }
44
+ .verdict { padding: 22px 24px; }
45
+ .verdict-heading { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 18px; }
46
+ h1, h2 { margin: 0; }
47
+ .verdict h2 { font-size: 19px; line-height: 1.3; font-weight: 600; }
48
+ .verdict > a { font-size: 14px; line-height: 1.5; }
49
+ .pill { display: inline-block; padding: 5px 10px; border-radius: 20px; font-size: 12px; line-height: 1.25; font-weight: 600; }
50
+ .success { color: var(--sv-success); background: var(--sv-successbg); }
51
+ .warning { color: var(--sv-warning); background: var(--sv-warningbg); }
52
+ .verdict .pill { font-size: 13px; white-space: nowrap; }
53
+ .tabs { display: flex; flex-wrap: wrap; gap: 6px; padding: 0 0 12px; border-bottom: 1px solid var(--sv-border); margin-bottom: 24px; }
54
+ .tabs a { padding: 10px 16px; border-radius: 6px; font-size: 14px; font-weight: 600; }
55
+ .tabs a[aria-current="page"] { background: var(--sv-active); color: var(--sv-link); }
56
+ .section-heading { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; margin-bottom: 14px; }
57
+ h1 { font-size: 21px; line-height: 1.3; letter-spacing: -0.4px; }
58
+ .eyebrow { color: var(--sv-muted); font-size: 11px; font-weight: 600; letter-spacing: 1.2px; text-transform: uppercase; }
59
+ .grid-card { padding: 0 20px 8px; }
60
+ table { width: 100%; border-collapse: collapse; table-layout: fixed; text-align: left; font-size: 14px; }
61
+ caption { color: var(--sv-muted); padding: 16px 0; text-align: left; font-size: 12px; }
62
+ col.stage { width: 9%; }
63
+ col.name { width: 22%; }
64
+ col.count { width: 15%; }
65
+ col.state { width: 24%; }
66
+ col.items { width: 15%; }
67
+ th, td { padding: 12px 10px; border-bottom: 1px solid var(--sv-border); vertical-align: middle; overflow-wrap: anywhere; }
68
+ thead th { background: var(--sv-raised); color: var(--sv-muted); font-size: 11px; letter-spacing: 0.7px; text-transform: uppercase; font-weight: 600; }
69
+ tbody th { font-family: var(--sv-mono); font-size: 13px; font-weight: 500; }
70
+ tbody tr:last-child > * { border-bottom: 0; }
71
+ .mono, code { font-family: var(--sv-mono); }
72
+ .mono { font-size: 13px; }
73
+ .muted { color: var(--sv-muted); }
74
+ .item-link { font-size: 13px; font-weight: 600; }
75
+ .tiles { display: grid; grid-template-columns: 1fr 1.25fr 0.75fr; gap: 14px; margin-top: 16px; }
76
+ .tile { display: flex; flex-direction: column; align-items: flex-start; gap: 12px; min-width: 0; padding: 20px; color: var(--sv-ink); }
77
+ .tile:hover { color: var(--sv-ink); text-decoration: none; border-color: var(--sv-control); }
78
+ .tile-label { font-size: 12px; font-weight: 600; color: var(--sv-muted); }
79
+ .tile-value { font-size: 15px; line-height: 1.5; }
80
+ .tile-value strong { font-weight: 600; }
81
+ .coverage-number { color: var(--sv-warning); }
82
+ .zero { font-size: 26px; line-height: 1.2; }
83
+ .show { color: var(--sv-link); font-size: 12px; margin-top: auto; }
84
+ .tile:hover .show { color: var(--sv-hover); text-decoration: underline; }
85
+ .next-action { display: flex; align-items: baseline; gap: 10px; margin: 20px 0 0; color: var(--sv-muted); font-size: 12px; line-height: 1.8; }
86
+ .next-action p { min-width: 0; }
87
+ code { background: var(--sv-code); padding: 3px 4px; border-radius: 3px; font-size: 11px; overflow-wrap: anywhere; }
88
+ button { font-family: var(--sv-font); font-size: 11px; color: var(--sv-muted); border: 1px solid var(--sv-border); background: var(--sv-surface); border-radius: 4px; padding: 5px 9px; }
89
+ .source { color: var(--sv-muted); margin-top: 28px; font-size: 12px; line-height: 1.7; overflow-wrap: anywhere; }
90
+ footer { margin-top: 20px; padding-top: 16px; border-top: 1px solid var(--sv-border); color: var(--sv-muted); font-size: 11px; line-height: 1.6; }
91
+ @media (max-width: 719px) {
92
+ main { padding-top: 20px; }
93
+ .verdicts, .tiles { grid-template-columns: 1fr; }
94
+ .verdict { padding: 20px; }
95
+ .tabs { gap: 2px; }
96
+ .tabs a { padding: 10px; font-size: 12px; }
97
+ .section-heading { align-items: flex-start; }
98
+ .grid-card { padding: 0 6px 6px; }
99
+ table { font-size: 12px; }
100
+ caption { padding: 14px 5px; }
101
+ th, td { padding: 12px 4px; }
102
+ thead th { font-size: 9px; letter-spacing: 0; }
103
+ .mono, tbody th, .item-link { font-size: 11px; }
104
+ .pill { padding: 4px 5px; font-size: 10px; max-width: 100%; }
105
+ .next-action { flex-wrap: wrap; }
106
+ }
107
+ </style>
108
+ </head>
109
+ <body>
110
+ <main>
111
+ <p class="intro">The rcf-lite viewer's Readiness tab currently mixes two verdict cards with a long scratchpad; this sketch shows the full rebuilt tab as linked tables and tiles that explain whether work can begin.</p>
112
+
113
+ <section aria-label="Readiness command page">
114
+ <div class="verdicts">
115
+ <section class="card verdict" aria-labelledby="engineers-heading">
116
+ <div class="verdict-heading">
117
+ <h2 id="engineers-heading">Ready for engineers</h2>
118
+ <span class="pill success">Yes</span>
119
+ </div>
120
+ <a href="#" title="#tab=readiness&amp;surface=questions">0 questions waiting for you</a>
121
+ </section>
122
+ <section class="card verdict" aria-labelledby="build-heading">
123
+ <div class="verdict-heading">
124
+ <h2 id="build-heading">Ready to build</h2>
125
+ <span class="pill warning">Not yet</span>
126
+ </div>
127
+ <a href="#" title="#tab=readiness&amp;surface=blocking">2 items for engineers, none for you</a>
128
+ </section>
129
+ </div>
130
+
131
+ <nav class="tabs" aria-label="Readiness sub-tabs">
132
+ <a href="#" title="#tab=readiness&amp;surface=overview" aria-current="page">Overview</a>
133
+ <a href="#" title="#tab=readiness&amp;surface=questions">Questions</a>
134
+ <a href="#" title="#tab=readiness&amp;surface=blocking">Blocking</a>
135
+ <a href="#" title="#tab=readiness&amp;surface=coverage">Coverage</a>
136
+ <a href="#" title="#tab=readiness&amp;surface=trace">Trace</a>
137
+ </nav>
138
+
139
+ <section aria-labelledby="grid-heading">
140
+ <div class="section-heading">
141
+ <h1 id="grid-heading">Readiness verdicts</h1>
142
+ <span class="eyebrow">Overview</span>
143
+ </div>
144
+ <div class="card grid-card">
145
+ <table>
146
+ <caption>D1 to D8 verdict grid, 8 rows</caption>
147
+ <colgroup><col class="stage"><col class="name"><col class="count"><col class="count"><col class="state"><col class="items"></colgroup>
148
+ <thead>
149
+ <tr><th scope="col">Stage</th><th scope="col">Name</th><th scope="col">Tree</th><th scope="col">Delta</th><th scope="col">State</th><th scope="col">Items</th></tr>
150
+ </thead>
151
+ <tbody>
152
+ <tr><th scope="row">D1</th><td>Brief</td><td class="mono">4/4</td><td class="mono">4/4</td><td><span class="pill success">pass</span></td><td class="muted">0</td></tr>
153
+ <tr><th scope="row">D2</th><td>Skeleton</td><td class="mono">6/6</td><td class="mono">6/6</td><td><span class="pill success">pass</span></td><td class="muted">0</td></tr>
154
+ <tr><th scope="row">D3</th><td>Shapes</td><td class="mono">8/8</td><td class="mono">8/8</td><td><span class="pill success">pass</span></td><td class="muted">0</td></tr>
155
+ <tr><th scope="row">D4</th><td>Stories</td><td class="mono">7/7</td><td class="mono">7/7</td><td><span class="pill success">pass</span></td><td class="muted">0</td></tr>
156
+ <tr><th scope="row">D5</th><td>Crosscut</td><td class="mono">5/5</td><td class="mono">5/5</td><td><span class="pill success">pass</span></td><td class="muted">0</td></tr>
157
+ <tr><th scope="row">D6</th><td>Consistency</td><td class="mono">9/9</td><td class="mono">7/9</td><td><span class="pill warning">unsatisfiable</span></td><td><a class="item-link" href="#" title="#tab=readiness&amp;surface=blocking&amp;stage=D6&amp;over=delta">2 <span class="muted">Delta</span></a></td></tr>
158
+ <tr><th scope="row">D7</th><td>Decisions</td><td class="mono">3/3</td><td class="mono">3/3</td><td><span class="pill success">pass</span></td><td class="muted">0</td></tr>
159
+ <tr><th scope="row">D8</th><td>Freeze</td><td class="mono">2/3</td><td class="mono">3/3</td><td><span class="pill warning">priorGates</span></td><td><a class="item-link" href="#" title="#tab=readiness&amp;surface=blocking&amp;stage=D8&amp;over=tree">1 <span class="muted">Tree</span></a></td></tr>
160
+ </tbody>
161
+ </table>
162
+ </div>
163
+
164
+ <div class="tiles">
165
+ <a class="card tile" href="#" title="#tab=readiness&amp;surface=overview&amp;section=delta">
166
+ <span class="tile-label">Delta</span>
167
+ <span class="tile-value"><strong>616 added</strong>, 0 changed, 0 removed</span>
168
+ <span class="show">show</span>
169
+ </a>
170
+ <a class="card tile" href="#" title="#tab=readiness&amp;surface=coverage">
171
+ <span class="tile-label">Coverage</span>
172
+ <span class="tile-value"><strong class="coverage-number">15 of 55 requirements covered (27 percent)</strong></span>
173
+ </a>
174
+ <a class="card tile" href="#" title="#tab=readiness&amp;surface=questions&amp;kind=decision">
175
+ <span class="tile-label">Open decisions</span>
176
+ <span class="tile-value zero">0</span>
177
+ </a>
178
+ </div>
179
+
180
+ <div class="next-action">
181
+ <p>Next action (engineer): D6 consistency:unsatisfiable, 2 items, re-check with <code>rcf define readiness --check consistency</code></p>
182
+ <button type="button" title="copies the re-check command">Copy</button>
183
+ </div>
184
+ </section>
185
+ </section>
186
+
187
+ <p class="source">Data: readiness.levels, readiness.stages[].checks[] grouped by over, readiness.delta, readiness.coverage.tree.totals. The For-engineers row no longer exists on the page; its content now lives on the Blocking and Coverage sub-tabs.</p>
188
+ <footer>Static sketch for the rcf-lite discovery document; mocked data, light theme.</footer>
189
+ </main>
190
+ </body>
191
+ </html>
@@ -0,0 +1,193 @@
1
+ <!doctype html>
2
+ <html lang="en-GB">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <title>Discovery sketch: 2-coverage</title>
7
+ <style>
8
+ <!-- F7-note: these --sv-* hex tokens are the LIGHT-mode palette only; the dark-mode block lives in src/view/style.css under html[data-theme="dark"] (and its auto variant) and is covered pair-by-pair by test/view/contrast-aa.test.js. The sketches set color-scheme: light to keep OS dark-mode from re-inking them; the viewer runtime switches tokens by data-theme, not by color-scheme. -->
9
+ :root {
10
+ --sv-canvas: #F6F8FC; --sv-surface: #FFFFFF; --sv-raised: #EEF2F8; --sv-ink: #111927;
11
+ --sv-muted: #536176; --sv-border: #D8DFEA; --sv-control: #738198; --sv-link: #2447EB;
12
+ --sv-hover: #1737C7; --sv-active: #E9EEFF; --sv-button: #2447EB; --sv-onbutton: #FFFFFF;
13
+ --sv-code: #EEF2F8; --sv-success: #116B4D; --sv-successbg: #E7F4ED; --sv-warning: #895000;
14
+ --sv-warningbg: #FFF3DC; --sv-danger: #B4233B; --sv-dangerbg: #FDECF0; --sv-focus: #2447EB;
15
+ --sv-font: Arial, Helvetica, sans-serif;
16
+ --sv-mono: ui-monospace, SFMono-Regular, Consolas, "Liberation Mono", monospace;
17
+ }
18
+ * { box-sizing: border-box; }
19
+ body { background: var(--sv-canvas); color: var(--sv-ink); font-family: var(--sv-font); margin: 0; }
20
+ main { max-width: 1100px; padding: 28px 16px 20px; margin: 0 auto; }
21
+ p { line-height: 1.55; }
22
+ .intro { max-width: 850px; font-size: 17px; margin: 0 0 22px; }
23
+ .panel, .stat { background: var(--sv-surface); border: 1px solid var(--sv-border); border-radius: 8px; }
24
+ .panel { padding: 24px; }
25
+ .heading { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 20px; }
26
+ h1 { font-size: 25px; letter-spacing: -.6px; margin: 0; }
27
+ .eyebrow { color: var(--sv-muted); font-size: 11px; font-weight: 700; letter-spacing: 1.2px; text-transform: uppercase; margin: 0 0 7px; }
28
+ .mock { font-size: 11px; color: var(--sv-muted); padding: 6px 9px; border: 1px solid var(--sv-border); border-radius: 4px; white-space: nowrap; }
29
+ .stats { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 10px; }
30
+ .stat { padding: 16px 12px; min-width: 0; }
31
+ .number { display: block; color: var(--sv-ink); font-size: clamp(24px, 3vw, 32px); font-weight: 700; letter-spacing: -1px; font-variant-numeric: tabular-nums; }
32
+ .label { display: block; color: var(--sv-muted); font-size: 12px; margin-top: 6px; }
33
+ .secondary { display: block; font-size: 11px; line-height: 1.4; margin-top: 9px; color: var(--sv-warning); }
34
+ .coverage { display: grid; grid-template-columns: minmax(0, 1fr) 150px; gap: 32px; align-items: center; margin: 28px 0 30px; }
35
+ h2 { font-size: 16px; margin: 0 0 7px; }
36
+ .summary { font-size: 13px; color: var(--sv-muted); margin: 0 0 13px; }
37
+ .summary strong { color: var(--sv-warning); }
38
+ .bar { display: flex; height: 36px; overflow: hidden; border-radius: 5px; }
39
+ .segment { display: flex; align-items: center; justify-content: center; color: var(--sv-onbutton); font-size: 13px; font-weight: 700; }
40
+ .covered-segment { flex-basis: 27.272727%; background: var(--sv-success); }
41
+ .unresolved-segment { flex-basis: 21.818182%; background: var(--sv-warning); }
42
+ .uncovered-segment { flex-basis: 50.909091%; background: var(--sv-danger); }
43
+ .legend { list-style: none; margin: 14px 0 0; padding: 0; display: grid; gap: 8px; }
44
+ .legend li { display: flex; align-items: baseline; gap: 8px; color: var(--sv-muted); font-size: 12px; line-height: 1.4; }
45
+ .legend strong { color: var(--sv-ink); font-weight: 600; }
46
+ .swatch { width: 9px; height: 9px; flex: 0 0 9px; border-radius: 2px; }
47
+ .swatch.success { background: var(--sv-success); }
48
+ .swatch.warning { background: var(--sv-warning); }
49
+ .swatch.danger { background: var(--sv-danger); }
50
+ figure { margin: 0; text-align: center; }
51
+ .donut { display: block; width: 120px; height: 120px; margin: 0 auto; }
52
+ .donut circle { fill: none; stroke-width: 20; }
53
+ .arc-success { stroke: var(--sv-success); }
54
+ .arc-warning { stroke: var(--sv-warning); }
55
+ .arc-danger { stroke: var(--sv-danger); }
56
+ .donut-percent { fill: var(--sv-warning); font-family: var(--sv-font); font-size: 23px; font-weight: 700; }
57
+ .donut-label { fill: var(--sv-muted); font-family: var(--sv-font); font-size: 10px; }
58
+ figcaption { color: var(--sv-muted); font-size: 11px; margin-top: 12px; }
59
+ table { border-collapse: separate; border-spacing: 0; width: 100%; table-layout: fixed; font-size: 12px; }
60
+ caption { text-align: left; color: var(--sv-ink); font-size: 16px; font-weight: 700; padding-bottom: 13px; line-height: 1.5; }
61
+ caption span { color: var(--sv-muted); font-size: 11px; font-weight: 400; }
62
+ th, td { padding: 12px 8px; border-bottom: 1px solid var(--sv-border); text-align: left; vertical-align: middle; overflow-wrap: anywhere; }
63
+ thead th { color: var(--sv-muted); background: var(--sv-raised); font-size: 10px; font-weight: 700; }
64
+ thead th:first-child { border-radius: 5px 0 0 0; }
65
+ thead th:last-child { border-radius: 0 5px 0 0; }
66
+ tbody th { font-weight: 400; }
67
+ .mono, code { font-family: var(--sv-mono); font-size: 11px; }
68
+ .numeric { text-align: right; font-variant-numeric: tabular-nums; }
69
+ .pill { display: inline-block; border-radius: 20px; padding: 4px 7px; font-size: 10px; font-weight: 700; white-space: nowrap; }
70
+ .pill.covered { color: var(--sv-success); background: var(--sv-successbg); }
71
+ .pill.unresolved { color: var(--sv-warning); background: var(--sv-warningbg); }
72
+ .pill.uncovered { color: var(--sv-danger); background: var(--sv-dangerbg); }
73
+ a { color: var(--sv-link); text-decoration: none; }
74
+ a:hover { color: var(--sv-hover); text-decoration: underline; }
75
+ a:focus-visible { outline: 2px solid var(--sv-focus); outline-offset: 3px; border-radius: 2px; }
76
+ .pointers { margin-top: 30px; }
77
+ .pointers td:last-child { color: var(--sv-warning); }
78
+ .continuation { font-size: 12px; color: var(--sv-muted); margin: 12px 0 0; }
79
+ code { background: var(--sv-code); border-radius: 3px; padding: 2px 4px; overflow-wrap: anywhere; }
80
+ .source { font-size: 12px; color: var(--sv-muted); margin: 18px 0; overflow-wrap: anywhere; }
81
+ footer { border-top: 1px solid var(--sv-border); padding-top: 13px; color: var(--sv-muted); font-size: 11px; line-height: 1.5; }
82
+ @media (min-width: 720px) and (max-width: 900px) {
83
+ .panel { padding: 16px; }
84
+ .stat { padding: 14px 8px; }
85
+ th, td { padding: 11px 4px; }
86
+ .pill { padding: 4px 5px; font-size: 9px; }
87
+ .mono { font-size: 10px; }
88
+ }
89
+ @media (max-width: 719px) {
90
+ main { padding-top: 20px; }
91
+ .panel { padding: 16px; }
92
+ .intro { font-size: 16px; }
93
+ .stats { grid-template-columns: repeat(3, minmax(0, 1fr)); }
94
+ .coverage { grid-template-columns: minmax(0, 1fr); gap: 22px; }
95
+ .heading { align-items: flex-start; }
96
+ h1 { font-size: 22px; }
97
+ table, caption, tbody, tr, td, tbody th { display: block; width: 100%; }
98
+ thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
99
+ tbody { display: grid; gap: 12px; }
100
+ tbody tr { border: 1px solid var(--sv-border); border-radius: 6px; overflow: hidden; }
101
+ tbody th, tbody td { display: grid; grid-template-columns: 92px minmax(0, 1fr); gap: 8px; text-align: left; padding: 9px 10px; align-items: center; }
102
+ tbody th { background: var(--sv-raised); }
103
+ tbody td:last-child { border-bottom: 0; }
104
+ tbody th::before, tbody td::before { content: attr(data-label); font-family: var(--sv-font); font-size: 11px; color: var(--sv-muted); font-weight: 400; }
105
+ .pill { justify-self: start; }
106
+ }
107
+ @media (max-width: 380px) {
108
+ .stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
109
+ .heading { flex-wrap: wrap; }
110
+ }
111
+ </style>
112
+ </head>
113
+ <body>
114
+ <main>
115
+ <p class="intro">The Coverage sub-tab turns raw test coverage counts and unresolved test references into a chart-and-table report.</p>
116
+ <section class="panel" aria-labelledby="page-title">
117
+ <header class="heading">
118
+ <div><p class="eyebrow">Discovery / Coverage</p><h1 id="page-title">Coverage summary</h1></div>
119
+ <span class="mock">Static mock</span>
120
+ </header>
121
+ <div class="stats" aria-label="Tree totals">
122
+ <div class="stat"><span class="number">55</span><span class="label">Requirements</span><span class="secondary">27 percent covered</span></div>
123
+ <div class="stat"><span class="number">165</span><span class="label">Stories</span></div>
124
+ <div class="stat"><span class="number">1,121</span><span class="label">Criteria</span></div>
125
+ <div class="stat"><span class="number">188</span><span class="label">Test suites</span></div>
126
+ <div class="stat"><span class="number">1,314</span><span class="label">Test cases</span></div>
127
+ <div class="stat"><span class="number">128</span><span class="label">Build specs</span></div>
128
+ </div>
129
+ <section class="coverage" aria-labelledby="distribution-title">
130
+ <div>
131
+ <h2 id="distribution-title">Requirement coverage</h2>
132
+ <p class="summary"><strong>15 of 55</strong> requirements covered</p>
133
+ <div class="bar" role="img" aria-label="55 requirements: 15 covered, 12 covered-unresolved, 28 uncovered">
134
+ <div class="segment covered-segment" title="15 covered">15</div>
135
+ <div class="segment unresolved-segment" title="12 covered-unresolved">12</div>
136
+ <div class="segment uncovered-segment" title="28 uncovered">28</div>
137
+ </div>
138
+ <ul class="legend">
139
+ <li><span class="swatch success" aria-hidden="true"></span><span><strong>covered:</strong> every criterion has a test that resolves on disk</span></li>
140
+ <li><span class="swatch warning" aria-hidden="true"></span><span><strong>unresolved:</strong> a test is named but its pointer does not resolve</span></li>
141
+ <li><span class="swatch danger" aria-hidden="true"></span><span><strong>uncovered:</strong> at least one criterion has no test</span></li>
142
+ </ul>
143
+ </div>
144
+ <figure>
145
+ <svg class="donut" viewBox="0 0 120 120" role="img" aria-labelledby="donut-title donut-desc">
146
+ <title id="donut-title">27% covered</title>
147
+ <desc id="donut-desc">15 covered, 12 unresolved and 28 uncovered requirements, out of 55.</desc>
148
+ <g transform="rotate(-90 60 60)">
149
+ <circle class="arc-success" cx="60" cy="60" r="50" stroke-dasharray="85.679800 228.479465" />
150
+ <circle class="arc-warning" cx="60" cy="60" r="50" stroke-dasharray="68.543840 245.615425" stroke-dashoffset="-85.679800" />
151
+ <circle class="arc-danger" cx="60" cy="60" r="50" stroke-dasharray="159.935625 154.223640" stroke-dashoffset="-154.223640" />
152
+ </g>
153
+ <text class="donut-percent" x="60" y="60" text-anchor="middle">27%</text>
154
+ <text class="donut-label" x="60" y="76" text-anchor="middle">covered</text>
155
+ </svg>
156
+ <figcaption>Share of 55 requirements</figcaption>
157
+ </figure>
158
+ </section>
159
+ <table aria-label="Requirements by coverage class">
160
+ <caption>Requirements by coverage class<span>, 8 rows (truncated from 55)</span></caption>
161
+ <colgroup><col style="width:12%"><col style="width:25%"><col style="width:8%"><col style="width:8%"><col style="width:9%"><col style="width:16%"><col style="width:11%"><col style="width:11%"></colgroup>
162
+ <thead><tr><th scope="col">Requirement</th><th scope="col">Title</th><th scope="col" class="numeric">Stories</th><th scope="col" class="numeric">Criteria</th><th scope="col" class="numeric">Covered</th><th scope="col">Class</th><th scope="col">Open</th><th scope="col">Trace</th></tr></thead>
163
+ <tbody>
164
+ <tr><th scope="row" data-label="Requirement" class="mono">REQ-022</th><td data-label="Title">Natural language query</td><td data-label="Stories" class="numeric">2</td><td data-label="Criteria" class="numeric">18</td><td data-label="Covered" class="numeric">0</td><td data-label="Class"><span class="pill uncovered">uncovered</span></td><td data-label="Open"><a href="#" title="#tab=requirements&amp;entity=REQ-022">Open</a></td><td data-label="Trace"><a href="#" title="#tab=trace&amp;id=REQ-022">Trace</a></td></tr>
165
+ <tr><th scope="row" data-label="Requirement" class="mono">REQ-031</th><td data-label="Title">Audit export</td><td data-label="Stories" class="numeric">3</td><td data-label="Criteria" class="numeric">22</td><td data-label="Covered" class="numeric">0</td><td data-label="Class"><span class="pill uncovered">uncovered</span></td><td data-label="Open"><a href="#" title="#tab=requirements&amp;entity=REQ-031">Open</a></td><td data-label="Trace"><a href="#" title="#tab=trace&amp;id=REQ-031">Trace</a></td></tr>
166
+ <tr><th scope="row" data-label="Requirement" class="mono">REQ-004</th><td data-label="Title">Freeze workflow</td><td data-label="Stories" class="numeric">1</td><td data-label="Criteria" class="numeric">7</td><td data-label="Covered" class="numeric">0</td><td data-label="Class"><span class="pill uncovered">uncovered</span></td><td data-label="Open"><a href="#" title="#tab=requirements&amp;entity=REQ-004">Open</a></td><td data-label="Trace"><a href="#" title="#tab=trace&amp;id=REQ-004">Trace</a></td></tr>
167
+ <tr><th scope="row" data-label="Requirement" class="mono">REQ-018</th><td data-label="Title">Delta rendering</td><td data-label="Stories" class="numeric">2</td><td data-label="Criteria" class="numeric">14</td><td data-label="Covered" class="numeric">9</td><td data-label="Class"><span class="pill unresolved">unresolved</span></td><td data-label="Open"><a href="#" title="#tab=requirements&amp;entity=REQ-018">Open</a></td><td data-label="Trace"><a href="#" title="#tab=trace&amp;id=REQ-018">Trace</a></td></tr>
168
+ <tr><th scope="row" data-label="Requirement" class="mono">REQ-007</th><td data-label="Title">Consistency checks</td><td data-label="Stories" class="numeric">3</td><td data-label="Criteria" class="numeric">24</td><td data-label="Covered" class="numeric">17</td><td data-label="Class"><span class="pill unresolved">unresolved</span></td><td data-label="Open"><a href="#" title="#tab=requirements&amp;entity=REQ-007">Open</a></td><td data-label="Trace"><a href="#" title="#tab=trace&amp;id=REQ-007">Trace</a></td></tr>
169
+ <tr><th scope="row" data-label="Requirement" class="mono">REQ-012</th><td data-label="Title">Coverage render</td><td data-label="Stories" class="numeric">2</td><td data-label="Criteria" class="numeric">15</td><td data-label="Covered" class="numeric">15</td><td data-label="Class"><span class="pill covered">covered</span></td><td data-label="Open"><a href="#" title="#tab=requirements&amp;entity=REQ-012">Open</a></td><td data-label="Trace"><a href="#" title="#tab=trace&amp;id=REQ-012">Trace</a></td></tr>
170
+ <tr><th scope="row" data-label="Requirement" class="mono">REQ-001</th><td data-label="Title">Readiness verdict</td><td data-label="Stories" class="numeric">2</td><td data-label="Criteria" class="numeric">11</td><td data-label="Covered" class="numeric">11</td><td data-label="Class"><span class="pill covered">covered</span></td><td data-label="Open"><a href="#" title="#tab=requirements&amp;entity=REQ-001">Open</a></td><td data-label="Trace"><a href="#" title="#tab=trace&amp;id=REQ-001">Trace</a></td></tr>
171
+ <tr><th scope="row" data-label="Requirement" class="mono">REQ-015</th><td data-label="Title">Trace matrix</td><td data-label="Stories" class="numeric">1</td><td data-label="Criteria" class="numeric">9</td><td data-label="Covered" class="numeric">9</td><td data-label="Class"><span class="pill covered">covered</span></td><td data-label="Open"><a href="#" title="#tab=requirements&amp;entity=REQ-015">Open</a></td><td data-label="Trace"><a href="#" title="#tab=trace&amp;id=REQ-015">Trace</a></td></tr>
172
+ </tbody>
173
+ </table>
174
+ <table class="pointers" aria-label="Unresolved test pointers">
175
+ <caption>Unresolved test pointers<span>, 6 of 94 shown</span></caption>
176
+ <colgroup><col style="width:16%"><col style="width:20%"><col style="width:46%"><col style="width:18%"></colgroup>
177
+ <thead><tr><th scope="col">Suite</th><th scope="col">Case</th><th scope="col">Pointer</th><th scope="col">Reason</th></tr></thead>
178
+ <tbody>
179
+ <tr><th scope="row" data-label="Suite" class="mono">TS-018-a</th><td data-label="Case" class="mono">TC-018-a-04</td><td data-label="Pointer" class="mono">tests/rcf/foo.spec.mjs::case</td><td data-label="Reason" class="mono">test-missing</td></tr>
180
+ <tr><th scope="row" data-label="Suite" class="mono">TS-018-a</th><td data-label="Case" class="mono">TC-018-a-05</td><td data-label="Pointer" class="mono">tests/rcf/foo.spec.mjs::case</td><td data-label="Reason" class="mono">test-missing</td></tr>
181
+ <tr><th scope="row" data-label="Suite" class="mono">TS-022-b</th><td data-label="Case" class="mono">TC-022-b-01</td><td data-label="Pointer" class="mono">tests/rcf/query.spec.mjs::nlq</td><td data-label="Reason" class="mono">file-missing</td></tr>
182
+ <tr><th scope="row" data-label="Suite" class="mono">TS-031-a</th><td data-label="Case" class="mono">TC-031-a-02</td><td data-label="Pointer" class="mono">tests/rcf/export.spec.mjs::audit</td><td data-label="Reason" class="mono">test-missing</td></tr>
183
+ <tr><th scope="row" data-label="Suite" class="mono">TS-007-c</th><td data-label="Case" class="mono">TC-007-c-03</td><td data-label="Pointer" class="mono">tests/rcf/consistency.spec.mjs::shape</td><td data-label="Reason" class="mono">test-missing</td></tr>
184
+ <tr><th scope="row" data-label="Suite" class="mono">TS-018-b</th><td data-label="Case" class="mono">TC-018-b-01</td><td data-label="Pointer" class="mono">tests/rcf/delta.spec.mjs::row</td><td data-label="Reason" class="mono">file-missing</td></tr>
185
+ </tbody>
186
+ </table>
187
+ <p class="continuation">List continues; the full set is available from <code>rcf audit coverage --json</code>.</p>
188
+ </section>
189
+ <p class="source">Data: coverage.tree.totals, coverage.tree.requirements[].coverageClass, coverage.tree.unresolvedTestPointers[], family counts from the tree model. Today the Coverage block prints a blank where this page prints 15 of 55.</p>
190
+ <footer>Static sketch for the rcf-lite discovery document; mocked data, light theme.</footer>
191
+ </main>
192
+ </body>
193
+ </html>