rcf-lite 0.28.2 → 0.29.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (327) hide show
  1. package/CHANGELOG.md +317 -0
  2. package/bin/rcf.js +8 -0
  3. package/fixtures/canary-manifest.json +9 -9
  4. package/guidance/define-draft-shapes.md +89 -0
  5. package/guidance/define-intake.md +97 -0
  6. package/guidance/define-intent.md +107 -0
  7. package/guidance/discover-prototype.md +67 -0
  8. package/guidance/discovery-prototypes.md +69 -0
  9. package/guidance/harness-template.md +34 -0
  10. package/guidance/managed/agent-instructions-block.hash +1 -1
  11. package/guidance/managed/agent-instructions-block.md +34 -0
  12. package/guidance/manifest.json +9 -2
  13. package/package.json +1 -1
  14. package/rcf/adrs/adr-4120-canonical-json-hashing.json +30 -0
  15. package/rcf/adrs/adr-4121-define-sidecars.json +30 -0
  16. package/rcf/adrs/adr-4122-define-gates-blocking-and-optout.json +30 -0
  17. package/rcf/adrs/adr-4123-readiness-single-object.json +30 -0
  18. package/rcf/adrs/adr-4124-define-freeze-verb.json +30 -0
  19. package/rcf/adrs/adr-4126-persona-tagged-blockers-two-levels.json +40 -0
  20. package/rcf/adrs/adr-4127-readiness-tab-order-and-register.json +40 -0
  21. package/rcf/adrs/adr-4129-questions-harness-driven-loop.json +25 -0
  22. package/rcf/adrs/adr-4130-intake-harness-split-tool-scanned.json +20 -0
  23. package/rcf/adrs/adr-4132-prototypes-in-discovery-as-evidence.json +20 -0
  24. package/rcf/adrs/adr-4133-dag-dependency-depth-layout.json +40 -0
  25. package/rcf/adrs/adr-4134-index-json-route.json +35 -0
  26. package/rcf/adrs/adr-4135-readiness-po-register-and-adapter.json +35 -0
  27. package/rcf/adrs/adr-4136-embedding-host-fixture.json +35 -0
  28. package/rcf/code-nodes/cn-700.json +23 -0
  29. package/rcf/code-nodes/cn-701.json +14 -0
  30. package/rcf/code-nodes/cn-702.json +14 -0
  31. package/rcf/code-nodes/cn-703.json +16 -0
  32. package/rcf/code-nodes/cn-720.json +15 -0
  33. package/rcf/code-nodes/cn-721.json +15 -0
  34. package/rcf/code-nodes/cn-722.json +15 -0
  35. package/rcf/code-nodes/cn-723.json +18 -0
  36. package/rcf/code-nodes/cn-724.json +14 -0
  37. package/rcf/code-nodes/cn-725.json +37 -0
  38. package/rcf/code-nodes/cn-726.json +25 -0
  39. package/rcf/code-nodes/cn-727.json +23 -0
  40. package/rcf/code-nodes/cn-728.json +37 -0
  41. package/rcf/code-nodes/cn-729.json +26 -0
  42. package/rcf/code-nodes/cn-730.json +24 -0
  43. package/rcf/code-nodes/cn-731.json +20 -0
  44. package/rcf/code-nodes/cn-732.json +14 -0
  45. package/rcf/code-nodes/cn-733.json +14 -0
  46. package/rcf/code-nodes/cn-734.json +14 -0
  47. package/rcf/code-nodes/cn-735.json +20 -0
  48. package/rcf/code-nodes/cn-736.json +14 -0
  49. package/rcf/code-nodes/cn-737.json +14 -0
  50. package/rcf/code-nodes/cn-738.json +14 -0
  51. package/rcf/code-nodes/cn-739.json +18 -0
  52. package/rcf/code-nodes/cn-740.json +19 -0
  53. package/rcf/code-nodes/cn-741.json +16 -0
  54. package/rcf/code-nodes/cn-742.json +16 -0
  55. package/rcf/code-nodes/cn-743.json +15 -0
  56. package/rcf/code-nodes/cn-744.json +22 -0
  57. package/rcf/code-nodes/cn-745.json +16 -0
  58. package/rcf/code-nodes/cn-746.json +14 -0
  59. package/rcf/code-nodes/cn-747.json +18 -0
  60. package/rcf/code-nodes/cn-748.json +16 -0
  61. package/rcf/code-nodes/cn-749.json +16 -0
  62. package/rcf/code-nodes/cn-750.json +15 -0
  63. package/rcf/code-nodes/cn-751.json +18 -0
  64. package/rcf/code-nodes/cn-752.json +14 -0
  65. package/rcf/fbs/fbs-190.json +37 -0
  66. package/rcf/fbs/fbs-191.json +34 -0
  67. package/rcf/fbs/fbs-192.json +17 -0
  68. package/rcf/fbs/fbs-193.json +37 -0
  69. package/rcf/fbs/fbs-194.json +35 -0
  70. package/rcf/fbs/fbs-195.json +37 -0
  71. package/rcf/fbs/fbs-196.json +45 -0
  72. package/rcf/fbs/fbs-197.json +41 -0
  73. package/rcf/fbs/fbs-198.json +42 -0
  74. package/rcf/fbs/fbs-199.json +59 -0
  75. package/rcf/fbs/fbs-200.json +46 -0
  76. package/rcf/fbs/fbs-201.json +49 -0
  77. package/rcf/fbs/fbs-202.json +110 -0
  78. package/rcf/fbs/fbs-203.json +100 -0
  79. package/rcf/requirements/req-001.json +2 -1
  80. package/rcf/requirements/req-002.json +3 -2
  81. package/rcf/requirements/req-003.json +2 -1
  82. package/rcf/requirements/req-004.json +2 -1
  83. package/rcf/requirements/req-005.json +2 -1
  84. package/rcf/requirements/req-006.json +2 -1
  85. package/rcf/requirements/req-007.json +2 -1
  86. package/rcf/requirements/req-008.json +2 -1
  87. package/rcf/requirements/req-009.json +2 -1
  88. package/rcf/requirements/req-010.json +5 -2
  89. package/rcf/requirements/req-011.json +2 -1
  90. package/rcf/requirements/req-012.json +2 -1
  91. package/rcf/requirements/req-013.json +2 -1
  92. package/rcf/requirements/req-014.json +2 -1
  93. package/rcf/requirements/req-015.json +2 -1
  94. package/rcf/requirements/req-016.json +5 -2
  95. package/rcf/requirements/req-017.json +6 -2
  96. package/rcf/requirements/req-018.json +5 -2
  97. package/rcf/requirements/req-019.json +5 -2
  98. package/rcf/requirements/req-020.json +5 -2
  99. package/rcf/requirements/req-021.json +5 -2
  100. package/rcf/requirements/req-022.json +5 -2
  101. package/rcf/requirements/req-023.json +6 -4
  102. package/rcf/requirements/req-024.json +5 -2
  103. package/rcf/requirements/req-025.json +5 -2
  104. package/rcf/requirements/req-026.json +5 -2
  105. package/rcf/requirements/req-027.json +5 -2
  106. package/rcf/requirements/req-028.json +5 -2
  107. package/rcf/requirements/req-029.json +5 -2
  108. package/rcf/requirements/req-030.json +5 -2
  109. package/rcf/requirements/req-040.json +5 -2
  110. package/rcf/requirements/req-041.json +5 -2
  111. package/rcf/requirements/req-042.json +5 -2
  112. package/rcf/requirements/req-043.json +5 -2
  113. package/rcf/requirements/req-050.json +5 -2
  114. package/rcf/requirements/req-051.json +5 -2
  115. package/rcf/requirements/req-052.json +5 -2
  116. package/rcf/requirements/req-053.json +5 -2
  117. package/rcf/requirements/req-054.json +5 -2
  118. package/rcf/requirements/req-060.json +5 -2
  119. package/rcf/requirements/req-061.json +5 -2
  120. package/rcf/requirements/req-062.json +5 -2
  121. package/rcf/requirements/req-063.json +5 -2
  122. package/rcf/requirements/req-070.json +5 -2
  123. package/rcf/requirements/req-071.json +5 -2
  124. package/rcf/requirements/req-072.json +5 -2
  125. package/rcf/requirements/req-073.json +5 -2
  126. package/rcf/requirements/req-074.json +5 -2
  127. package/rcf/requirements/req-075.json +5 -2
  128. package/rcf/requirements/req-076.json +5 -2
  129. package/rcf/requirements/req-077.json +5 -2
  130. package/rcf/requirements/req-080.json +5 -2
  131. package/rcf/requirements/req-081.json +5 -2
  132. package/rcf/requirements/req-082.json +5 -2
  133. package/rcf/requirements/req-083.json +5 -2
  134. package/rcf/requirements/req-084.json +5 -2
  135. package/rcf/requirements/req-085.json +5 -2
  136. package/rcf/requirements/req-086.json +5 -2
  137. package/rcf/requirements/req-090.json +5 -2
  138. package/rcf/requirements/req-091.json +5 -2
  139. package/rcf/requirements/req-092.json +5 -2
  140. package/rcf/requirements/req-093.json +5 -2
  141. package/rcf/requirements/req-094.json +5 -2
  142. package/rcf/requirements/req-100.json +5 -2
  143. package/rcf/requirements/req-101.json +5 -2
  144. package/rcf/requirements/req-102.json +5 -2
  145. package/rcf/requirements/req-103.json +5 -2
  146. package/rcf/requirements/req-104.json +5 -2
  147. package/rcf/requirements/req-110.json +5 -2
  148. package/rcf/requirements/req-111.json +5 -2
  149. package/rcf/requirements/req-112.json +5 -2
  150. package/rcf/requirements/req-113.json +5 -2
  151. package/rcf/requirements/req-114.json +5 -2
  152. package/rcf/requirements/req-115.json +5 -2
  153. package/rcf/requirements/req-120.json +5 -2
  154. package/rcf/requirements/req-121.json +5 -2
  155. package/rcf/requirements/req-122.json +5 -2
  156. package/rcf/requirements/req-123.json +5 -2
  157. package/rcf/requirements/req-124.json +5 -2
  158. package/rcf/requirements/req-125.json +5 -2
  159. package/rcf/requirements/req-130.json +6 -2
  160. package/rcf/requirements/req-131.json +6 -2
  161. package/rcf/requirements/req-132.json +6 -2
  162. package/rcf/requirements/req-133.json +6 -2
  163. package/rcf/requirements/req-134.json +6 -2
  164. package/rcf/requirements/req-140.json +5 -2
  165. package/rcf/requirements/req-145.json +5 -2
  166. package/rcf/requirements/req-150.json +6 -2
  167. package/rcf/requirements/req-151.json +6 -2
  168. package/rcf/requirements/req-152.json +6 -2
  169. package/rcf/requirements/req-153.json +6 -2
  170. package/rcf/requirements/req-154.json +5 -2
  171. package/rcf/requirements/req-155.json +4 -1
  172. package/rcf/requirements/req-156.json +4 -1
  173. package/rcf/requirements/req-157.json +4 -1
  174. package/rcf/requirements/req-158.json +4 -1
  175. package/rcf/requirements/req-159.json +4 -1
  176. package/rcf/requirements/req-160.json +4 -1
  177. package/rcf/requirements/req-161.json +4 -1
  178. package/rcf/requirements/req-162.json +4 -1
  179. package/rcf/requirements/req-163.json +5 -2
  180. package/rcf/requirements/req-164.json +5 -2
  181. package/rcf/requirements/req-165.json +5 -2
  182. package/rcf/requirements/req-170.json +33 -0
  183. package/rcf/requirements/req-171.json +44 -0
  184. package/rcf/requirements/req-172.json +25 -0
  185. package/rcf/requirements/req-173.json +25 -0
  186. package/rcf/requirements/req-174.json +31 -0
  187. package/rcf/requirements/req-175.json +31 -0
  188. package/rcf/requirements/req-176.json +25 -0
  189. package/rcf/requirements/req-180.json +31 -0
  190. package/rcf/requirements/req-181.json +31 -0
  191. package/rcf/requirements/req-182.json +25 -0
  192. package/rcf/requirements/req-186.json +25 -0
  193. package/rcf/requirements/req-187.json +31 -0
  194. package/rcf/requirements/req-188.json +25 -0
  195. package/rcf/tacs/tac-4120-define-delta-and-freeze.json +21 -0
  196. package/rcf/tacs/tac-4121-define-ledgers.json +35 -0
  197. package/rcf/tacs/tac-4122-define-gates.json +61 -0
  198. package/rcf/tacs/tac-4123-define-readiness.json +61 -0
  199. package/rcf/tacs/tac-4124-define-freeze.json +28 -0
  200. package/rcf/tacs/tac-4127-readiness-view.json +49 -0
  201. package/rcf/tacs/tac-4128-define-guidance.json +53 -0
  202. package/rcf/tacs/tac-4129-define-questions.json +45 -0
  203. package/rcf/tacs/tac-4130-define-intake-brief.json +35 -0
  204. package/rcf/tacs/tac-4131-build-dag-view.json +39 -0
  205. package/rcf/tacs/tac-4132-id-lookup.json +42 -0
  206. package/rcf/tacs/tac-4133-readiness-po-layer.json +37 -0
  207. package/rcf/tacs/tac-4134-wespa-host-fixture.json +54 -0
  208. package/rcf/test-suites/ts-016.json +3 -3
  209. package/rcf/test-suites/ts-204.json +30 -0
  210. package/rcf/test-suites/ts-205.json +22 -0
  211. package/rcf/test-suites/ts-206.json +22 -0
  212. package/rcf/test-suites/ts-207.json +22 -0
  213. package/rcf/test-suites/ts-208.json +22 -0
  214. package/rcf/test-suites/ts-209.json +22 -0
  215. package/rcf/test-suites/ts-210.json +22 -0
  216. package/rcf/test-suites/ts-211.json +22 -0
  217. package/rcf/test-suites/ts-212.json +22 -0
  218. package/rcf/test-suites/ts-213.json +50 -0
  219. package/rcf/test-suites/ts-214.json +74 -0
  220. package/rcf/test-suites/ts-215.json +211 -0
  221. package/rcf/test-suites/ts-216.json +94 -0
  222. package/rcf/test-suites/ts-217.json +62 -0
  223. package/rcf/test-suites/ts-218.json +78 -0
  224. package/rcf/test-suites/ts-219.json +70 -0
  225. package/rcf/test-suites/ts-220.json +78 -0
  226. package/rcf/test-suites/ts-221.json +78 -0
  227. package/rcf/test-suites/ts-222.json +100 -0
  228. package/rcf/test-suites/ts-223.json +94 -0
  229. package/rcf/test-suites/ts-224.json +70 -0
  230. package/rcf/test-suites/ts-225.json +78 -0
  231. package/rcf/test-suites/ts-226.json +158 -0
  232. package/rcf/test-suites/ts-227.json +38 -0
  233. package/rcf/test-suites/ts-228.json +86 -0
  234. package/rcf/test-suites/ts-229.json +83 -0
  235. package/rcf/user-stories/us-15601.json +4 -4
  236. package/rcf/user-stories/us-17001.json +27 -0
  237. package/rcf/user-stories/us-17002.json +22 -0
  238. package/rcf/user-stories/us-17003.json +22 -0
  239. package/rcf/user-stories/us-17004.json +22 -0
  240. package/rcf/user-stories/us-17005.json +22 -0
  241. package/rcf/user-stories/us-17006.json +21 -0
  242. package/rcf/user-stories/us-17007.json +21 -0
  243. package/rcf/user-stories/us-17008.json +22 -0
  244. package/rcf/user-stories/us-17101.json +22 -0
  245. package/rcf/user-stories/us-17102.json +22 -0
  246. package/rcf/user-stories/us-17201.json +38 -0
  247. package/rcf/user-stories/us-17301.json +38 -0
  248. package/rcf/user-stories/us-17302.json +50 -0
  249. package/rcf/user-stories/us-17401.json +70 -0
  250. package/rcf/user-stories/us-17402.json +55 -0
  251. package/rcf/user-stories/us-17403.json +60 -0
  252. package/rcf/user-stories/us-17501.json +48 -0
  253. package/rcf/user-stories/us-17502.json +60 -0
  254. package/rcf/user-stories/us-17503.json +65 -0
  255. package/rcf/user-stories/us-17601.json +58 -0
  256. package/rcf/user-stories/us-18001.json +55 -0
  257. package/rcf/user-stories/us-18002.json +35 -0
  258. package/rcf/user-stories/us-18101.json +35 -0
  259. package/rcf/user-stories/us-18202.json +40 -0
  260. package/rcf/user-stories/us-18601.json +55 -0
  261. package/rcf/user-stories/us-18602.json +50 -0
  262. package/rcf/user-stories/us-18603.json +45 -0
  263. package/rcf/user-stories/us-18701.json +50 -0
  264. package/rcf/user-stories/us-18702.json +50 -0
  265. package/rcf/user-stories/us-18801.json +45 -0
  266. package/rcf/user-stories/us-204.json +59 -0
  267. package/rcf/user-stories/us-205.json +64 -0
  268. package/rcf/user-stories/us-206.json +54 -0
  269. package/releases/releases.yaml +31 -1
  270. package/src/cli/feedback.js +126 -10
  271. package/src/cli/freeze.js +730 -0
  272. package/src/cli/help.js +23 -0
  273. package/src/cli/ledger.js +615 -0
  274. package/src/cli/questions.js +288 -0
  275. package/src/cli/readiness.js +498 -0
  276. package/src/cli/view.js +29 -0
  277. package/src/core/store/writer.js +86 -6
  278. package/src/define/freeze-record.js +247 -0
  279. package/src/define/ledgers.js +712 -0
  280. package/src/feedback/redact.js +105 -19
  281. package/src/intake/index.js +1 -1
  282. package/src/intake/orchestrator.js +117 -0
  283. package/src/mcp/tools.js +354 -0
  284. package/src/query/delta.js +282 -0
  285. package/src/query/gates.js +1107 -0
  286. package/src/query/index.js +50 -0
  287. package/src/query/questions.js +438 -0
  288. package/src/query/readiness.js +574 -0
  289. package/src/server/index.js +60 -1
  290. package/src/server/routes.js +133 -4
  291. package/src/setup/identity-seed.js +17 -0
  292. package/src/view/build-dag.js +563 -0
  293. package/src/view/components/badge.js +41 -0
  294. package/src/view/components/diff.js +72 -0
  295. package/src/view/components/doc-row.js +62 -0
  296. package/src/view/components/empty-state.js +35 -0
  297. package/src/view/components/entity-selector.js +137 -0
  298. package/src/view/components/filter-bar.js +97 -0
  299. package/src/view/components/findings-list.js +49 -0
  300. package/src/view/components/index.js +12 -0
  301. package/src/view/components/pill.js +46 -0
  302. package/src/view/components/sub-tab-strip.js +43 -0
  303. package/src/view/components/toast.js +25 -0
  304. package/src/view/components-fixture.js +265 -0
  305. package/src/view/doc-renderers/architecture.js +304 -0
  306. package/src/view/doc-renderers/build.js +160 -0
  307. package/src/view/doc-renderers/helpers.js +2 -2
  308. package/src/view/doc-renderers/index.js +2 -0
  309. package/src/view/doc-renderers/prd.js +35 -6
  310. package/src/view/doc-renderers/req.js +10 -2
  311. package/src/view/doc-renderers/user-story.js +10 -5
  312. package/src/view/html-page.js +717 -300
  313. package/src/view/index.js +109 -3
  314. package/src/view/live-client.js +61 -8
  315. package/src/view/needs-work.js +79 -0
  316. package/src/view/page-init.js +2193 -0
  317. package/src/view/product-map.js +751 -0
  318. package/src/view/readiness/phrasebook.js +115 -0
  319. package/src/view/readiness/po-layer.js +288 -0
  320. package/src/view/readiness/question-adapter.js +329 -0
  321. package/src/view/readiness/stage-legend.js +71 -0
  322. package/src/view/readiness.js +505 -0
  323. package/src/view/style.css +2279 -266
  324. package/src/view/test-host/embed-client.js +121 -0
  325. package/src/view/test-host/fixture.js +183 -0
  326. package/src/view/test-host/lints.js +220 -0
  327. package/src/view/view-index.js +323 -0
@@ -0,0 +1,24 @@
1
+ {
2
+ "cnId": "CN-730",
3
+ "path": "test/cli/readiness.test.js",
4
+ "title": "CLI tests for rcf define readiness",
5
+ "description": "Covers AC-17501-5 (text output, --json emission, --check exit codes), AC-17502-7 (byte-stable rcf/ tree across a readiness run) and AC-17503-1..9 (default exits 0 + both verdict lines; --level intent exits 4 iff PO fails; --level build exits 4 iff readyToBuild is false, with warn lines emitted; --check all unchanged; --persona filters text and does not change exit; unknown values exit 2; --json --level intent carries _meta.level; text report groups PO before engineer with persona in detail lines; parameterised exit matrix).",
6
+ "implementsAcIds": [
7
+ "AC-17501-5",
8
+ "AC-17502-7",
9
+ "AC-17503-1",
10
+ "AC-17503-2",
11
+ "AC-17503-3",
12
+ "AC-17503-4",
13
+ "AC-17503-5",
14
+ "AC-17503-6",
15
+ "AC-17503-7",
16
+ "AC-17503-8",
17
+ "AC-17503-9"
18
+ ],
19
+ "dependencies": [],
20
+ "version": "0.1.0",
21
+ "status": "draft",
22
+ "createdAt": "2026-09-24T14:30:00Z",
23
+ "updatedAt": "2026-10-01T16:00:00Z"
24
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ "cnId": "CN-731",
3
+ "path": "test/cli/freeze.test.js",
4
+ "title": "CLI tests for rcf define freeze",
5
+ "description": "Covers AC-17601-1..6 and AC-17601-8: happy freeze, refusal on failing D1, --ack on D3/D5/D6 only, section 2.5 summary line, --status is read-only, admissibility refusal is informational, and the readiness CLI stage header + CHANGELOG line no longer use ' -- '.",
6
+ "implementsAcIds": [
7
+ "AC-17601-1",
8
+ "AC-17601-2",
9
+ "AC-17601-3",
10
+ "AC-17601-4",
11
+ "AC-17601-5",
12
+ "AC-17601-6",
13
+ "AC-17601-8"
14
+ ],
15
+ "dependencies": [],
16
+ "version": "0.1.0",
17
+ "status": "draft",
18
+ "createdAt": "2026-09-24T16:33:15Z",
19
+ "updatedAt": "2026-09-24T16:33:15Z"
20
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "cnId": "CN-732",
3
+ "path": "test/define/freeze-record.test.js",
4
+ "title": "Extension tests for freeze-record override-nullable-required contract",
5
+ "description": "Covers AC-17601-7: validateFreezeRecord requires override (nullable), loadFreezeRecord defaults a missing override key to null, saveFreezeRecord refuses to write a body without override.",
6
+ "implementsAcIds": [
7
+ "AC-17601-7"
8
+ ],
9
+ "dependencies": [],
10
+ "version": "0.1.0",
11
+ "status": "draft",
12
+ "createdAt": "2026-09-24T16:33:15Z",
13
+ "updatedAt": "2026-09-24T16:33:15Z"
14
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "cnId": "CN-733",
3
+ "path": "src/setup/identity-seed.js",
4
+ "title": "Identity-seed template with the ## Surface section",
5
+ "description": "IDENTITY_TEMPLATE carries a ## Surface section between ## Register and ## Project-scoped notes naming viewer / runningApp / prDiff, seeded to prDiff so a fresh rcf init project satisfies checkD1Brief profile:surface marker without operator edit. writeIdentityTemplate keeps the slice-1 kept contract: an existing profile.md is left byte-identical.",
6
+ "implementsAcIds": [
7
+ "AC-17401-10"
8
+ ],
9
+ "dependencies": [],
10
+ "version": "0.1.0",
11
+ "status": "draft",
12
+ "createdAt": "2026-10-01T13:22:37Z",
13
+ "updatedAt": "2026-10-01T13:22:37Z"
14
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "cnId": "CN-734",
3
+ "path": "test/setup/identity-register.test.js",
4
+ "title": "Identity-seed Surface section tests",
5
+ "description": "Covers AC-17401-10: ## Surface heading placement; three value names + prDiff default; writeIdentityTemplate on a fresh dir seeds a profile that satisfies checkD1Brief surfaceMarkers; existing profile.md with no ## Surface is left byte-identical.",
6
+ "implementsAcIds": [
7
+ "AC-17401-10"
8
+ ],
9
+ "dependencies": [],
10
+ "version": "0.1.0",
11
+ "status": "draft",
12
+ "createdAt": "2026-10-01T13:22:37Z",
13
+ "updatedAt": "2026-10-01T13:22:37Z"
14
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ "cnId": "CN-735",
3
+ "path": "src/view/readiness.js",
4
+ "title": "Readiness tab panel renderer",
5
+ "description": "renderReadinessPanel(result, { profile, freezeRecord }) returns the eleven ordered blocks of spec section 5 for the Readiness tab: tree line, two verdict pills with formatVerdictLines labels, two per-persona next-action lines, D1..D8 state chips, blockers grouped by persona (register orders the pair; the non-register group collapses with its count visible, never omitted), delta list, per-stage check detail, coverage tree-vs-delta, decisions outstanding, Freeze now control (enabled iff levels.readyToBuild.ok), freeze record. Pure: no I/O, no recompute. pickRegister helper mirrors the CLI's contract.",
6
+ "implementsAcIds": [
7
+ "AC-18001-1",
8
+ "AC-18001-2",
9
+ "AC-18001-3",
10
+ "AC-18001-4",
11
+ "AC-18001-5",
12
+ "AC-18001-6",
13
+ "AC-18001-7"
14
+ ],
15
+ "dependencies": [],
16
+ "version": "0.1.0",
17
+ "status": "draft",
18
+ "createdAt": "2026-10-01T18:00:00Z",
19
+ "updatedAt": "2026-10-01T18:00:00Z"
20
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "cnId": "CN-736",
3
+ "path": "src/view/components/pill.js",
4
+ "title": "Shared pill component",
5
+ "description": "pill({ value, variant, title?, href? }) emits one markup shape across every vocabulary family (gate state, level verdict, persona, AC class) with class suffixes derived from a normalised value. Pure.",
6
+ "implementsAcIds": [
7
+ "AC-18101-1"
8
+ ],
9
+ "dependencies": [],
10
+ "version": "0.1.0",
11
+ "status": "draft",
12
+ "createdAt": "2026-10-01T18:00:00Z",
13
+ "updatedAt": "2026-10-01T18:00:00Z"
14
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "cnId": "CN-737",
3
+ "path": "src/view/components/findings-list.js",
4
+ "title": "Shared findings-list component",
5
+ "description": "findingsList({ heading, count, items }) emits a heading plus an id-anchor list with per-id why strings; ids are capped at 20 and the tail becomes a `... N more suppressed` line. Pure.",
6
+ "implementsAcIds": [
7
+ "AC-18101-2"
8
+ ],
9
+ "dependencies": [],
10
+ "version": "0.1.0",
11
+ "status": "draft",
12
+ "createdAt": "2026-10-01T18:00:00Z",
13
+ "updatedAt": "2026-10-01T18:00:00Z"
14
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "cnId": "CN-738",
3
+ "path": "src/view/components/diff.js",
4
+ "title": "Shared document-level diff component",
5
+ "description": "diff(before, after) renders a two-column before-and-after of two document bodies for the Readiness delta list. 0.29.0 ships document-level only; criterion-level before-and-after is deferred per ADR-4127. Pure.",
6
+ "implementsAcIds": [
7
+ "AC-18101-3"
8
+ ],
9
+ "dependencies": [],
10
+ "version": "0.1.0",
11
+ "status": "draft",
12
+ "createdAt": "2026-10-01T18:00:00Z",
13
+ "updatedAt": "2026-10-01T18:00:00Z"
14
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "cnId": "CN-739",
3
+ "path": "src/view/build-dag.js",
4
+ "title": "Build/DAG sub-tab pure renderer",
5
+ "description": "Pure HTML-string renderer for the Build tab's DAG sub-tab: `buildDagLayout(fbsItems, buildableIds)` projects `dependsOnFbsIds` into depth columns, `buildOrder` row ordering, upstream/downstream closures, longest-chain critical path and the no-in-no-out unconnected lane; `renderBuildDag({ layout, inspectorPayload })` emits the toolbar, canvas (HTML button nodes + inline SVG edges with cubic paths and arrowheads) and inspector shell. `buildDagInspectorPayload(layout)` builds the one-row-per-FBS payload (status, area, size, order, AC count, direct and transitive needs/waits, meta) that rides on the inspector shell as `data-rcf-dag-inspector-data` per the PR 1 contract. Cycles are excluded from the depth layout and surfaced as `cycleIds` for the toolbar finding (AC-204-6); the renderer never emits a `postMessage` call (AC-204-7).",
6
+ "implementsAcIds": [
7
+ "AC-204-1",
8
+ "AC-204-2",
9
+ "AC-204-3",
10
+ "AC-204-6",
11
+ "AC-204-7"
12
+ ],
13
+ "dependencies": [],
14
+ "version": "0.1.0",
15
+ "status": "draft",
16
+ "createdAt": "2026-10-02T19:00:00Z",
17
+ "updatedAt": "2026-10-02T19:00:00Z"
18
+ }
@@ -0,0 +1,19 @@
1
+ {
2
+ "cnId": "CN-740",
3
+ "path": "src/view/page-init.js",
4
+ "title": "Build/DAG client wiring (page-init DAG seam)",
5
+ "description": "`wireBuildDag` and its helpers wire the Build/DAG sub-tab in the browser: `parseDagInspectorPayload` reads the `data-rcf-dag-inspector-data` attribute off the inspector shell (never an inline <script>), click handlers on `.rcf-dag-node` run `selectDagNode` which sets `data-rcf-dag-sel`, auto-presses Show-unconnected when the node is unconnected, outlines upstream/downstream closures via `data-rcf-dag-role` attributes and renders the inspector body from the payload. Filter chips (status, area, Buildable-now, Critical-path, Show-unconnected) run `applyDagFilters` which keeps the current selection intact (AC-204-5). `buildHashFragment` writes `#tab=build&sub=dag&entity=<id>` and `currentDagHashExtras` preserves non-DAG hash params through DAG writes; `applyBuildHash` restores the selection, auto-presses Show-unconnected when the restored node is unconnected and scrolls the node into view (AC-204-4). `renderDagInspector` lists status, area, AC count, size, buildOrder, buildable-now, Needs (direct and transitive total) and Waits (direct and transitive total) with an Open-in-Specs link that moves to `#tab=build&sub=specs&entity=<id>` (AC-204-3).",
6
+ "implementsAcIds": [
7
+ "AC-204-2",
8
+ "AC-204-3",
9
+ "AC-204-4",
10
+ "AC-204-5"
11
+ ],
12
+ "dependencies": [
13
+ "CN-739"
14
+ ],
15
+ "version": "0.1.0",
16
+ "status": "draft",
17
+ "createdAt": "2026-10-02T19:00:00Z",
18
+ "updatedAt": "2026-10-02T19:00:00Z"
19
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "cnId": "CN-741",
3
+ "path": "src/view/view-index.js",
4
+ "title": "ID lookup pure projection + rank helper",
5
+ "description": "`buildViewIndex(model)` projects a BuiltTreeModel into one row per PRD/REQ/US/TAD/TAC/ADR/BS/FBS/TS plus one row per AC under each US, each `{ id, kind, title, snippet, parent, tab }`; `snippet` is the kind-specific prose field whitespace-collapsed and capped at 110 chars; `tab` is the viewer tab that owns the id. `serialiseViewIndex(model)` returns the exact JSON string the server serves (so Content-Length matches). `rankLookupRows(query, rows)` implements the design doc section 6 ranking: single-char id-only, otherwise id first (exact / prefix / contains), then every word must match title or snippet, title weighted above snippet, stable on ties by id, 20-result cap. This is the pure projection the server renders into `./index.json` on every rewalk (AC-205-1 to AC-205-3).",
6
+ "implementsAcIds": [
7
+ "AC-205-1",
8
+ "AC-205-2",
9
+ "AC-205-3"
10
+ ],
11
+ "dependencies": [],
12
+ "version": "0.1.0",
13
+ "status": "draft",
14
+ "createdAt": "2026-10-03T00:00:00Z",
15
+ "updatedAt": "2026-10-03T00:00:00Z"
16
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "cnId": "CN-742",
3
+ "path": "src/server/routes.js",
4
+ "title": "GET /index.json route for the viewer ID lookup",
5
+ "description": "`GET /index.json` returns the server-side ID index as `application/json; charset=utf-8` with `cache-control: no-store`. The handler reads `state.indexJson` (snapshotted per rewalk from `renderModelToPage().indexJson` so bytes match Content-Length) and never touches disk; before the first walk it 503s with `view server initialising`. The route is release-noted (PR 1 relative-script policy, wespa reverse-proxy allow-list adds it before the version pin bump) and is the fourth release-noted viewer route after `./page-init.js` (AC-205-1).",
6
+ "implementsAcIds": [
7
+ "AC-205-1"
8
+ ],
9
+ "dependencies": [
10
+ "CN-741"
11
+ ],
12
+ "version": "0.1.0",
13
+ "status": "draft",
14
+ "createdAt": "2026-10-03T00:00:00Z",
15
+ "updatedAt": "2026-10-03T00:00:00Z"
16
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "cnId": "CN-743",
3
+ "path": "src/view/html-page.js",
4
+ "title": "SearchButton + LookupModal shell markup",
5
+ "description": "`renderSearchButton()` emits a `<button data-rcf-search>` inside the shell `<div class=\"tools\">` to the right of the tabstrip, carrying the Cmd/Ctrl+F mnemonic on `aria-label` + `title`. `renderLookupModal()` emits the modal shell once in the shell outside `#rcf-live-content` so the SSE innerHTML swap never blows it away: `<aside role=\"dialog\" aria-modal=\"true\" aria-labelledby=...>` with `<section>`, `<header>`, labelled `<input>`, aria-live status region, `<ul role=\"listbox\">` results, empty-state block and `Reload index` affordance. No `<div>` tags inside the modal, so the Phase 3.8 D13a shell invariant (`lastIndexOf(\"</div>\")` resolves to the live-content wrapper close) stays intact (AC-205-1, AC-205-7).",
6
+ "implementsAcIds": [
7
+ "AC-205-1",
8
+ "AC-205-7"
9
+ ],
10
+ "dependencies": [],
11
+ "version": "0.1.0",
12
+ "status": "draft",
13
+ "createdAt": "2026-10-03T00:00:00Z",
14
+ "updatedAt": "2026-10-03T00:00:00Z"
15
+ }
@@ -0,0 +1,22 @@
1
+ {
2
+ "cnId": "CN-744",
3
+ "path": "src/view/page-init.js",
4
+ "title": "wireLookup client (ID lookup wiring)",
5
+ "description": "`wireLookup` lazily XHR-fetches `./index.json` on first modal open, refetches once when `window.__rcfLookupDirty` is set by live-client (SSE tree-update), ranks via a mirror of `rankLookupRows`, cycles the active row with Up / Down, picks with Enter and closes with Esc. The Router's `resolveHash` honours `?tab=&entity=` at mount so a landed URL (`?tab=requirements&entity=US-304`) opens the same position at first paint without the LookupModal (AC-205-5). Pick writes `#tab=<tab>&entity=<id>` via `writeHash` so `?embed=` and `?theme=` survive (PR 1 contract); the Router's hashchange listener activates the tab, opens ancestor DocRows and flashes the target. Cmd/Ctrl+F opens the modal from any tab; Cmd/Ctrl+Shift+F is deliberately NOT intercepted so the browser find still works. Marks every id / title / snippet substring hit by a query word (`<mark>`, escaped). Empty state shows `The index could not be loaded.` + `Reload index` on fetch failure; never calls `postMessage`, never writes to localStorage / sessionStorage / document.cookie, and never makes an outbound fetch other than `./index.json` (AC-205-4, AC-205-6, AC-205-7, AC-205-8).",
6
+ "implementsAcIds": [
7
+ "AC-205-4",
8
+ "AC-205-5",
9
+ "AC-205-6",
10
+ "AC-205-7",
11
+ "AC-205-8"
12
+ ],
13
+ "dependencies": [
14
+ "CN-741",
15
+ "CN-742",
16
+ "CN-743"
17
+ ],
18
+ "version": "0.1.0",
19
+ "status": "draft",
20
+ "createdAt": "2026-10-03T00:00:00Z",
21
+ "updatedAt": "2026-10-03T00:00:00Z"
22
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "cnId": "CN-745",
3
+ "path": "src/view/live-client.js",
4
+ "title": "SSE tree-update dirties the ID lookup cache",
5
+ "description": "On every SSE `tree-update` event, live-client sets `window.__rcfLookupDirty = true`. `wireLookup` reads this flag on the next modal open and refetches `./index.json` once, then clears it. This keeps the modal consistent with the live walker without polling (AC-205-4).",
6
+ "implementsAcIds": [
7
+ "AC-205-4"
8
+ ],
9
+ "dependencies": [
10
+ "CN-744"
11
+ ],
12
+ "version": "0.1.0",
13
+ "status": "draft",
14
+ "createdAt": "2026-10-03T00:00:00Z",
15
+ "updatedAt": "2026-10-03T00:00:00Z"
16
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "cnId": "CN-746",
3
+ "path": "src/view/readiness/question-adapter.js",
4
+ "title": "Readiness PO question adapter: feature-detected questions source + source-span grouping",
5
+ "description": "`toQuestions(readiness)` is the pure projection the Readiness PO layer reads. `preferReadinessQuestions(readiness)` feature-detects the DEFINE step 3 PR 2 `computeQuestions` output on `readiness.questions`: when present, the adapter reads from there, using `groups[]` labels and the per-question `heading` / `ask` / `hint` with phrasebook fallback per field; the group label falls back to a conservative sourceSpan prose when no `sourceSpanLabel` is given. Otherwise the adapter reads `personas.productOwner.blockers`, groups by source span (brief:<n>, REQ-N, or a plain stage label) and fills asks from the phrasebook. One source of truth for the PO ask text; nothing is fabricated that is not on the tree (AC-18002-1).",
6
+ "implementsAcIds": [
7
+ "AC-18002-1"
8
+ ],
9
+ "dependencies": [],
10
+ "version": "0.1.0",
11
+ "status": "draft",
12
+ "createdAt": "2026-10-03T09:30:00Z",
13
+ "updatedAt": "2026-10-03T09:30:00Z"
14
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "cnId": "CN-747",
3
+ "path": "src/view/readiness/po-layer.js",
4
+ "title": "Readiness PO layer: VerdictCards, QuestionCards grouped by source span, intent-complete empty state, For-engineers DocRow",
5
+ "description": "`renderReadinessPO(readiness, { persona, engineerBody })` emits the PO layer HTML: two equal-height VerdictCards (intent-complete and ready-to-build) with the chain term muted beside each plain label; one QuestionCard group per source span sourced from `toQuestions(readiness)`; a `data-rcf-empty=\"yes\"` block that renders the verbatim `formatVerdictLines(readiness).intentComplete` string when `questions[]` is empty and both levels are ok (AC-18002-2); the Requirements-that-still-need-work table; and the For-engineers DocRow that wraps the engineer rendering, closed under productOwner / unstated and open under engineer, with the data preserved in the DOM in every register (AC-18002-3). Stamps `data-rcf-source=\"readiness.questions\"` on the questions block when the real compute shape is live (AC-18002-1).",
6
+ "implementsAcIds": [
7
+ "AC-18002-1",
8
+ "AC-18002-2",
9
+ "AC-18002-3"
10
+ ],
11
+ "dependencies": [
12
+ "CN-746"
13
+ ],
14
+ "version": "0.1.0",
15
+ "status": "draft",
16
+ "createdAt": "2026-10-03T09:30:00Z",
17
+ "updatedAt": "2026-10-03T09:30:00Z"
18
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "cnId": "CN-748",
3
+ "path": "src/view/readiness.js",
4
+ "title": "renderReadinessPanel wraps the PO layer around the engineer body and picks the register from profile.md",
5
+ "description": "`renderReadinessPanel(result, { profileText })` picks the register from `profile.md` (productOwner | engineer | unstated), renders the engineer body (the pre-PR-8 Readiness rendering: tree line, CLI verdict lines, next-action-per-persona, D1..D8 chips, PO + Engineer blocker groups, delta/diff) once, and hands it to `renderReadinessPO` as `engineerBody`. The engineer body is never removed from the DOM; `renderReadinessPO` is what folds it into the For-engineers DocRow and decides open/closed per register (AC-18002-3).",
6
+ "implementsAcIds": [
7
+ "AC-18002-3"
8
+ ],
9
+ "dependencies": [
10
+ "CN-747"
11
+ ],
12
+ "version": "0.1.0",
13
+ "status": "draft",
14
+ "createdAt": "2026-10-03T09:30:00Z",
15
+ "updatedAt": "2026-10-03T09:30:00Z"
16
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "cnId": "CN-749",
3
+ "path": "src/view/index.js",
4
+ "title": "View bootstrap attaches computeQuestions output to readiness so the adapter feature-detects the real shape",
5
+ "description": "After `computeReadiness` returns, the view bootstrap calls `computeQuestions(readiness, { tree, ledgers, profileText, persona: 'productOwner' })` and merges the result's `questions`, `groups`, `optional` and `engineer` fields onto the readiness object before it reaches `renderPage`. `preferReadinessQuestions` then returns true and `fromReadinessQuestions` reads the real `computeQuestions` output rather than falling back to the blockers path (AC-18002-1). The phrasebook stays available as the per-field fallback when a question carries no `ask` / `hint` of its own.",
6
+ "implementsAcIds": [
7
+ "AC-18002-1"
8
+ ],
9
+ "dependencies": [
10
+ "CN-746"
11
+ ],
12
+ "version": "0.1.0",
13
+ "status": "draft",
14
+ "createdAt": "2026-10-03T09:30:00Z",
15
+ "updatedAt": "2026-10-03T09:30:00Z"
16
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "cnId": "CN-750",
3
+ "path": "src/view/test-host/fixture.js",
4
+ "title": "Wespa host fixture page: 56px header, resizable sidebar, iframe mounted at ./?embed=1&theme=light with no inline script",
5
+ "description": "`renderTestHostPage()` returns the host-fixture HTML as a pure string: HTML5 doctype, lang='en-GB', a 56px wespa-header carrying the Light/Dark toggle buttons, a resizable sidebar shell (data-rcf-host-sidebar + drag handle) and a content pane carrying `<iframe id=\"rcf-test-host-iframe\" src=\"./?embed=1&amp;theme=light\">`. The fixture ships no inline `<script>` body (CSP-friendly, consistent with the PR 1 contract); its client-side wiring lives at /test-host.js (served via /test-host.js when the test-host route is enabled). The fixture does not persist theme or sidebar width to localStorage (ADR-4136): a passing run has to flip the iframe through the postMessage path, which is the invariant the fixture pins. Proves AC-206-1 (shell + iframe src + no inline script) and underwrites AC-206-6 (no outbound postMessage shape beyond the embed-client's single rcf-view-theme post).",
6
+ "implementsAcIds": [
7
+ "AC-206-1",
8
+ "AC-206-6"
9
+ ],
10
+ "dependencies": [],
11
+ "version": "0.1.0",
12
+ "status": "draft",
13
+ "createdAt": "2026-10-03T09:55:00Z",
14
+ "updatedAt": "2026-10-03T09:55:00Z"
15
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "cnId": "CN-751",
3
+ "path": "src/view/test-host/embed-client.js",
4
+ "title": "Wespa host fixture client: theme postMessage, sidebar drag + collapse/expand, same-origin message target",
5
+ "description": "Classic (non-module) browser script served at /test-host.js when the test-host route is on. Three fixture behaviours: (a) the theme toggle posts `{ type: 'rcf-view-theme', theme }` to `iframe.contentWindow`, targeting `window.location.origin` so a cross-origin receiver would refuse the message (underwrites AC-206-4 together with the viewer's own origin check in page-init.js); (b) the sidebar drag handle sets `--wespa-sidebar-width` on the <main> grid, clamped to 64..400 px live; (c) collapse/expand snaps the sidebar between 64 px and 200 px. Reads the iframe's `data-theme` attribute as evidence of the postMessage round-trip (AC-206-2). After the iframe's hash-only navigation, `data-embed` and the search string carry embed=1 and the theme, which the live-proof script captures (AC-206-3). The host does not read event.origin (the viewer does) and does not persist theme to localStorage (ADR-4136 invariant).",
6
+ "implementsAcIds": [
7
+ "AC-206-2",
8
+ "AC-206-3",
9
+ "AC-206-4"
10
+ ],
11
+ "dependencies": [
12
+ "CN-750"
13
+ ],
14
+ "version": "0.1.0",
15
+ "status": "draft",
16
+ "createdAt": "2026-10-03T09:55:00Z",
17
+ "updatedAt": "2026-10-03T09:55:00Z"
18
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "cnId": "CN-752",
3
+ "path": "src/view/test-host/lints.js",
4
+ "title": "Three embedding lints: framing headers, target=_top, localStorage namespace",
5
+ "description": "Three pure assertions callable by any test harness; test/view/wespa-host-fixture.test.js is the suite caller. (1) `assertFramingHeaders(response)` refuses on `X-Frame-Options` or on CSP `frame-ancestors` forbidding same-origin, and accepts `frame-ancestors 'self'`. (2) `assertNoTargetTop(renderedHtml)` greps for `target=\"_top\"` / `target='_top'` / `target=_top` and refuses on any match; returns `{ ok, count }`. (3) `assertLocalStorageNamespace(sourceTreeRoot)` walks every .js file under `src/view/**` (excluding vendored and .min.js) and asserts every `localStorage.*` / `sessionStorage.*` / shared `storage.*` call site uses a key literal starting with `rcf-view:v1:` or a constant resolving to that prefix. Together they pin AC-206-5 against regressions.",
6
+ "implementsAcIds": [
7
+ "AC-206-5"
8
+ ],
9
+ "dependencies": [],
10
+ "version": "0.1.0",
11
+ "status": "draft",
12
+ "createdAt": "2026-10-03T09:55:00Z",
13
+ "updatedAt": "2026-10-03T09:55:00Z"
14
+ }
@@ -0,0 +1,37 @@
1
+ {
2
+ "fbsId": "FBS-190",
3
+ "prdId": "PRD-001",
4
+ "bsId": "BS-001",
5
+ "buildOrder": 190,
6
+ "executionStatus": "complete",
7
+ "title": "Product Map tab on the review surface",
8
+ "summary": "Deliver REQ-170: a new \"Product Map\" tab with five groupings (shape, status filter, component-first, trace coverage, capability) drilling group -> REQ -> US -> AC, hash-addressable.",
9
+ "approach": "Add a product-map tab to src/view/html-page.js after Build sequence. Extend inline script TAB list. Write src/view/product-map.js: pure bucketing over the BuiltTreeModel, one function per grouping, returning {buckets, unclassifiedCount} shapes the renderer consumes. Reuse the existing detailsWrap/renderReq helpers so REQ blocks match the Requirements tab. Deep-link hash pattern #tab=product-map&group=<g>&status=<s> handled by extending resolveHash + status filter client-side.",
10
+ "acIds": [
11
+ "AC-17001-1",
12
+ "AC-17001-2",
13
+ "AC-17002-1",
14
+ "AC-17003-1",
15
+ "AC-17004-1",
16
+ "AC-17005-1"
17
+ ],
18
+ "dependsOnFbsIds": [],
19
+ "contextRequirements": {
20
+ "tacIds": [],
21
+ "adrIds": []
22
+ },
23
+ "deliverables": [
24
+ "src/view/product-map.js: pure bucketing (groupByShape, groupByComponent, groupByTraceCoverage, groupByCapability)",
25
+ "src/view/html-page.js: fifth tab wired, panel renderer, inline script TAB list extended, status filter handling",
26
+ "test/view/product-map.test.js: 5 grouping tests + status filter + hash routing shape",
27
+ "test/view/fixtures/phase-3-6-static.html: regenerated baseline (product-map tab is a whitelisted additive delta)",
28
+ "test/view/tabs.test.js: expect the fifth tab in order"
29
+ ],
30
+ "riskLevel": "low",
31
+ "domain": "reviewSurface",
32
+ "estimatedSize": "medium",
33
+ "estimatedHours": 8,
34
+ "notes": "No schema changes. Capability grouping consumes REQ.tags[] convention (FBS-191 populates the data).",
35
+ "createdAt": "2026-09-21T17:00:00.000Z",
36
+ "updatedAt": "2026-09-21T17:00:00.000Z"
37
+ }
@@ -0,0 +1,34 @@
1
+ {
2
+ "fbsId": "FBS-191",
3
+ "prdId": "PRD-001",
4
+ "bsId": "BS-001",
5
+ "buildOrder": 191,
6
+ "executionStatus": "complete",
7
+ "title": "Capability tag convention: taxonomy + dogfood application",
8
+ "summary": "Deliver REQ-171: tag every dogfood REQ with at least one capability:<slug> tag, document the taxonomy and the rule for adding a new capability.",
9
+ "approach": "Author a compact taxonomy (10-12 slugs) derived from the actual REQ set, hand-map each of the 103 dogfood REQs (or via a small offline script commit-editing the tags[] arrays), and add a capability-tags.md doc linked from docs/README.md.",
10
+ "acIds": [
11
+ "AC-17101-1",
12
+ "AC-17102-1"
13
+ ],
14
+ "dependsOnFbsIds": [
15
+ "FBS-190"
16
+ ],
17
+ "contextRequirements": {
18
+ "tacIds": [],
19
+ "adrIds": []
20
+ },
21
+ "deliverables": [
22
+ "packages/rcf-lite/rcf/requirements/*.json: every REQ has >= 1 capability:<slug> tag",
23
+ "packages/rcf-lite/docs/capability-tags.md: the taxonomy and the rule",
24
+ "packages/rcf-lite/docs/README.md: link to capability-tags.md",
25
+ "test/view/product-map.test.js: capability grouping assertion runs on real data"
26
+ ],
27
+ "riskLevel": "low",
28
+ "domain": "reviewSurface",
29
+ "estimatedSize": "small",
30
+ "estimatedHours": 3,
31
+ "notes": "A classifier verb (rcf discover req-capability-classify) is a follow-up, not part of this PR.",
32
+ "createdAt": "2026-09-21T17:00:00.000Z",
33
+ "updatedAt": "2026-09-21T17:00:00.000Z"
34
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "createdAt": "2026-09-21T19:43:56.521Z",
3
+ "updatedAt": "2026-09-21T19:44:37.430Z",
4
+ "acIds": [
5
+ "AC-17006-1",
6
+ "AC-17007-1"
7
+ ],
8
+ "fbsId": "FBS-192",
9
+ "prdId": "PRD-001",
10
+ "bsId": "BS-001",
11
+ "buildOrder": 192,
12
+ "executionStatus": "complete",
13
+ "title": "Product Map UX rescue pass",
14
+ "summary": "Turn the Product Map from function-emitted to usable-every-day: sticky styled controls, collapsed-by-default buckets, jump-nav, per-status mini counts, hash-encoded open buckets, live-refresh persistence via stable data-doc-id, and a lazy first-load payload that ships only bucket-heading skeletons.",
15
+ "dependsOnFbsIds": [],
16
+ "approach": "Restyle pm-controls with the viewer indigo/rounded tokens. Wrap each bucket in <details class=\"pm-bucket\"> with a summary carrying label + count + per-status mini pills. Emit a pm-jump-nav chip row per grouping. Extend the hash schema to carry &open=<bucketIds>. Suppress raw-JSON disclosures inside pm-req cards via a suppressRawJson flag on renderReq/renderUserStory. Add a /product-map/<name> partial endpoint; the client fetches groupings on demand and invalidates the cache on every SSE swap."
17
+ }
@@ -0,0 +1,37 @@
1
+ {
2
+ "createdAt": "2026-09-22T11:59:39Z",
3
+ "updatedAt": "2026-09-22T15:00:00Z",
4
+ "acIds": [
5
+ "AC-17008-1"
6
+ ],
7
+ "fbsId": "FBS-193",
8
+ "prdId": "PRD-001",
9
+ "bsId": "BS-001",
10
+ "buildOrder": 193,
11
+ "executionStatus": "complete",
12
+ "title": "Product Map: blueprint badge and by-blueprint grouping",
13
+ "summary": "Add a sixth grouping to the Product Map tab: 'By blueprint', with one bucket per applied blueprint plus an Application bucket for the project's own (non-blueprint) requirements. Every REQ row contributed by an applied blueprint carries a compact blueprint badge in every grouping. The by-blueprint bucket's second level is capability, then the usual REQ->US->AC drill-down.",
14
+ "dependsOnFbsIds": [
15
+ "FBS-192"
16
+ ],
17
+ "approach": "Extend GROUPINGS with 'blueprint'. Read manifest.blueprints[].contributions[] via scope.contributionsForBlueprint as the source of truth for blueprint attribution; fall back to reqId's kebab-slug prefix only when no contributions record is present. Add renderBlueprintGrouping that emits jump-nav + one <details class=pm-bucket> per applied blueprint plus an Application bucket, each carrying a capability sub-heading before its REQ rows. Add a pm-blueprint-badge span into renderReqWrapper (or a wrapping helper) so every grouping's REQ rows render the badge when attributed. Extend inline script PM_GROUPS to include 'blueprint'; renderProductMapPanel adds a blueprint <section>; view/index.js adds a 'blueprint' partial to pmPartials.",
18
+ "contextRequirements": {
19
+ "tacIds": [],
20
+ "adrIds": []
21
+ },
22
+ "deliverables": [
23
+ "src/view/product-map.js: groupByBlueprint, blueprintForReq, renderBlueprintGrouping, badge in renderReqWrapper",
24
+ "src/view/html-page.js: PM_GROUPS extended, blueprint <section>, group label 'Blueprint'",
25
+ "src/view/index.js: pmPartials.blueprint",
26
+ "src/view/style.css: .pm-blueprint-badge token",
27
+ "test/view/fixtures/blueprint-applied/: fixture project with one applied blueprint (2 contributed REQs) + 2 project REQs",
28
+ "test/view/product-map.test.js: five tests covering AC-17008-1",
29
+ "test/view/fixtures/phase-3-6-static.html: regenerated baseline (blueprint grouping is a whitelisted additive delta)",
30
+ "docs/capability-tags.md, docs/how-it-works.md: short line about the by-blueprint grouping and badge"
31
+ ],
32
+ "riskLevel": "low",
33
+ "domain": "reviewSurface",
34
+ "estimatedSize": "medium",
35
+ "estimatedHours": 5,
36
+ "notes": "No schema change. Uses manifest.blueprints[].contributions[] as truth (project-local); id-prefix fallback only when contributions absent. Dogfood tree applies no blueprints, so the by-blueprint tab shows one Application bucket - fixture proves the multi-bucket path."
37
+ }
@@ -0,0 +1,35 @@
1
+ {
2
+ "createdAt": "2026-09-24T12:00:00Z",
3
+ "updatedAt": "2026-09-24T12:00:00Z",
4
+ "acIds": [
5
+ "AC-17201-1",
6
+ "AC-17201-2",
7
+ "AC-17201-3",
8
+ "AC-17201-4"
9
+ ],
10
+ "fbsId": "FBS-194",
11
+ "prdId": "PRD-001",
12
+ "bsId": "BS-001",
13
+ "buildOrder": 194,
14
+ "executionStatus": "complete",
15
+ "title": "DEFINE slice 1: delta module and freeze record I/O",
16
+ "summary": "Ship src/query/delta.js (hashDocument, computeTreeHash, computeDelta) and src/define/freeze-record.js (load, save, validate). Export the delta primitives from src/query/index.js. Cover every AC with unit tests in test/query/delta.test.js and test/define/freeze-record.test.js.",
17
+ "dependsOnFbsIds": [],
18
+ "approach": "Pure module with SHA-256 over canonical JSON per proposal 2026-09-22 v3 section 2.1 / 2.2. Canonicalise recurses over the parsed value, sorting object keys and stripping whitespace. Tree hash is SHA-256 over the sorted (id, docHash) pairs. Delta enumerates tree.byId once and classifies each id against the freeze docHashes, appending ledger:<name> entries for the sidecars the caller passes. Freeze record I/O treats a missing file as null; a malformed body raises FreezeRecordError with a coded reason and a named field. The writer validates first so a bad in-memory record never lands on disk.",
19
+ "contextRequirements": {
20
+ "tacIds": ["TAC-4120-define-delta-and-freeze"],
21
+ "adrIds": ["ADR-4120-canonical-json-hashing"]
22
+ },
23
+ "deliverables": [
24
+ "src/query/delta.js: canonicaliseJson, hashDocument, computeTreeHash, computeDelta (§2.2 shape)",
25
+ "src/query/index.js: re-export the four delta primitives",
26
+ "src/define/freeze-record.js: FREEZE_RECORD_REL_PATH, FreezeRecordError, validateFreezeRecord, loadFreezeRecord, saveFreezeRecord",
27
+ "test/query/delta.test.js: eleven tests covering AC-17201-1 and AC-17201-2",
28
+ "test/define/freeze-record.test.js: nine tests covering AC-17201-3 and AC-17201-4"
29
+ ],
30
+ "riskLevel": "low",
31
+ "domain": "defineDetection",
32
+ "estimatedSize": "small",
33
+ "estimatedHours": 3,
34
+ "notes": "Pure module: no filesystem I/O beyond the freeze reader / writer. computeDelta signature and return shape are the contract every later slice reads."
35
+ }