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.
- package/CHANGELOG.md +288 -0
- package/LICENSE +202 -0
- package/README.md +92 -4
- package/bin/rcf-verify.js +122 -0
- package/bin/rcf.js +174 -0
- package/bin/view-supervisor-child.mjs +14 -0
- package/fixtures/canary-manifest.json +103 -0
- package/guidance/README.md +25 -0
- package/guidance/build-cycle-playbook.md +492 -0
- package/guidance/build-cycle.md +40 -0
- package/guidance/document-model.md +45 -0
- package/guidance/elicitation-playbook.md +442 -0
- package/guidance/harness-template.md +246 -0
- package/guidance/managed/README.md +63 -0
- package/guidance/managed/agent-instructions-block.hash +1 -0
- package/guidance/managed/agent-instructions-block.md +220 -0
- package/guidance/managed/legacy-fragment-hashes.json +22 -0
- package/guidance/manifest.json +21 -0
- package/guidance/overview.md +48 -0
- package/guidance/persona-programme.md +44 -0
- package/package.json +69 -8
- package/rcf/adrs/adr-001.json +25 -0
- package/rcf/adrs/adr-002.json +25 -0
- package/rcf/adrs/adr-003.json +25 -0
- package/rcf/adrs/adr-004.json +20 -0
- package/rcf/adrs/adr-005.json +20 -0
- package/rcf/adrs/adr-006.json +25 -0
- package/rcf/adrs/adr-007.json +25 -0
- package/rcf/adrs/adr-008.json +25 -0
- package/rcf/adrs/adr-009.json +25 -0
- package/rcf/build-sequence.json +11 -0
- package/rcf/code-nodes/cn-001.json +14 -0
- package/rcf/code-nodes/cn-002.json +14 -0
- package/rcf/code-nodes/cn-003.json +15 -0
- package/rcf/code-nodes/cn-004.json +17 -0
- package/rcf/code-nodes/cn-005.json +19 -0
- package/rcf/code-nodes/cn-006.json +17 -0
- package/rcf/code-nodes/cn-007.json +16 -0
- package/rcf/code-nodes/cn-008.json +19 -0
- package/rcf/code-nodes/cn-009.json +16 -0
- package/rcf/code-nodes/cn-010.json +18 -0
- package/rcf/code-nodes/cn-011.json +18 -0
- package/rcf/code-nodes/cn-012.json +18 -0
- package/rcf/code-nodes/cn-013.json +19 -0
- package/rcf/code-nodes/cn-014.json +16 -0
- package/rcf/code-nodes/cn-015.json +16 -0
- package/rcf/code-nodes/cn-016.json +16 -0
- package/rcf/code-nodes/cn-017.json +16 -0
- package/rcf/code-nodes/cn-018.json +15 -0
- package/rcf/code-nodes/cn-019.json +16 -0
- package/rcf/code-nodes/cn-020.json +16 -0
- package/rcf/code-nodes/cn-021.json +16 -0
- package/rcf/code-nodes/cn-022.json +16 -0
- package/rcf/code-nodes/cn-023.json +16 -0
- package/rcf/code-nodes/cn-024.json +16 -0
- package/rcf/code-nodes/cn-025.json +16 -0
- package/rcf/code-nodes/cn-026.json +16 -0
- package/rcf/code-nodes/cn-027.json +16 -0
- package/rcf/code-nodes/cn-028.json +16 -0
- package/rcf/code-nodes/cn-029.json +19 -0
- package/rcf/code-nodes/cn-030.json +14 -0
- package/rcf/code-nodes/cn-031.json +14 -0
- package/rcf/code-nodes/cn-032.json +14 -0
- package/rcf/code-nodes/cn-033.json +14 -0
- package/rcf/code-nodes/cn-034.json +14 -0
- package/rcf/code-nodes/cn-035.json +14 -0
- package/rcf/code-nodes/cn-036.json +14 -0
- package/rcf/code-nodes/cn-037.json +14 -0
- package/rcf/code-nodes/cn-038.json +14 -0
- package/rcf/code-nodes/cn-039.json +14 -0
- package/rcf/code-nodes/cn-040.json +14 -0
- package/rcf/code-nodes/cn-041.json +14 -0
- package/rcf/code-nodes/cn-042.json +14 -0
- package/rcf/code-nodes/cn-043.json +14 -0
- package/rcf/code-nodes/cn-044.json +14 -0
- package/rcf/code-nodes/cn-045.json +14 -0
- package/rcf/code-nodes/cn-046.json +14 -0
- package/rcf/code-nodes/cn-047.json +14 -0
- package/rcf/code-nodes/cn-048.json +14 -0
- package/rcf/code-nodes/cn-049.json +14 -0
- package/rcf/code-nodes/cn-050.json +14 -0
- package/rcf/code-nodes/cn-051.json +14 -0
- package/rcf/code-nodes/cn-052.json +14 -0
- package/rcf/code-nodes/cn-053.json +14 -0
- package/rcf/code-nodes/cn-054.json +14 -0
- package/rcf/code-nodes/cn-055.json +14 -0
- package/rcf/code-nodes/cn-056.json +14 -0
- package/rcf/code-nodes/cn-057.json +14 -0
- package/rcf/fbs/fbs-001.json +49 -0
- package/rcf/fbs/fbs-002.json +42 -0
- package/rcf/fbs/fbs-003.json +37 -0
- package/rcf/fbs/fbs-004.json +39 -0
- package/rcf/fbs/fbs-005.json +38 -0
- package/rcf/fbs/fbs-006.json +48 -0
- package/rcf/fbs/fbs-007.json +39 -0
- package/rcf/fbs/fbs-008.json +40 -0
- package/rcf/fbs/fbs-009.json +36 -0
- package/rcf/fbs/fbs-010.json +41 -0
- package/rcf/fbs/fbs-011.json +36 -0
- package/rcf/fbs/fbs-012.json +46 -0
- package/rcf/fbs/fbs-013.json +42 -0
- package/rcf/fbs/fbs-014.json +49 -0
- package/rcf/fbs/fbs-015.json +32 -0
- package/rcf/manifest.json +17 -0
- package/rcf/prd.json +47 -0
- package/rcf/requirements/req-001.json +19 -0
- package/rcf/requirements/req-002.json +19 -0
- package/rcf/requirements/req-003.json +19 -0
- package/rcf/requirements/req-004.json +19 -0
- package/rcf/requirements/req-005.json +19 -0
- package/rcf/requirements/req-006.json +19 -0
- package/rcf/requirements/req-007.json +19 -0
- package/rcf/requirements/req-008.json +19 -0
- package/rcf/requirements/req-009.json +19 -0
- package/rcf/tacs/tac-001.json +45 -0
- package/rcf/tacs/tac-002.json +109 -0
- package/rcf/tacs/tac-003.json +40 -0
- package/rcf/tacs/tac-004.json +51 -0
- package/rcf/tacs/tac-005.json +52 -0
- package/rcf/tacs/tac-006.json +104 -0
- package/rcf/tacs/tac-007.json +38 -0
- package/rcf/tacs/tac-008.json +51 -0
- package/rcf/tad.json +51 -0
- package/rcf/test-suites/PENDING.md +23 -0
- package/rcf/test-suites/ts-001.json +38 -0
- package/rcf/test-suites/ts-002.json +38 -0
- package/rcf/test-suites/ts-003.json +43 -0
- package/rcf/test-suites/ts-004.json +44 -0
- package/rcf/test-suites/ts-005.json +30 -0
- package/rcf/test-suites/ts-006.json +36 -0
- package/rcf/test-suites/ts-007.json +43 -0
- package/rcf/test-suites/ts-008.json +37 -0
- package/rcf/test-suites/ts-009.json +38 -0
- package/rcf/test-suites/ts-010.json +38 -0
- package/rcf/test-suites/ts-011.json +44 -0
- package/rcf/test-suites/ts-012.json +36 -0
- package/rcf/test-suites/ts-013.json +38 -0
- package/rcf/test-suites/ts-014.json +38 -0
- package/rcf/test-suites/ts-015.json +38 -0
- package/rcf/test-suites/ts-016.json +37 -0
- package/rcf/test-suites/ts-017.json +38 -0
- package/rcf/test-suites/ts-018.json +38 -0
- package/rcf/test-suites/ts-019.json +37 -0
- package/rcf/test-suites/ts-020.json +46 -0
- package/rcf/test-suites/ts-021.json +46 -0
- package/rcf/test-suites/ts-022.json +46 -0
- package/rcf/test-suites/ts-023.json +46 -0
- package/rcf/test-suites/ts-024.json +46 -0
- package/rcf/test-suites/ts-025.json +52 -0
- package/rcf/user-stories/us-101.json +40 -0
- package/rcf/user-stories/us-102.json +40 -0
- package/rcf/user-stories/us-201.json +40 -0
- package/rcf/user-stories/us-202.json +40 -0
- package/rcf/user-stories/us-203.json +32 -0
- package/rcf/user-stories/us-301.json +40 -0
- package/rcf/user-stories/us-302.json +40 -0
- package/rcf/user-stories/us-303.json +40 -0
- package/rcf/user-stories/us-304.json +40 -0
- package/rcf/user-stories/us-401.json +40 -0
- package/rcf/user-stories/us-402.json +40 -0
- package/rcf/user-stories/us-403.json +40 -0
- package/rcf/user-stories/us-501.json +40 -0
- package/rcf/user-stories/us-502.json +40 -0
- package/rcf/user-stories/us-503.json +40 -0
- package/rcf/user-stories/us-601.json +40 -0
- package/rcf/user-stories/us-602.json +40 -0
- package/rcf/user-stories/us-701.json +40 -0
- package/rcf/user-stories/us-702.json +40 -0
- package/rcf/user-stories/us-801.json +49 -0
- package/rcf/user-stories/us-802.json +49 -0
- package/rcf/user-stories/us-803.json +49 -0
- package/rcf/user-stories/us-804.json +49 -0
- package/rcf/user-stories/us-805.json +49 -0
- package/rcf/user-stories/us-901.json +40 -0
- package/src/.gitkeep +0 -0
- package/src/browser-verify/auth-smoke.js +109 -0
- package/src/browser-verify/index.js +29 -0
- package/src/browser-verify/invariants.js +336 -0
- package/src/browser-verify/manifest-writer.js +189 -0
- package/src/browser-verify/runner.js +171 -0
- package/src/build/bundle.js +198 -0
- package/src/build/formatters/json.js +18 -0
- package/src/build/formatters/markdown.js +406 -0
- package/src/build/index.js +14 -0
- package/src/build/mark.js +177 -0
- package/src/build/queue.js +285 -0
- package/src/cli/browser-verify.js +231 -0
- package/src/cli/build.js +584 -0
- package/src/cli/coverage.js +219 -0
- package/src/cli/create.js +355 -0
- package/src/cli/delete.js +127 -0
- package/src/cli/design.js +353 -0
- package/src/cli/doctor.js +548 -0
- package/src/cli/fbs.js +171 -0
- package/src/cli/finalise.js +377 -0
- package/src/cli/guidance.js +206 -0
- package/src/cli/help.js +156 -0
- package/src/cli/impact.js +119 -0
- package/src/cli/init.js +282 -0
- package/src/cli/intake.js +153 -0
- package/src/cli/link.js +128 -0
- package/src/cli/mcp.js +160 -0
- package/src/cli/preflight.js +220 -0
- package/src/cli/read.js +162 -0
- package/src/cli/req-baseline.js +269 -0
- package/src/cli/req-classify.js +135 -0
- package/src/cli/review.js +295 -0
- package/src/cli/test-suite.js +216 -0
- package/src/cli/trace.js +172 -0
- package/src/cli/ui-baseline.js +292 -0
- package/src/cli/ui-classify.js +108 -0
- package/src/cli/update.js +197 -0
- package/src/cli/validate.js +168 -0
- package/src/cli/view.js +452 -0
- package/src/core/baseline-catalog/data/auth.json +42 -0
- package/src/core/baseline-catalog/data/http-api.json +42 -0
- package/src/core/baseline-catalog/data/notifications.json +33 -0
- package/src/core/baseline-catalog/data/persistence.json +33 -0
- package/src/core/baseline-catalog/data/web-ui.json +60 -0
- package/src/core/baseline-catalog/index.js +121 -0
- package/src/core/errors/index.js +167 -0
- package/src/core/fixtures/register-canary/canary-prompt-01.json +18 -0
- package/src/core/fixtures/register-canary/canary-prompt-02.json +21 -0
- package/src/core/fixtures/register-canary/canary-prompt-03.json +17 -0
- package/src/core/isolation/index.js +60 -0
- package/src/core/mcp/framing.js +103 -0
- package/src/core/mcp/index.js +8 -0
- package/src/core/mcp/server.js +228 -0
- package/src/core/patterns/register-canary.js +209 -0
- package/src/core/patterns/req-shapes.js +158 -0
- package/src/core/patterns/services.js +358 -0
- package/src/core/patterns/ui-shapes.js +166 -0
- package/src/core/store/cn-resolve.js +134 -0
- package/src/core/store/derive-deps.js +93 -0
- package/src/core/store/ids.js +78 -0
- package/src/core/store/index.js +20 -0
- package/src/core/store/init.js +255 -0
- package/src/core/store/loader.js +211 -0
- package/src/core/store/tp-resolve.js +176 -0
- package/src/core/store/validator.js +191 -0
- package/src/core/store/walker.js +898 -0
- package/src/core/store/writer.js +1849 -0
- package/src/design/index.js +11 -0
- package/src/design/writer.js +271 -0
- package/src/finalise/detect.js +129 -0
- package/src/finalise/index.js +17 -0
- package/src/finalise/ingest.js +119 -0
- package/src/finalise/install.js +119 -0
- package/src/finalise/ship-without-verified.js +131 -0
- package/src/finalise/spawn.js +84 -0
- package/src/intake/fidelity.js +105 -0
- package/src/intake/index.js +6 -0
- package/src/intake/manifest-writer.js +100 -0
- package/src/intake/orchestrator.js +138 -0
- package/src/intake/validate.js +80 -0
- package/src/mcp/map-errors.js +131 -0
- package/src/mcp/prompts.js +49 -0
- package/src/mcp/resources.js +244 -0
- package/src/mcp/tools.js +1204 -0
- package/src/preflight/design-shapes.js +185 -0
- package/src/preflight/index.js +90 -0
- package/src/preflight/manifest-writer.js +264 -0
- package/src/preflight/scanner.js +206 -0
- package/src/preflight/secrets.js +134 -0
- package/src/preflight/session.js +246 -0
- package/src/query/attestation.js +285 -0
- package/src/query/coverage.js +308 -0
- package/src/query/formatters/json.js +21 -0
- package/src/query/formatters/mermaid.js +209 -0
- package/src/query/formatters/table.js +203 -0
- package/src/query/impact.js +173 -0
- package/src/query/index.js +9 -0
- package/src/query/trace.js +345 -0
- package/src/register-canary/fixture-loader.js +87 -0
- package/src/register-canary/index.js +10 -0
- package/src/register-canary/record-writer.js +132 -0
- package/src/register-canary/runner.js +156 -0
- package/src/req-baseline/gate.js +86 -0
- package/src/req-baseline/index.js +27 -0
- package/src/req-baseline/open-candidates.js +143 -0
- package/src/req-baseline/opt-out.js +195 -0
- package/src/req-baseline/sweep.js +230 -0
- package/src/req-detection/classifier.js +181 -0
- package/src/req-detection/index.js +9 -0
- package/src/req-detection/persist.js +55 -0
- package/src/review/index.js +325 -0
- package/src/review/mutation.js +117 -0
- package/src/review/ui-baseline-drift.js +138 -0
- package/src/server/index.js +178 -0
- package/src/server/routes.js +110 -0
- package/src/server/sse.js +118 -0
- package/src/setup/agent-setup.js +362 -0
- package/src/setup/identity-seed.js +104 -0
- package/src/setup/knowledge-seed.js +123 -0
- package/src/setup/managed-block.js +193 -0
- package/src/setup/managed-gitignore.js +166 -0
- package/src/setup/managed-markers.js +49 -0
- package/src/ui-baseline/defaults.js +119 -0
- package/src/ui-baseline/index.js +25 -0
- package/src/ui-baseline/manifest-writer.js +282 -0
- package/src/ui-baseline/session.js +178 -0
- package/src/ui-detection/classifier.js +192 -0
- package/src/verify/chain/index.js +190 -0
- package/src/verify/cli/cleanup.js +61 -0
- package/src/verify/cli/help.js +56 -0
- package/src/verify/cli/mcp.js +98 -0
- package/src/verify/cli/provision.js +71 -0
- package/src/verify/cli/report.js +71 -0
- package/src/verify/cli/run.js +155 -0
- package/src/verify/engine/brief.js +87 -0
- package/src/verify/engine/index.js +177 -0
- package/src/verify/engine/launcher.js +307 -0
- package/src/verify/mcp/tools.js +107 -0
- package/src/verify/profile/index.js +146 -0
- package/src/verify/provision/index.js +256 -0
- package/src/verify/report/index.js +139 -0
- package/src/verify/report/renderer.js +118 -0
- package/src/verify/verdict/index.js +246 -0
- package/src/view/doc-renderers/adr.js +44 -0
- package/src/view/doc-renderers/build-sequence.js +40 -0
- package/src/view/doc-renderers/fbs.js +128 -0
- package/src/view/doc-renderers/helpers.js +159 -0
- package/src/view/doc-renderers/index.js +12 -0
- package/src/view/doc-renderers/prd.js +45 -0
- package/src/view/doc-renderers/req.js +43 -0
- package/src/view/doc-renderers/tac.js +38 -0
- package/src/view/doc-renderers/tad.js +74 -0
- package/src/view/doc-renderers/test-suite.js +45 -0
- package/src/view/doc-renderers/user-story.js +63 -0
- package/src/view/html-page.js +462 -0
- package/src/view/index.js +63 -0
- package/src/view/live-client.js +338 -0
- package/src/view/mermaid-diagram.js +178 -0
- package/src/view/style.css +735 -0
- package/src/view/tree-model.js +152 -0
- package/src/view/vendored/mermaid.min.js +2607 -0
- package/src/view-supervisor/index.js +26 -0
- package/src/view-supervisor/logs.js +32 -0
- package/src/view-supervisor/manifest-writer.js +178 -0
- package/src/view-supervisor/persist-until.js +85 -0
- package/src/view-supervisor/supervisor.js +276 -0
- 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
|
+
}
|