Build and publish 3D Architecture Wizzard documentation / build (pull_request) Failing after 11s
129 lines
5.8 KiB
JavaScript
129 lines
5.8 KiB
JavaScript
import {readFileSync, readdirSync, mkdirSync, writeFileSync, existsSync} from 'node:fs';
|
|
import {dirname, join} from 'node:path';
|
|
import process from 'node:process';
|
|
|
|
const root = process.cwd();
|
|
const sourceDir = join(root, 'data/scope/epics');
|
|
const check = process.argv.includes('--check');
|
|
const records = readdirSync(sourceDir)
|
|
.filter((name) => name.endsWith('.yml'))
|
|
.map((name) => JSON.parse(readFileSync(join(sourceDir, name), 'utf8')))
|
|
.sort((left, right) => Number(left.id.split('-').at(-1)) - Number(right.id.split('-').at(-1)));
|
|
|
|
if (records.length !== 10) throw new Error(`Expected 10 Epic records, found ${records.length}`);
|
|
const ids = new Set();
|
|
for (const epic of records) {
|
|
if (!/^3DARCH-EP-([1-9]|10)$/.test(epic.id)) throw new Error(`Invalid Epic ID: ${epic.id}`);
|
|
if (ids.has(epic.id)) throw new Error(`Duplicate Epic ID: ${epic.id}`);
|
|
ids.add(epic.id);
|
|
if (epic.type !== 'Epic' || epic.status !== 'IN_BACKLOG' || epic.status_source !== 'EXACT') throw new Error(`Invalid governed state: ${epic.id}`);
|
|
if (epic.approval?.approved_for_solution !== false) throw new Error(`Unexpected solution approval: ${epic.id}`);
|
|
if (!epic.catalogue_decision?.evidence_url || !epic.last_transition?.evidence_url) throw new Error(`Missing decision evidence: ${epic.id}`);
|
|
if (!Array.isArray(epic.legacy_evidence) || epic.legacy_evidence.length === 0) throw new Error(`Missing legacy evidence: ${epic.id}`);
|
|
}
|
|
|
|
const sourceList = (epic) => epic.sources.map((source) => `- [${source.label}](${source.url})`).join('\n');
|
|
const evidenceList = (epic) => epic.legacy_evidence.map((source) => `- [\`${source.path}\`](${source.url})`).join('\n');
|
|
const epicPage = (epic) => `---
|
|
title: "${epic.id} — ${epic.title}"
|
|
description: "Use this approved Epic boundary to assess related Features and outcomes."
|
|
---
|
|
|
|
# ${epic.title}
|
|
|
|
| Epic | Delivery status | Status source | Owner | Approved for Solution |
|
|
|---|---|---|---|---|
|
|
| \`${epic.id}\` | \`${epic.status}\` | \`${epic.status_source}\` | ${epic.owner} | No |
|
|
|
|
## Goal
|
|
|
|
${epic.goal}
|
|
|
|
## Benefit
|
|
|
|
${epic.value}
|
|
|
|
## Problem or opportunity
|
|
|
|
${epic.problem}
|
|
|
|
## Constraints
|
|
|
|
${epic.constraints.map((item) => `- ${item}`).join('\n')}
|
|
|
|
## Features
|
|
|
|
No child Features have been defined or approved. Feature discovery must preserve this Epic boundary and requires a separate human **Approved for Solution** decision before Architecture solution work begins.
|
|
|
|
## Original source
|
|
|
|
${sourceList(epic)}
|
|
|
|
### Legacy implementation evidence
|
|
|
|
The approved catalogue was mined from legacy revision \`${epic.legacy_revision}\`.
|
|
|
|
${evidenceList(epic)}
|
|
`;
|
|
|
|
const epicLinks = records.map((epic) => `- [${epic.id} — ${epic.title}](./${epic.id.toLowerCase()}.md)`).join('\n');
|
|
const epicIndex = `---
|
|
title: "Epics"
|
|
description: "Review the approved experience-led Epic catalogue mined from the legacy platform."
|
|
---
|
|
|
|
# Review the approved Epic catalogue
|
|
|
|
These ten Epics define the documented product boundary mined from materially implemented legacy behavior. \`3DARCH-EP-1\` owns the engineering foundation; every remaining Epic describes a user experience or usage outcome.
|
|
|
|
${epicLinks}
|
|
|
|
Planned-only capabilities—including VR entry, whiteboards, extra Archwiz domains, exports, and undo—remain outside this catalogue until separately evidenced and approved.
|
|
`;
|
|
|
|
const roadmapRows = records.map((epic) => `| [${epic.id}](./epics/${epic.id.toLowerCase()}.md) | ${epic.title} | \`${epic.status}\` | Current approved catalogue; no delivery forecast | ${epic.owner} | [2026-09-02 decision](${epic.catalogue_decision.evidence_url}) |`).join('\n');
|
|
const roadmap = `---
|
|
title: "Roadmap"
|
|
description: "Distinguish the approved Epic baseline from future sequencing and delivery forecasts."
|
|
---
|
|
|
|
# Review the product roadmap baseline
|
|
|
|
The current roadmap records the approved Epic catalogue without inventing sequence, dates, Feature scope, or delivery commitments. All Epics remain in \`IN_BACKLOG\`; future horizon and dependency decisions require separate evidence and human approval.
|
|
|
|
| Epic | Outcome area | Delivery status | Horizon | Owner | Last evidenced update |
|
|
|---|---|---|---|---|---|
|
|
${roadmapRows}
|
|
`;
|
|
|
|
const ts = `// Generated by scripts/generate-scope.mjs from data/scope/epics/*.yml. Do not edit.\nexport type ScopeIssue = {id:string; type:string; title:string; parent:string; status:string; statusSource:string; blocked:boolean; owner:string; approval:string; requiredChildren:string; dependencies:string; evidenceUrl:string; recordUrl:string};\nexport const scopeIssues: ScopeIssue[] = ${JSON.stringify(records.map((epic) => ({
|
|
id: epic.id, type: epic.type, title: epic.title, parent: '—', status: epic.status,
|
|
statusSource: epic.status_source, blocked: epic.blocked, owner: epic.owner,
|
|
approval: epic.approval.approved_for_solution ? 'Approved for Solution' : 'Not approved for Solution',
|
|
requiredChildren: epic.required_features.length ? epic.required_features.join(', ') : 'None defined',
|
|
dependencies: epic.dependencies.length ? epic.dependencies.join(', ') : 'None recorded',
|
|
evidenceUrl: epic.last_transition.evidence_url, recordUrl: `/scope/epics/${epic.id.toLowerCase()}/`,
|
|
})), null, 2)};\n`;
|
|
|
|
const expected = new Map([
|
|
[join(root, 'scope/epics/index.md'), epicIndex],
|
|
[join(root, 'scope/roadmap.md'), roadmap],
|
|
[join(root, 'src/data/scopeIssues.ts'), ts],
|
|
...records.map((epic) => [join(root, `scope/epics/${epic.id.toLowerCase()}.md`), epicPage(epic)]),
|
|
]);
|
|
|
|
let stale = false;
|
|
for (const [path, content] of expected) {
|
|
if (check) {
|
|
if (!existsSync(path) || readFileSync(path, 'utf8') !== content) {
|
|
console.error(`Stale generated artifact: ${path}`);
|
|
stale = true;
|
|
}
|
|
} else {
|
|
mkdirSync(dirname(path), {recursive: true});
|
|
writeFileSync(path, content);
|
|
}
|
|
}
|
|
if (stale) process.exit(1);
|
|
console.log(`${check ? 'Verified' : 'Generated'} ${expected.size} Scope artifacts from ${records.length} canonical Epics.`);
|