@sdd-method/author-cli 0.15.0 → 0.15.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.
@@ -90,7 +90,7 @@ export async function runCatalogueBuild(inputs, write) {
90
90
  const intendedRows = [];
91
91
  const rowsByCatalogue = modelFiles === null
92
92
  ? collected
93
- : overlayModel(schema, viewOf(modelFiles, modelProblems), collected, findings, intendedWrites(open, agreedOrder(open)), intendedRows);
93
+ : withC4Rollups(overlayModel(schema, viewOf(modelFiles, modelProblems), collected, findings, intendedWrites(open, agreedOrder(open)), intendedRows));
94
94
  for (const p of modelProblems)
95
95
  findings.add("convention", `${p} (M-ADR 0230)`);
96
96
  // 3a. Normalise every keyed catalogue to PK-unique rows. Multi-source edge
@@ -1517,6 +1517,18 @@ async function collectRows(schema, manifest, findings, sddPath, snapshotStore) {
1517
1517
  });
1518
1518
  return out;
1519
1519
  }
1520
+ /**
1521
+ * The C4 roll-ups joined again over the catalogues the structural model settles (M-ADR 0159 §4.8, M-ADR 0230 §4.3).
1522
+ * collectRows joins them over the sources, which can state an element an agreed open change adds; the overlay holds
1523
+ * that element back until the change archives, and a roll-up row reaching it would be a current row referencing it.
1524
+ */
1525
+ function withC4Rollups(rows) {
1526
+ const c4Containers = rows.get("c4_containers") ?? [];
1527
+ const containerEntityRows = buildC4ContainerEntity({ serviceEntityRows: rows.get("service_entity") ?? [], c4Containers });
1528
+ rows.set("c4_container_entity", containerEntityRows);
1529
+ rows.set("c4_system_entity", buildC4SystemEntity({ containerEntityRows, c4Containers }));
1530
+ return rows;
1531
+ }
1520
1532
  const CONTEXT_CROSS_CUTTING = "cross-cutting";
1521
1533
  /**
1522
1534
  * Convention check (schema 2.21.0): where a screen carries `context` and the
@@ -86,6 +86,8 @@ const COMMIT_RE = /^[0-9a-f]{7,40}$/;
86
86
  // OpenSpec counts a task done when its box holds only `x`, either case, any spacing.
87
87
  const TASK_DONE_RE = /^\s*-\s*\[\s*[xX]\s*\]/m;
88
88
  const TARGET_HEADING_RE = /^##\s+(MODIFIED|REMOVED|RENAMED)\s+Requirements\b/m;
89
+ // A tasks.md group headed by one word, `## <n>. <word>`, is that repository's work order (taskGroups).
90
+ const GROUP_REPO = (repo) => `tasks.md has a work order for ${repo} and the record's work_orders do not; its evidence cannot be checked (a group heading of one word, \`## <n>. ${repo}\`, names the group's repository)`;
89
91
  async function exists(p) {
90
92
  try {
91
93
  await access(p);
@@ -516,6 +518,14 @@ export async function checkBehaviourStore(repo, options = {}) {
516
518
  }
517
519
  }
518
520
  }
521
+ // The archive check reads a task group's repository from its heading; once the record declares work orders, a
522
+ // heading it would read as a repository the record lacks fails here, while the change can still be amended.
523
+ if (versionAtLeast(record?.schemaVersion, "1.1.0") && record?.status === "agreed" && record.workOrders.length > 0 && tasks !== null) {
524
+ const recorded = new Set(record.workOrders.map((w) => w.repo));
525
+ for (const g of taskGroups(tasks))
526
+ if (!recorded.has(g.repo))
527
+ failures.push(`${record.file}: ${GROUP_REPO(g.repo)}`);
528
+ }
519
529
  // A test plan's kinds (M-ADR 0223 §4.4 as amended): changed and repaired scenarios go red then green, carried ones stay green.
520
530
  if (versionAtLeast(record?.schemaVersion, "1.1.0") && record?.status === "agreed") {
521
531
  const plan = await readText(join(repo, dir, "test-plan.md"));
@@ -717,7 +727,7 @@ export async function checkBehaviourStore(repo, options = {}) {
717
727
  const recorded = new Set(record.workOrders.map((w) => w.repo));
718
728
  for (const g of groups)
719
729
  if (!recorded.has(g.repo))
720
- failures.push(`${record.file}: tasks.md has a work order for ${g.repo} and the record's work_orders do not; its evidence cannot be checked`);
730
+ failures.push(`${record.file}: ${GROUP_REPO(g.repo)}`);
721
731
  // Requirement names are unique within a feature, not across a change: a work order names `<feature>::<name>`,
722
732
  // or a bare name only one feature in the change has (schema 5.0.0). An ambiguous bare name implements nothing.
723
733
  const built = [];
@@ -1,4 +1,4 @@
1
1
  {
2
- "version": "0.16.0",
3
- "built_against_sdd_cli": "5.2.0"
2
+ "version": "0.16.1",
3
+ "built_against_sdd_cli": "5.2.1"
4
4
  }
@@ -1,4 +1,4 @@
1
1
  {
2
- "version": "5.2.0",
3
- "built_against_sdd_cli": "5.2.0"
2
+ "version": "5.2.1",
3
+ "built_against_sdd_cli": "5.2.1"
4
4
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@sdd-method/author-cli",
3
- "version": "0.15.0",
4
- "sddCliVersion": "5.2.0",
3
+ "version": "0.15.1",
4
+ "sddCliVersion": "5.2.1",
5
5
  "description": "Re-author one SDD's content — scaffold, plan, contracts, conformance, api-surface, snapshots, briefings, catalogue check — plus every read-only verify verb. Ships only the code those verbs reach; it cannot sync the baseline or rebuild the catalogues. Maintenance is in @sdd-method/maintain-cli, administration in @sdd-method/sdd-cli.",
6
6
  "license": "UNLICENSED",
7
7
  "type": "module",