rcf-lite 0.0.1 → 0.7.1

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 (342) hide show
  1. package/CHANGELOG.md +288 -0
  2. package/LICENSE +202 -0
  3. package/README.md +92 -4
  4. package/bin/rcf-verify.js +122 -0
  5. package/bin/rcf.js +174 -0
  6. package/bin/view-supervisor-child.mjs +14 -0
  7. package/fixtures/canary-manifest.json +103 -0
  8. package/guidance/README.md +25 -0
  9. package/guidance/build-cycle-playbook.md +492 -0
  10. package/guidance/build-cycle.md +40 -0
  11. package/guidance/document-model.md +45 -0
  12. package/guidance/elicitation-playbook.md +442 -0
  13. package/guidance/harness-template.md +246 -0
  14. package/guidance/managed/README.md +63 -0
  15. package/guidance/managed/agent-instructions-block.hash +1 -0
  16. package/guidance/managed/agent-instructions-block.md +220 -0
  17. package/guidance/managed/legacy-fragment-hashes.json +22 -0
  18. package/guidance/manifest.json +21 -0
  19. package/guidance/overview.md +48 -0
  20. package/guidance/persona-programme.md +44 -0
  21. package/package.json +69 -8
  22. package/rcf/adrs/adr-001.json +25 -0
  23. package/rcf/adrs/adr-002.json +25 -0
  24. package/rcf/adrs/adr-003.json +25 -0
  25. package/rcf/adrs/adr-004.json +20 -0
  26. package/rcf/adrs/adr-005.json +20 -0
  27. package/rcf/adrs/adr-006.json +25 -0
  28. package/rcf/adrs/adr-007.json +25 -0
  29. package/rcf/adrs/adr-008.json +25 -0
  30. package/rcf/adrs/adr-009.json +25 -0
  31. package/rcf/build-sequence.json +11 -0
  32. package/rcf/code-nodes/cn-001.json +14 -0
  33. package/rcf/code-nodes/cn-002.json +14 -0
  34. package/rcf/code-nodes/cn-003.json +15 -0
  35. package/rcf/code-nodes/cn-004.json +17 -0
  36. package/rcf/code-nodes/cn-005.json +19 -0
  37. package/rcf/code-nodes/cn-006.json +17 -0
  38. package/rcf/code-nodes/cn-007.json +16 -0
  39. package/rcf/code-nodes/cn-008.json +19 -0
  40. package/rcf/code-nodes/cn-009.json +16 -0
  41. package/rcf/code-nodes/cn-010.json +18 -0
  42. package/rcf/code-nodes/cn-011.json +18 -0
  43. package/rcf/code-nodes/cn-012.json +18 -0
  44. package/rcf/code-nodes/cn-013.json +19 -0
  45. package/rcf/code-nodes/cn-014.json +16 -0
  46. package/rcf/code-nodes/cn-015.json +16 -0
  47. package/rcf/code-nodes/cn-016.json +16 -0
  48. package/rcf/code-nodes/cn-017.json +16 -0
  49. package/rcf/code-nodes/cn-018.json +15 -0
  50. package/rcf/code-nodes/cn-019.json +16 -0
  51. package/rcf/code-nodes/cn-020.json +16 -0
  52. package/rcf/code-nodes/cn-021.json +16 -0
  53. package/rcf/code-nodes/cn-022.json +16 -0
  54. package/rcf/code-nodes/cn-023.json +16 -0
  55. package/rcf/code-nodes/cn-024.json +16 -0
  56. package/rcf/code-nodes/cn-025.json +16 -0
  57. package/rcf/code-nodes/cn-026.json +16 -0
  58. package/rcf/code-nodes/cn-027.json +16 -0
  59. package/rcf/code-nodes/cn-028.json +16 -0
  60. package/rcf/code-nodes/cn-029.json +19 -0
  61. package/rcf/code-nodes/cn-030.json +14 -0
  62. package/rcf/code-nodes/cn-031.json +14 -0
  63. package/rcf/code-nodes/cn-032.json +14 -0
  64. package/rcf/code-nodes/cn-033.json +14 -0
  65. package/rcf/code-nodes/cn-034.json +14 -0
  66. package/rcf/code-nodes/cn-035.json +14 -0
  67. package/rcf/code-nodes/cn-036.json +14 -0
  68. package/rcf/code-nodes/cn-037.json +14 -0
  69. package/rcf/code-nodes/cn-038.json +14 -0
  70. package/rcf/code-nodes/cn-039.json +14 -0
  71. package/rcf/code-nodes/cn-040.json +14 -0
  72. package/rcf/code-nodes/cn-041.json +14 -0
  73. package/rcf/code-nodes/cn-042.json +14 -0
  74. package/rcf/code-nodes/cn-043.json +14 -0
  75. package/rcf/code-nodes/cn-044.json +14 -0
  76. package/rcf/code-nodes/cn-045.json +14 -0
  77. package/rcf/code-nodes/cn-046.json +14 -0
  78. package/rcf/code-nodes/cn-047.json +14 -0
  79. package/rcf/code-nodes/cn-048.json +14 -0
  80. package/rcf/code-nodes/cn-049.json +14 -0
  81. package/rcf/code-nodes/cn-050.json +14 -0
  82. package/rcf/code-nodes/cn-051.json +14 -0
  83. package/rcf/code-nodes/cn-052.json +14 -0
  84. package/rcf/code-nodes/cn-053.json +14 -0
  85. package/rcf/code-nodes/cn-054.json +14 -0
  86. package/rcf/code-nodes/cn-055.json +14 -0
  87. package/rcf/code-nodes/cn-056.json +14 -0
  88. package/rcf/code-nodes/cn-057.json +14 -0
  89. package/rcf/fbs/fbs-001.json +49 -0
  90. package/rcf/fbs/fbs-002.json +42 -0
  91. package/rcf/fbs/fbs-003.json +37 -0
  92. package/rcf/fbs/fbs-004.json +39 -0
  93. package/rcf/fbs/fbs-005.json +38 -0
  94. package/rcf/fbs/fbs-006.json +48 -0
  95. package/rcf/fbs/fbs-007.json +39 -0
  96. package/rcf/fbs/fbs-008.json +40 -0
  97. package/rcf/fbs/fbs-009.json +36 -0
  98. package/rcf/fbs/fbs-010.json +41 -0
  99. package/rcf/fbs/fbs-011.json +36 -0
  100. package/rcf/fbs/fbs-012.json +46 -0
  101. package/rcf/fbs/fbs-013.json +42 -0
  102. package/rcf/fbs/fbs-014.json +49 -0
  103. package/rcf/fbs/fbs-015.json +32 -0
  104. package/rcf/manifest.json +17 -0
  105. package/rcf/prd.json +47 -0
  106. package/rcf/requirements/req-001.json +19 -0
  107. package/rcf/requirements/req-002.json +19 -0
  108. package/rcf/requirements/req-003.json +19 -0
  109. package/rcf/requirements/req-004.json +19 -0
  110. package/rcf/requirements/req-005.json +19 -0
  111. package/rcf/requirements/req-006.json +19 -0
  112. package/rcf/requirements/req-007.json +19 -0
  113. package/rcf/requirements/req-008.json +19 -0
  114. package/rcf/requirements/req-009.json +19 -0
  115. package/rcf/tacs/tac-001.json +45 -0
  116. package/rcf/tacs/tac-002.json +109 -0
  117. package/rcf/tacs/tac-003.json +40 -0
  118. package/rcf/tacs/tac-004.json +51 -0
  119. package/rcf/tacs/tac-005.json +52 -0
  120. package/rcf/tacs/tac-006.json +104 -0
  121. package/rcf/tacs/tac-007.json +38 -0
  122. package/rcf/tacs/tac-008.json +51 -0
  123. package/rcf/tad.json +51 -0
  124. package/rcf/test-suites/PENDING.md +23 -0
  125. package/rcf/test-suites/ts-001.json +38 -0
  126. package/rcf/test-suites/ts-002.json +38 -0
  127. package/rcf/test-suites/ts-003.json +43 -0
  128. package/rcf/test-suites/ts-004.json +44 -0
  129. package/rcf/test-suites/ts-005.json +30 -0
  130. package/rcf/test-suites/ts-006.json +36 -0
  131. package/rcf/test-suites/ts-007.json +43 -0
  132. package/rcf/test-suites/ts-008.json +37 -0
  133. package/rcf/test-suites/ts-009.json +38 -0
  134. package/rcf/test-suites/ts-010.json +38 -0
  135. package/rcf/test-suites/ts-011.json +44 -0
  136. package/rcf/test-suites/ts-012.json +36 -0
  137. package/rcf/test-suites/ts-013.json +38 -0
  138. package/rcf/test-suites/ts-014.json +38 -0
  139. package/rcf/test-suites/ts-015.json +38 -0
  140. package/rcf/test-suites/ts-016.json +37 -0
  141. package/rcf/test-suites/ts-017.json +38 -0
  142. package/rcf/test-suites/ts-018.json +38 -0
  143. package/rcf/test-suites/ts-019.json +37 -0
  144. package/rcf/test-suites/ts-020.json +46 -0
  145. package/rcf/test-suites/ts-021.json +46 -0
  146. package/rcf/test-suites/ts-022.json +46 -0
  147. package/rcf/test-suites/ts-023.json +46 -0
  148. package/rcf/test-suites/ts-024.json +46 -0
  149. package/rcf/test-suites/ts-025.json +52 -0
  150. package/rcf/user-stories/us-101.json +40 -0
  151. package/rcf/user-stories/us-102.json +40 -0
  152. package/rcf/user-stories/us-201.json +40 -0
  153. package/rcf/user-stories/us-202.json +40 -0
  154. package/rcf/user-stories/us-203.json +32 -0
  155. package/rcf/user-stories/us-301.json +40 -0
  156. package/rcf/user-stories/us-302.json +40 -0
  157. package/rcf/user-stories/us-303.json +40 -0
  158. package/rcf/user-stories/us-304.json +40 -0
  159. package/rcf/user-stories/us-401.json +40 -0
  160. package/rcf/user-stories/us-402.json +40 -0
  161. package/rcf/user-stories/us-403.json +40 -0
  162. package/rcf/user-stories/us-501.json +40 -0
  163. package/rcf/user-stories/us-502.json +40 -0
  164. package/rcf/user-stories/us-503.json +40 -0
  165. package/rcf/user-stories/us-601.json +40 -0
  166. package/rcf/user-stories/us-602.json +40 -0
  167. package/rcf/user-stories/us-701.json +40 -0
  168. package/rcf/user-stories/us-702.json +40 -0
  169. package/rcf/user-stories/us-801.json +49 -0
  170. package/rcf/user-stories/us-802.json +49 -0
  171. package/rcf/user-stories/us-803.json +49 -0
  172. package/rcf/user-stories/us-804.json +49 -0
  173. package/rcf/user-stories/us-805.json +49 -0
  174. package/rcf/user-stories/us-901.json +40 -0
  175. package/src/.gitkeep +0 -0
  176. package/src/browser-verify/auth-smoke.js +109 -0
  177. package/src/browser-verify/index.js +29 -0
  178. package/src/browser-verify/invariants.js +336 -0
  179. package/src/browser-verify/manifest-writer.js +189 -0
  180. package/src/browser-verify/runner.js +171 -0
  181. package/src/build/bundle.js +198 -0
  182. package/src/build/formatters/json.js +18 -0
  183. package/src/build/formatters/markdown.js +406 -0
  184. package/src/build/index.js +14 -0
  185. package/src/build/mark.js +177 -0
  186. package/src/build/queue.js +285 -0
  187. package/src/cli/browser-verify.js +231 -0
  188. package/src/cli/build.js +584 -0
  189. package/src/cli/coverage.js +219 -0
  190. package/src/cli/create.js +355 -0
  191. package/src/cli/delete.js +127 -0
  192. package/src/cli/design.js +353 -0
  193. package/src/cli/doctor.js +548 -0
  194. package/src/cli/fbs.js +171 -0
  195. package/src/cli/finalise.js +377 -0
  196. package/src/cli/guidance.js +206 -0
  197. package/src/cli/help.js +156 -0
  198. package/src/cli/impact.js +119 -0
  199. package/src/cli/init.js +282 -0
  200. package/src/cli/intake.js +153 -0
  201. package/src/cli/link.js +128 -0
  202. package/src/cli/mcp.js +160 -0
  203. package/src/cli/preflight.js +220 -0
  204. package/src/cli/read.js +162 -0
  205. package/src/cli/req-baseline.js +269 -0
  206. package/src/cli/req-classify.js +135 -0
  207. package/src/cli/review.js +295 -0
  208. package/src/cli/test-suite.js +216 -0
  209. package/src/cli/trace.js +172 -0
  210. package/src/cli/ui-baseline.js +292 -0
  211. package/src/cli/ui-classify.js +108 -0
  212. package/src/cli/update.js +197 -0
  213. package/src/cli/validate.js +168 -0
  214. package/src/cli/view.js +452 -0
  215. package/src/core/baseline-catalog/data/auth.json +42 -0
  216. package/src/core/baseline-catalog/data/http-api.json +42 -0
  217. package/src/core/baseline-catalog/data/notifications.json +33 -0
  218. package/src/core/baseline-catalog/data/persistence.json +33 -0
  219. package/src/core/baseline-catalog/data/web-ui.json +60 -0
  220. package/src/core/baseline-catalog/index.js +121 -0
  221. package/src/core/errors/index.js +167 -0
  222. package/src/core/fixtures/register-canary/canary-prompt-01.json +18 -0
  223. package/src/core/fixtures/register-canary/canary-prompt-02.json +21 -0
  224. package/src/core/fixtures/register-canary/canary-prompt-03.json +17 -0
  225. package/src/core/isolation/index.js +60 -0
  226. package/src/core/mcp/framing.js +103 -0
  227. package/src/core/mcp/index.js +8 -0
  228. package/src/core/mcp/server.js +228 -0
  229. package/src/core/patterns/register-canary.js +209 -0
  230. package/src/core/patterns/req-shapes.js +158 -0
  231. package/src/core/patterns/services.js +358 -0
  232. package/src/core/patterns/ui-shapes.js +166 -0
  233. package/src/core/store/cn-resolve.js +134 -0
  234. package/src/core/store/derive-deps.js +93 -0
  235. package/src/core/store/ids.js +78 -0
  236. package/src/core/store/index.js +20 -0
  237. package/src/core/store/init.js +255 -0
  238. package/src/core/store/loader.js +211 -0
  239. package/src/core/store/tp-resolve.js +176 -0
  240. package/src/core/store/validator.js +191 -0
  241. package/src/core/store/walker.js +898 -0
  242. package/src/core/store/writer.js +1849 -0
  243. package/src/design/index.js +11 -0
  244. package/src/design/writer.js +271 -0
  245. package/src/finalise/detect.js +129 -0
  246. package/src/finalise/index.js +17 -0
  247. package/src/finalise/ingest.js +119 -0
  248. package/src/finalise/install.js +119 -0
  249. package/src/finalise/ship-without-verified.js +131 -0
  250. package/src/finalise/spawn.js +84 -0
  251. package/src/intake/fidelity.js +105 -0
  252. package/src/intake/index.js +6 -0
  253. package/src/intake/manifest-writer.js +100 -0
  254. package/src/intake/orchestrator.js +138 -0
  255. package/src/intake/validate.js +80 -0
  256. package/src/mcp/map-errors.js +131 -0
  257. package/src/mcp/prompts.js +49 -0
  258. package/src/mcp/resources.js +244 -0
  259. package/src/mcp/tools.js +1204 -0
  260. package/src/preflight/design-shapes.js +185 -0
  261. package/src/preflight/index.js +90 -0
  262. package/src/preflight/manifest-writer.js +264 -0
  263. package/src/preflight/scanner.js +206 -0
  264. package/src/preflight/secrets.js +134 -0
  265. package/src/preflight/session.js +246 -0
  266. package/src/query/attestation.js +285 -0
  267. package/src/query/coverage.js +308 -0
  268. package/src/query/formatters/json.js +21 -0
  269. package/src/query/formatters/mermaid.js +209 -0
  270. package/src/query/formatters/table.js +203 -0
  271. package/src/query/impact.js +173 -0
  272. package/src/query/index.js +9 -0
  273. package/src/query/trace.js +345 -0
  274. package/src/register-canary/fixture-loader.js +87 -0
  275. package/src/register-canary/index.js +10 -0
  276. package/src/register-canary/record-writer.js +132 -0
  277. package/src/register-canary/runner.js +156 -0
  278. package/src/req-baseline/gate.js +86 -0
  279. package/src/req-baseline/index.js +27 -0
  280. package/src/req-baseline/open-candidates.js +143 -0
  281. package/src/req-baseline/opt-out.js +195 -0
  282. package/src/req-baseline/sweep.js +230 -0
  283. package/src/req-detection/classifier.js +181 -0
  284. package/src/req-detection/index.js +9 -0
  285. package/src/req-detection/persist.js +55 -0
  286. package/src/review/index.js +325 -0
  287. package/src/review/mutation.js +117 -0
  288. package/src/review/ui-baseline-drift.js +138 -0
  289. package/src/server/index.js +178 -0
  290. package/src/server/routes.js +110 -0
  291. package/src/server/sse.js +118 -0
  292. package/src/setup/agent-setup.js +362 -0
  293. package/src/setup/identity-seed.js +104 -0
  294. package/src/setup/knowledge-seed.js +123 -0
  295. package/src/setup/managed-block.js +193 -0
  296. package/src/setup/managed-gitignore.js +166 -0
  297. package/src/setup/managed-markers.js +49 -0
  298. package/src/ui-baseline/defaults.js +119 -0
  299. package/src/ui-baseline/index.js +25 -0
  300. package/src/ui-baseline/manifest-writer.js +282 -0
  301. package/src/ui-baseline/session.js +178 -0
  302. package/src/ui-detection/classifier.js +192 -0
  303. package/src/verify/chain/index.js +190 -0
  304. package/src/verify/cli/cleanup.js +61 -0
  305. package/src/verify/cli/help.js +56 -0
  306. package/src/verify/cli/mcp.js +98 -0
  307. package/src/verify/cli/provision.js +71 -0
  308. package/src/verify/cli/report.js +71 -0
  309. package/src/verify/cli/run.js +155 -0
  310. package/src/verify/engine/brief.js +87 -0
  311. package/src/verify/engine/index.js +177 -0
  312. package/src/verify/engine/launcher.js +307 -0
  313. package/src/verify/mcp/tools.js +107 -0
  314. package/src/verify/profile/index.js +146 -0
  315. package/src/verify/provision/index.js +256 -0
  316. package/src/verify/report/index.js +139 -0
  317. package/src/verify/report/renderer.js +118 -0
  318. package/src/verify/verdict/index.js +246 -0
  319. package/src/view/doc-renderers/adr.js +44 -0
  320. package/src/view/doc-renderers/build-sequence.js +40 -0
  321. package/src/view/doc-renderers/fbs.js +128 -0
  322. package/src/view/doc-renderers/helpers.js +159 -0
  323. package/src/view/doc-renderers/index.js +12 -0
  324. package/src/view/doc-renderers/prd.js +45 -0
  325. package/src/view/doc-renderers/req.js +43 -0
  326. package/src/view/doc-renderers/tac.js +38 -0
  327. package/src/view/doc-renderers/tad.js +74 -0
  328. package/src/view/doc-renderers/test-suite.js +45 -0
  329. package/src/view/doc-renderers/user-story.js +63 -0
  330. package/src/view/html-page.js +462 -0
  331. package/src/view/index.js +63 -0
  332. package/src/view/live-client.js +338 -0
  333. package/src/view/mermaid-diagram.js +178 -0
  334. package/src/view/style.css +735 -0
  335. package/src/view/tree-model.js +152 -0
  336. package/src/view/vendored/mermaid.min.js +2607 -0
  337. package/src/view-supervisor/index.js +26 -0
  338. package/src/view-supervisor/logs.js +32 -0
  339. package/src/view-supervisor/manifest-writer.js +178 -0
  340. package/src/view-supervisor/persist-until.js +85 -0
  341. package/src/view-supervisor/supervisor.js +276 -0
  342. package/src/watch/index.js +152 -0
@@ -0,0 +1,43 @@
1
+ // REQ renderer. Carries an optional per-REQ Mermaid subdiagram block when
2
+ // the caller passes one (the html-page module decides whether to include it).
3
+ // Child user stories are NOT rendered as inline links because the Phase 3.2
4
+ // layout nests them as `<details>` under the REQ's own `<details>` wrapper.
5
+
6
+ import {
7
+ anchorIdFor,
8
+ brokenBanner,
9
+ escapeHtml,
10
+ fieldList,
11
+ fieldPara,
12
+ rawJsonDisclosure,
13
+ } from './helpers.js';
14
+
15
+ /**
16
+ * @param {object} req
17
+ * @param {object} ctx
18
+ * @param {string|undefined} ctx.raw
19
+ * @param {import('#core/errors').RcfError[]} [ctx.errors]
20
+ * @param {string|undefined} [ctx.subdiagram]
21
+ * @returns {string}
22
+ */
23
+ export function renderReq(req, ctx) {
24
+ if (!req) return '';
25
+ const anchor = anchorIdFor(req.reqId ?? 'REQ');
26
+ const broken = ctx.errors?.length ? brokenBanner(ctx.errors) : '';
27
+ const subdiagram = ctx.subdiagram
28
+ ? `<section class="subdiagram"><h4>Slice diagram</h4><pre class="mermaid">${escapeHtml(ctx.subdiagram)}</pre></section>`
29
+ : '';
30
+ return `
31
+ <article id="${anchor}" class="doc doc-req">
32
+ <h3>${escapeHtml(req.reqId ?? 'REQ')} - ${escapeHtml(req.title ?? '')}</h3>
33
+ ${broken}
34
+ ${fieldPara('Description', req.description)}
35
+ ${fieldPara('Category', req.category)}
36
+ ${fieldPara('Domain', req.domain)}
37
+ ${fieldPara('Priority', req.priority)}
38
+ ${fieldPara('Rationale', req.rationale)}
39
+ ${fieldList('Tags', req.tags)}
40
+ ${subdiagram}
41
+ ${rawJsonDisclosure(ctx.raw, req, req.reqId)}
42
+ </article>`.trim();
43
+ }
@@ -0,0 +1,38 @@
1
+ // TAC renderer.
2
+
3
+ import {
4
+ anchorIdFor,
5
+ brokenBanner,
6
+ escapeHtml,
7
+ fieldList,
8
+ fieldPara,
9
+ rawJsonDisclosure,
10
+ } from './helpers.js';
11
+
12
+ /**
13
+ * @param {object} tac
14
+ * @param {object} ctx
15
+ * @param {string|undefined} ctx.raw
16
+ * @param {import('#core/errors').RcfError[]} [ctx.errors]
17
+ * @returns {string}
18
+ */
19
+ export function renderTac(tac, ctx) {
20
+ if (!tac) return '';
21
+ const anchor = anchorIdFor(tac.tacId ?? 'TAC');
22
+ const broken = ctx.errors?.length ? brokenBanner(ctx.errors) : '';
23
+ const interfaces = (tac.interfaces ?? []).map((i) => `<li><strong>${escapeHtml(i.name ?? '')}</strong> (${escapeHtml(i.kind ?? '')}) - ${escapeHtml(i.description ?? '')}</li>`).join('');
24
+ const deps = (tac.dependencies ?? []).map((d) => `<li><strong>${escapeHtml(d.name ?? '')}</strong> (${escapeHtml(d.kind ?? '')}) - ${escapeHtml(d.description ?? '')}</li>`).join('');
25
+ return `
26
+ <article id="${anchor}" class="doc doc-tac">
27
+ <h3>${escapeHtml(tac.tacId ?? 'TAC')} - ${escapeHtml(tac.name ?? '')}</h3>
28
+ ${broken}
29
+ ${fieldPara('Purpose', tac.purpose)}
30
+ ${fieldList('Responsibilities', tac.responsibilities)}
31
+ ${fieldPara('Internal structure', tac.internalStructure)}
32
+ ${interfaces ? `<section class="field-list"><h4>Interfaces</h4><ul>${interfaces}</ul></section>` : ''}
33
+ ${deps ? `<section class="field-list"><h4>Dependencies</h4><ul>${deps}</ul></section>` : ''}
34
+ ${fieldPara('Trade-offs', tac.tradeoffs)}
35
+ ${fieldPara('Notes', tac.notes)}
36
+ ${rawJsonDisclosure(ctx.raw, tac, tac.tacId)}
37
+ </article>`.trim();
38
+ }
@@ -0,0 +1,74 @@
1
+ // TAD renderer. Curated fields per spec D11; iterates the architecturePrinciples[]
2
+ // array rather than hard-coding a count. Post-3.7 (D15) the child TAC / ADR
3
+ // lists are not read from removed parent fields (`componentIds`,
4
+ // `architecturalDecisionIds`) but from computed lists supplied via ctx.
5
+
6
+ import {
7
+ anchorIdFor,
8
+ brokenBanner,
9
+ docLinkList,
10
+ escapeHtml,
11
+ fieldList,
12
+ fieldPara,
13
+ rawJsonDisclosure,
14
+ } from './helpers.js';
15
+
16
+ /**
17
+ * @param {object} tad
18
+ * @param {object} ctx
19
+ * @param {string|undefined} ctx.raw
20
+ * @param {import('#core/errors').RcfError[]} [ctx.errors]
21
+ * @param {string[]} [ctx.componentIds] - computed TAC children
22
+ * @param {string[]} [ctx.architecturalDecisionIds] - computed ADR children
23
+ * @returns {string}
24
+ */
25
+ export function renderTad(tad, ctx) {
26
+ if (!tad) return '';
27
+ const anchor = anchorIdFor(tad.tadId ?? 'TAD');
28
+ const broken = ctx.errors?.length ? brokenBanner(ctx.errors) : '';
29
+ const overview = tad.systemOverview ?? {};
30
+ const componentIds = ctx.componentIds ?? [];
31
+ const architecturalDecisionIds = ctx.architecturalDecisionIds ?? [];
32
+ const principles = (tad.architecturePrinciples ?? []).map((p) => `
33
+ <li>
34
+ <strong>${escapeHtml(p.name)}.</strong> ${escapeHtml(p.description)}
35
+ <br/><em>Rationale:</em> ${escapeHtml(p.rationale)}
36
+ </li>`.trim()).join('\n');
37
+ const optionalSections = renderOptionalSections(tad);
38
+ return `
39
+ <article id="${anchor}" class="doc doc-tad">
40
+ <h3>${escapeHtml(tad.tadId ?? 'TAD')} - Technical Architecture Document</h3>
41
+ ${broken}
42
+ ${fieldPara('Executive summary', overview.executiveSummary)}
43
+ ${fieldPara('System purpose', overview.systemPurpose)}
44
+ ${fieldPara('Architectural approach', overview.architecturalApproach)}
45
+ ${fieldList('Key capabilities', overview.keyCapabilities)}
46
+ ${principles ? `<section class="field-list"><h4>Architecture principles</h4><ul>${principles}</ul></section>` : ''}
47
+ ${optionalSections}
48
+ <section class="field-list"><h4>Components (TACs)</h4><p>${docLinkList(componentIds)}</p></section>
49
+ <section class="field-list"><h4>Architectural decisions (ADRs)</h4><p>${docLinkList(architecturalDecisionIds)}</p></section>
50
+ ${rawJsonDisclosure(ctx.raw, tad, tad.tadId)}
51
+ </article>`.trim();
52
+ }
53
+
54
+ function renderOptionalSections(tad) {
55
+ const out = [];
56
+ const named = {
57
+ dataArchitecture: 'Data architecture',
58
+ integrationArchitecture: 'Integration architecture',
59
+ securityArchitecture: 'Security architecture',
60
+ deploymentArchitecture: 'Deployment architecture',
61
+ operationalConcerns: 'Operational concerns',
62
+ };
63
+ for (const [key, label] of Object.entries(named)) {
64
+ const section = tad[key];
65
+ if (!section || typeof section !== 'object') continue;
66
+ const rows = Object.entries(section).map(([k, v]) => {
67
+ if (typeof v === 'string') return `<dt>${escapeHtml(k)}</dt><dd>${escapeHtml(v)}</dd>`;
68
+ if (Array.isArray(v)) return `<dt>${escapeHtml(k)}</dt><dd>${v.map((x) => `<code>${escapeHtml(typeof x === 'object' ? JSON.stringify(x) : x)}</code>`).join(', ')}</dd>`;
69
+ return `<dt>${escapeHtml(k)}</dt><dd><pre>${escapeHtml(JSON.stringify(v, null, 2))}</pre></dd>`;
70
+ }).join('\n');
71
+ out.push(`<section class="field-list"><h4>${escapeHtml(label)}</h4><dl>${rows}</dl></section>`);
72
+ }
73
+ return out.join('\n');
74
+ }
@@ -0,0 +1,45 @@
1
+ // Test suite renderer. Post-3.7 the TS id field is `id` (matches the
2
+ // 0.2.0 test-suite schema); inline test cases carry `id` + `acId` +
3
+ // `description` + `status` (+ optional `testPointer`).
4
+
5
+ import {
6
+ anchorIdFor,
7
+ brokenBanner,
8
+ docLink,
9
+ docLinkList,
10
+ escapeHtml,
11
+ fieldPara,
12
+ rawJsonDisclosure,
13
+ } from './helpers.js';
14
+
15
+ /**
16
+ * @param {object} ts
17
+ * @param {object} ctx
18
+ * @param {string|undefined} ctx.raw
19
+ * @param {import('#core/errors').RcfError[]} [ctx.errors]
20
+ * @returns {string}
21
+ */
22
+ export function renderTestSuite(ts, ctx) {
23
+ if (!ts) return '';
24
+ const tsId = ts.id ?? 'TS';
25
+ const anchor = anchorIdFor(tsId);
26
+ const broken = ctx.errors?.length ? brokenBanner(ctx.errors) : '';
27
+ const tcs = (ts.testCases ?? []).map((tc) => `
28
+ <div class="tc" id="${escapeHtml(tc.id ?? '')}">
29
+ <p><strong>${escapeHtml(tc.id ?? 'TC')}</strong> - covers ${tc.acId ? docLink(tc.acId) : 'AC'} <span class="status ${escapeHtml(tc.status ?? '')}">${escapeHtml(tc.status ?? 'pending')}</span></p>
30
+ ${tc.description ? `<p>${escapeHtml(tc.description)}</p>` : ''}
31
+ ${tc.testPointer ? `<p><em>Test pointer:</em> <code>${escapeHtml(tc.testPointer)}</code></p>` : ''}
32
+ </div>`.trim()).join('\n');
33
+ return `
34
+ <article id="${anchor}" class="doc doc-ts">
35
+ <h3>${escapeHtml(tsId)} - ${escapeHtml(ts.title ?? 'test suite')}</h3>
36
+ ${broken}
37
+ ${ts.usId ? `<p><strong>Verifies user story:</strong> ${docLink(ts.usId)}</p>` : ''}
38
+ ${fieldPara('Purpose', ts.purpose)}
39
+ ${fieldPara('Test level', ts.testLevel)}
40
+ ${ts.acIds?.length ? `<section class="field-list"><h4>Acceptance criteria verified</h4><p>${docLinkList(ts.acIds)}</p></section>` : ''}
41
+ ${fieldPara('Status', ts.status)}
42
+ <section class="field-list"><h4>Test cases</h4>${tcs || '<em>no test cases</em>'}</section>
43
+ ${rawJsonDisclosure(ctx.raw, ts, ts.id)}
44
+ </article>`.trim();
45
+ }
@@ -0,0 +1,63 @@
1
+ // User story renderer. ACs are rendered inline as list items so an AC can
2
+ // be a top-level scroll anchor (per Phase 3.2 D4) without wrapping each in
3
+ // its own `<section>`. Each AC line links back to the FBS or FBSs that
4
+ // deliver it via `fbsByAcId` (D8).
5
+
6
+ import {
7
+ anchorIdFor,
8
+ brokenBanner,
9
+ docLink,
10
+ escapeHtml,
11
+ fieldPara,
12
+ rawJsonDisclosure,
13
+ } from './helpers.js';
14
+
15
+ /**
16
+ * @param {object} us
17
+ * @param {object} ctx
18
+ * @param {string|undefined} ctx.raw
19
+ * @param {import('#core/errors').RcfError[]} [ctx.errors]
20
+ * @param {Map<string, object[]>} [ctx.fbsByAcId]
21
+ * @returns {string}
22
+ */
23
+ export function renderUserStory(us, ctx) {
24
+ if (!us) return '';
25
+ const anchor = anchorIdFor(us.usId ?? 'US');
26
+ const broken = ctx.errors?.length ? brokenBanner(ctx.errors) : '';
27
+ const acItems = (us.acceptanceCriteria ?? []).map((ac) => renderAcItem(ac, ctx)).join('\n');
28
+ return `
29
+ <article id="${anchor}" class="doc doc-us">
30
+ <h3>${escapeHtml(us.usId ?? 'US')} - ${escapeHtml(us.title ?? '')}</h3>
31
+ ${broken}
32
+ <p><strong>As a:</strong> ${escapeHtml(us.asA ?? '')}</p>
33
+ <p><strong>I want:</strong> ${escapeHtml(us.iWant ?? '')}</p>
34
+ <p><strong>So that:</strong> ${escapeHtml(us.soThat ?? '')}</p>
35
+ ${fieldPara('Description', us.description)}
36
+ <section class="field-list"><h4>Requirement</h4><p>${docLink(us.reqId)}</p></section>
37
+ <section class="acceptance-criteria">
38
+ <h4>Acceptance criteria</h4>
39
+ <ul class="ac-list">
40
+ ${acItems}
41
+ </ul>
42
+ </section>
43
+ ${rawJsonDisclosure(ctx.raw, us, us.usId)}
44
+ </article>`.trim();
45
+ }
46
+
47
+ function renderAcItem(ac, ctx) {
48
+ const acId = ac.id ?? 'AC';
49
+ const acAnchor = anchorIdFor(acId);
50
+ const fbsList = ctx.fbsByAcId?.get(acId) ?? [];
51
+ const coveredBy = fbsList.length === 0
52
+ ? '<em>not yet delivered by any FBS</em>'
53
+ : `Covered by ${fbsList.map((f) => docLink(f.fbsId)).join(', ')}`;
54
+ const parts = [];
55
+ parts.push(`<strong>${escapeHtml(acId)}</strong> - ${escapeHtml(ac.description ?? '')}`);
56
+ const gwt = [];
57
+ if (ac.given) gwt.push(`<em>Given</em> ${escapeHtml(ac.given)}`);
58
+ if (ac.when) gwt.push(`<em>When</em> ${escapeHtml(ac.when)}`);
59
+ if (ac.then) gwt.push(`<em>Then</em> ${escapeHtml(ac.then)}`);
60
+ if (gwt.length > 0) parts.push(`<div class="ac-gwt">${gwt.map((p) => `<p>${p}</p>`).join('')}</div>`);
61
+ parts.push(`<p class="ac-meta"><strong>Testable:</strong> ${escapeHtml(String(ac.testable ?? false))} - ${coveredBy}</p>`);
62
+ return `<li id="${acAnchor}" class="ac-item">${parts.join('\n')}</li>`;
63
+ }