@sdd-method/author-cli 0.7.0 → 0.9.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.
- package/dist/author-program.js +2 -1
- package/dist/lib/agent-harness.js +2 -2
- package/dist/lib/behaviour-store/archive.js +28 -1
- package/dist/lib/behaviour-store/schema.js +85 -0
- package/dist/lib/briefing/index.js +1 -1
- package/dist/lib/briefing/render.js +1 -1
- package/dist/lib/briefing/variables.js +1 -1
- package/dist/lib/catalogue/application-archetype/vocabulary.js +2 -2
- package/dist/lib/catalogue/archetype/maps/android.yaml +2 -2
- package/dist/lib/catalogue/archetype/maps/swiftui.yaml +2 -2
- package/dist/lib/catalogue/archetype/maps/uikit.yaml +2 -2
- package/dist/lib/catalogue/archetype/maps/web-generic.yaml +2 -2
- package/dist/lib/catalogue/archetype/openui-archetype-vocabulary.yaml +3 -3
- package/dist/lib/catalogue/archetype/resolver.js +4 -4
- package/dist/lib/catalogue/archetype/wireframe.js +1 -1
- package/dist/lib/catalogue/build.js +36 -33
- package/dist/lib/catalogue/builders/adr-supersedes.js +3 -3
- package/dist/lib/catalogue/builders/adrs.js +3 -3
- package/dist/lib/catalogue/builders/c4-containers.js +2 -2
- package/dist/lib/catalogue/builders/c4-entity-rollups.js +1 -1
- package/dist/lib/catalogue/builders/c4-external-systems.js +2 -2
- package/dist/lib/catalogue/builders/c4-systems.js +1 -1
- package/dist/lib/catalogue/builders/capabilities.js +1 -1
- package/dist/lib/catalogue/builders/capability-domain-model.js +1 -1
- package/dist/lib/catalogue/builders/capability-spec-walker.js +2 -2
- package/dist/lib/catalogue/builders/capability-spec.js +4 -4
- package/dist/lib/catalogue/builders/contracts.js +3 -3
- package/dist/lib/catalogue/builders/data-store-mapping.js +2 -2
- package/dist/lib/catalogue/builders/domain-models.js +2 -2
- package/dist/lib/catalogue/builders/domains.js +3 -3
- package/dist/lib/catalogue/builders/entities-manifest.js +8 -8
- package/dist/lib/catalogue/builders/entities-mermaid.js +4 -4
- package/dist/lib/catalogue/builders/entity-persistence.js +1 -1
- package/dist/lib/catalogue/builders/entity-slug.js +3 -3
- package/dist/lib/catalogue/builders/event-catalog-walker.js +6 -6
- package/dist/lib/catalogue/builders/event-edges.js +6 -6
- package/dist/lib/catalogue/builders/events.js +3 -3
- package/dist/lib/catalogue/builders/evidence-class.js +1 -1
- package/dist/lib/catalogue/builders/feature-domain-model.js +1 -1
- package/dist/lib/catalogue/builders/feature-grounding-walker.js +2 -2
- package/dist/lib/catalogue/builders/feature-grounding.js +5 -5
- package/dist/lib/catalogue/builders/feature-subscription-channels.js +3 -3
- package/dist/lib/catalogue/builders/features.js +1 -1
- package/dist/lib/catalogue/builders/glossary-xref.js +4 -4
- package/dist/lib/catalogue/builders/integrations.js +4 -4
- package/dist/lib/catalogue/builders/persona-c4system.js +1 -1
- package/dist/lib/catalogue/builders/product-edges.js +1 -1
- package/dist/lib/catalogue/builders/product-platform-dependencies.js +2 -2
- package/dist/lib/catalogue/builders/products.js +5 -5
- package/dist/lib/catalogue/builders/repo-edges.js +12 -12
- package/dist/lib/catalogue/builders/repositories.js +11 -7
- package/dist/lib/catalogue/builders/requirements.js +110 -11
- package/dist/lib/catalogue/builders/screen-tree.js +6 -6
- package/dist/lib/catalogue/builders/screens.js +18 -18
- package/dist/lib/catalogue/builders/service-contract-consumes.js +1 -1
- package/dist/lib/catalogue/builders/service-entity-tables.js +3 -3
- package/dist/lib/catalogue/builders/services.js +5 -5
- package/dist/lib/catalogue/builders/system-external-dependency.js +2 -2
- package/dist/lib/catalogue/canonical-schema.yaml +138 -2
- package/dist/lib/catalogue/coverage-render.js +15 -15
- package/dist/lib/catalogue/csv-writer.js +1 -1
- package/dist/lib/catalogue/feature-grounding-aliases-loader.js +1 -1
- package/dist/lib/catalogue/findings.js +1 -1
- package/dist/lib/catalogue/fk-validator.js +2 -2
- package/dist/lib/catalogue/manifest-loader.js +3 -3
- package/dist/lib/catalogue/rubric-coverage-map.yaml +28 -0
- package/dist/lib/catalogue/schema-compat.js +2 -2
- package/dist/lib/catalogue/schema-loader.js +1 -1
- package/dist/lib/catalogue/screen-validation-loader.js +2 -2
- package/dist/lib/catalogue/service-architecture-parser.js +1 -1
- package/dist/lib/catalogue/traceability-loader.js +6 -4
- package/dist/lib/conformance/finding.js +1 -1
- package/dist/lib/conformance/index.js +5 -5
- package/dist/lib/generate-briefing/index.js +2 -2
- package/dist/lib/metamodel/tql-subset-parser.js +280 -0
- package/dist/lib/pack/schema.js +2 -2
- package/dist/lib/pack/seed.js +2 -2
- package/dist/lib/pack/validate.js +1 -1
- package/dist/lib/plan/read-sdd.js +1 -1
- package/dist/lib/repo-kind.js +4 -12
- package/dist/lib/scaffold/archetype-behaviour.js +173 -0
- package/dist/lib/scaffold/behaviour-store.js +60 -0
- package/dist/lib/scaffold/domain.js +24 -6
- package/dist/lib/scaffold/registry.js +1 -1
- package/dist/lib/sync/briefing-merge.js +2 -2
- package/dist/lib/sync/bundle-cache.js +4 -4
- package/dist/lib/sync/yaml-block-merge.js +1 -1
- package/dist/lib/validate/archetype-citations.js +169 -0
- package/dist/lib/validate/behaviour-store.js +161 -6
- package/dist/lib/validate/dispatch.js +8 -1
- package/dist/maintain-version.json +2 -2
- package/dist/verbs/conformance.js +3 -3
- package/dist/verbs/list.js +1 -1
- package/dist/verbs/render.js +1 -1
- package/dist/verbs/scaffold.js +36 -4
- package/dist/verify-program.js +2 -2
- package/dist/verify-version.json +2 -2
- package/package.json +2 -2
- package/scripts/validate-app-dependencies.sh +1 -1
- package/scripts/validate-integration-docs.sh +1 -1
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
// 0197 §4.1 — a dangling reference to it resolves to an orphan finding
|
|
11
11
|
// elsewhere, not a crash here).
|
|
12
12
|
//
|
|
13
|
-
// Per ADR 0134 + Q7.1 resolution, runtime kinds are
|
|
13
|
+
// Per M-ADR 0134 + Q7.1 resolution, runtime kinds are
|
|
14
14
|
// {api_service, worker, gateway, frontend, mobile} — read from the
|
|
15
15
|
// canonical schema's enums.service_type block where
|
|
16
16
|
// `emits_service_row: true`. The runtime-kind gate applies only to the
|
|
@@ -29,13 +29,13 @@
|
|
|
29
29
|
// service-architecture-parser module.
|
|
30
30
|
//
|
|
31
31
|
// The `description` column has two authoring sources, honoured per the
|
|
32
|
-
// forward/reverse parity principle (ADR 0157, extended to node columns by
|
|
33
|
-
// ADR 0163):
|
|
32
|
+
// forward/reverse parity principle (M-ADR 0157, extended to node columns by
|
|
33
|
+
// M-ADR 0163):
|
|
34
34
|
// - forward: `orchestration/repo-config/<repo>.yaml` `description:` —
|
|
35
35
|
// the deliberate spec, authored by forward-method adopters.
|
|
36
36
|
// - reverse: the arch doc's `## Purpose` lead paragraph.
|
|
37
37
|
// When both are present for the same service the forward repo-config
|
|
38
|
-
// description wins (matching the ADR 0156 / 0162 merge convention) and a
|
|
38
|
+
// description wins (matching the M-ADR 0156 / 0162 merge convention) and a
|
|
39
39
|
// `divergence` finding records the conflict. In practice an adopter has
|
|
40
40
|
// only one of the two, so this is usually a plain coalesce.
|
|
41
41
|
//
|
|
@@ -111,7 +111,7 @@ export async function buildServices(inputs) {
|
|
|
111
111
|
// repos/<group>/<repo>/docs/..., so a recursive walk is required.
|
|
112
112
|
// Services whose architecture doc lives in a federated member SDD (rather
|
|
113
113
|
// than this SDD's own repos/) resolve to no entry here — their metadata is
|
|
114
|
-
// an aggregation-time concern (ADR 0163 P2), not a local build gap.
|
|
114
|
+
// an aggregation-time concern (M-ADR 0163 P2), not a local build gap.
|
|
115
115
|
const archIndex = await indexServiceArchitectures(inputs.sddPath);
|
|
116
116
|
const repoDescriptions = inputs.repoDescriptions ?? new Map();
|
|
117
117
|
const declaredByRepo = inputs.declaredServicesByRepo ?? new Map();
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
// system_external_dependency edge builder — emits one row per
|
|
2
2
|
// `Rel(...)` line on an L1/L2 diagram that connects the SDD's own system
|
|
3
|
-
// (or one of its containers) to an external system (per ADR 0155).
|
|
3
|
+
// (or one of its containers) to an external system (per M-ADR 0155).
|
|
4
4
|
//
|
|
5
5
|
// Resolution: the c4-external-systems builder supplies `externalIdByEntryId`
|
|
6
6
|
// (diagram entry-id → ext-... row id). For each `Rel(a, b, "label")` where
|
|
7
7
|
// exactly one endpoint is a known external entry-id, we emit an edge from
|
|
8
8
|
// the SDD's c4_systems row to that external system. Container-level external
|
|
9
|
-
// dependencies are intentionally collapsed to the system level — ADR 0155
|
|
9
|
+
// dependencies are intentionally collapsed to the system level — M-ADR 0155
|
|
10
10
|
// §4.2 keeps the edge system-scoped.
|
|
11
11
|
import { readFile } from "node:fs/promises";
|
|
12
12
|
import { collectC4DiagramFiles } from "./c4-external-systems.js";
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
# Emitted by sdd-cli's YAML emitter with no line folding; the three header scalars are quoted for the
|
|
8
8
|
# textual readers downstream. The one deliberate difference from the authored form is schema_status:
|
|
9
9
|
# the authored form says canonical; a projection never does.
|
|
10
|
-
schema_version: "4.
|
|
10
|
+
schema_version: "4.2.0"
|
|
11
11
|
schema_owner: "sdd-method"
|
|
12
12
|
schema_status: "generated"
|
|
13
13
|
enums:
|
|
@@ -643,6 +643,31 @@ enums:
|
|
|
643
643
|
- value: observed
|
|
644
644
|
description: Independent evidence from this repository's code matches (a baseline's characterization tests or a reverse snapshot).
|
|
645
645
|
description: A requirement's status in one implementing repository (M-ADR 0221 §4.5).
|
|
646
|
+
change_status:
|
|
647
|
+
values:
|
|
648
|
+
- value: proposed
|
|
649
|
+
description: Open, with a proposed agreement record or none yet.
|
|
650
|
+
- value: agreed
|
|
651
|
+
description: "Open, with an agreed record: being built."
|
|
652
|
+
- value: superseded
|
|
653
|
+
description: Open, its record superseded by another change.
|
|
654
|
+
- value: withdrawn
|
|
655
|
+
description: Open, its record withdrawn.
|
|
656
|
+
- value: archived
|
|
657
|
+
description: Archived into the living specs.
|
|
658
|
+
description: Where a change stands (M-ADR 0222 §4.6, M-ADR 0223 §4.6).
|
|
659
|
+
judge_verdict:
|
|
660
|
+
values:
|
|
661
|
+
- value: PASS
|
|
662
|
+
- value: FAIL
|
|
663
|
+
description: The judge's verdict on a change (M-ADR 0223 §4.5).
|
|
664
|
+
work_order_status:
|
|
665
|
+
values:
|
|
666
|
+
- value: agreed
|
|
667
|
+
description: Agreed; the repository's work is not yet judged.
|
|
668
|
+
- value: completed
|
|
669
|
+
description: Marked completed by a passing judge.
|
|
670
|
+
description: A work order's status in its change's agreement record (M-ADR 0223 §4.2, §4.6).
|
|
646
671
|
catalogues:
|
|
647
672
|
domains:
|
|
648
673
|
primary_key: id
|
|
@@ -4200,7 +4225,7 @@ catalogues:
|
|
|
4200
4225
|
- name: change_id
|
|
4201
4226
|
type: string
|
|
4202
4227
|
nullable: false
|
|
4203
|
-
description: The archived change's directory name (its archive date prefix included).
|
|
4228
|
+
description: The archived change's directory name (its archive date prefix included); a changes.id.
|
|
4204
4229
|
- name: change_kind
|
|
4205
4230
|
type: string
|
|
4206
4231
|
nullable: false
|
|
@@ -4226,6 +4251,9 @@ catalogues:
|
|
|
4226
4251
|
- column: requirement_id
|
|
4227
4252
|
references: requirements.id
|
|
4228
4253
|
nullable: false
|
|
4254
|
+
- column: change_id
|
|
4255
|
+
references: changes.id
|
|
4256
|
+
nullable: false
|
|
4229
4257
|
column_enums:
|
|
4230
4258
|
change_kind: enums.requirement_change_kind
|
|
4231
4259
|
operation: enums.requirement_operation
|
|
@@ -4269,3 +4297,111 @@ catalogues:
|
|
|
4269
4297
|
nullable: false
|
|
4270
4298
|
column_enums:
|
|
4271
4299
|
status: enums.requirement_status_value
|
|
4300
|
+
changes:
|
|
4301
|
+
primary_key: id
|
|
4302
|
+
columns:
|
|
4303
|
+
- name: id
|
|
4304
|
+
type: string
|
|
4305
|
+
nullable: false
|
|
4306
|
+
description: "The change's directory name: the open change's name, or the archived change's directory (its archive date prefix included). requirement_lineage.change_id references it."
|
|
4307
|
+
- name: name
|
|
4308
|
+
type: string
|
|
4309
|
+
nullable: false
|
|
4310
|
+
description: "The change's name without the archive date prefix: the same before and after archive, so a work item that cites the change keeps its link."
|
|
4311
|
+
- name: change_kind
|
|
4312
|
+
type: string
|
|
4313
|
+
nullable: false
|
|
4314
|
+
description: "Bound to requirement_change_kind: baseline (it carries baseline-evidence.md) or change."
|
|
4315
|
+
- name: status
|
|
4316
|
+
type: string
|
|
4317
|
+
nullable: false
|
|
4318
|
+
description: "Bound to change_status: archived for an archived change; otherwise the agreement record's status, or proposed when there is no record yet."
|
|
4319
|
+
- name: archived_on
|
|
4320
|
+
type: string
|
|
4321
|
+
nullable: true
|
|
4322
|
+
description: The archive date (YYYY-MM-DD) from the archived change's directory name; empty for an open change.
|
|
4323
|
+
- name: verdict
|
|
4324
|
+
type: string
|
|
4325
|
+
nullable: true
|
|
4326
|
+
description: "Bound to judge_verdict: the agreement record's verdict result (M-ADR 0223 §4.6). Empty for a baseline, and for a change not yet judged."
|
|
4327
|
+
- name: source_sdd_id
|
|
4328
|
+
type: string
|
|
4329
|
+
nullable: true
|
|
4330
|
+
description: Originating SDD (stamped at aggregation; empty in a per-SDD build).
|
|
4331
|
+
- name: platform_sdd_id
|
|
4332
|
+
type: string
|
|
4333
|
+
nullable: true
|
|
4334
|
+
description: The platform SDD the row belongs to (stamped at aggregation).
|
|
4335
|
+
description: "A change in the SDD's behaviour store (M-ADR 0223 §4.2), open or archived, including baseline changes. Derived, never authored: from the store's change directories and their agreement records (M-ADR 0222 §4.6)."
|
|
4336
|
+
column_enums:
|
|
4337
|
+
change_kind: enums.requirement_change_kind
|
|
4338
|
+
status: enums.change_status
|
|
4339
|
+
verdict: enums.judge_verdict
|
|
4340
|
+
change_work_order:
|
|
4341
|
+
primary_key: id
|
|
4342
|
+
columns:
|
|
4343
|
+
- name: id
|
|
4344
|
+
type: string
|
|
4345
|
+
nullable: false
|
|
4346
|
+
description: <change_id>__<repo_id>.
|
|
4347
|
+
- name: change_id
|
|
4348
|
+
type: string
|
|
4349
|
+
nullable: false
|
|
4350
|
+
- name: repo_id
|
|
4351
|
+
type: string
|
|
4352
|
+
nullable: false
|
|
4353
|
+
description: The repository the work order is for.
|
|
4354
|
+
- name: status
|
|
4355
|
+
type: string
|
|
4356
|
+
nullable: false
|
|
4357
|
+
description: "Bound to work_order_status: the record's status for the work order; a judge PASS marks it completed (M-ADR 0223 §4.6)."
|
|
4358
|
+
- name: source_sdd_id
|
|
4359
|
+
type: string
|
|
4360
|
+
nullable: true
|
|
4361
|
+
description: Originating SDD (stamped at aggregation; empty in a per-SDD build).
|
|
4362
|
+
- name: platform_sdd_id
|
|
4363
|
+
type: string
|
|
4364
|
+
nullable: true
|
|
4365
|
+
description: The platform SDD the row belongs to (stamped at aggregation).
|
|
4366
|
+
description: "Edge: a change's work order for one implementing repository (M-ADR 0223 §4.2), from the change's agreement record. Derived, never authored."
|
|
4367
|
+
foreign_keys:
|
|
4368
|
+
- column: change_id
|
|
4369
|
+
references: changes.id
|
|
4370
|
+
nullable: false
|
|
4371
|
+
- column: repo_id
|
|
4372
|
+
references: repositories.id
|
|
4373
|
+
nullable: false
|
|
4374
|
+
column_enums:
|
|
4375
|
+
status: enums.work_order_status
|
|
4376
|
+
change_work_item:
|
|
4377
|
+
primary_key: id
|
|
4378
|
+
columns:
|
|
4379
|
+
- name: id
|
|
4380
|
+
type: string
|
|
4381
|
+
nullable: false
|
|
4382
|
+
description: "<change_name>__<work_item_id>: keyed by the change's undated name, so the row is the same before and after archive."
|
|
4383
|
+
- name: change_id
|
|
4384
|
+
type: string
|
|
4385
|
+
nullable: false
|
|
4386
|
+
description: "The change as it stands now: its open name, or its archive directory."
|
|
4387
|
+
- name: change_name
|
|
4388
|
+
type: string
|
|
4389
|
+
nullable: false
|
|
4390
|
+
description: The change's undated name.
|
|
4391
|
+
- name: work_item_id
|
|
4392
|
+
type: string
|
|
4393
|
+
nullable: false
|
|
4394
|
+
description: The work item's id in the adopter's work-item tool, as the proposal's Work Items section gives it.
|
|
4395
|
+
- name: source_sdd_id
|
|
4396
|
+
type: string
|
|
4397
|
+
nullable: true
|
|
4398
|
+
description: Originating SDD (stamped at aggregation; empty in a per-SDD build).
|
|
4399
|
+
- name: platform_sdd_id
|
|
4400
|
+
type: string
|
|
4401
|
+
nullable: true
|
|
4402
|
+
description: The platform SDD the row belongs to (stamped at aggregation).
|
|
4403
|
+
description: "Annotation: a work item a change's proposal says it delivers (M-ADR 0223 §4.2), giving the roll-up from work item to changes to requirements. The work item's id is the adopter's work-item tool's (M-ADR 0035), so it has no foreign key."
|
|
4404
|
+
foreign_keys:
|
|
4405
|
+
- column: change_id
|
|
4406
|
+
references: changes.id
|
|
4407
|
+
nullable: false
|
|
@@ -281,47 +281,47 @@ export function renderContractCoverage(res, tier) {
|
|
|
281
281
|
}
|
|
282
282
|
// ─── the nine Phase-0 gate checks ────────────────────────────────────────
|
|
283
283
|
export function renderEventCatalogueCheck(gaps) {
|
|
284
|
-
return gaps.map((g) => `[finding] coverage: domain ${g.domain} event-catalog.yaml declares ${g.declared} events but events.csv contains ${g.emitted} rows for that domain (per ADR 0156 Phase 0)`);
|
|
284
|
+
return gaps.map((g) => `[finding] coverage: domain ${g.domain} event-catalog.yaml declares ${g.declared} events but events.csv contains ${g.emitted} rows for that domain (per M-ADR 0156 Phase 0)`);
|
|
285
285
|
}
|
|
286
286
|
export function renderRepoEdgesCheck(res) {
|
|
287
287
|
const lines = [];
|
|
288
288
|
if (res.repoCapabilityGap) {
|
|
289
289
|
const g = res.repoCapabilityGap;
|
|
290
|
-
lines.push(`[finding] coverage: repo_capability.csv is empty but ${g.capabilityService} capability_service rows + ${g.servicesWithRepo} services with primary_repo_id present — reverse-method derivation likely missing (per ADR 0157 §4.3, Phase 0)`);
|
|
290
|
+
lines.push(`[finding] coverage: repo_capability.csv is empty but ${g.capabilityService} capability_service rows + ${g.servicesWithRepo} services with primary_repo_id present — reverse-method derivation likely missing (per M-ADR 0157 §4.3, Phase 0)`);
|
|
291
291
|
}
|
|
292
292
|
if (res.repoContractForwardGap) {
|
|
293
293
|
const g = res.repoContractForwardGap;
|
|
294
|
-
lines.push(`[finding] coverage: repo_contract.csv is empty but ${g.contracts} contracts and ${g.repoConfigsWithContracts} repo-configs with contracts: blocks present — forward-method derivation likely missing (per ADR 0157 §4.2, Phase 0)`);
|
|
294
|
+
lines.push(`[finding] coverage: repo_contract.csv is empty but ${g.contracts} contracts and ${g.repoConfigsWithContracts} repo-configs with contracts: blocks present — forward-method derivation likely missing (per M-ADR 0157 §4.2, Phase 0)`);
|
|
295
295
|
}
|
|
296
296
|
if (res.repoContractPathXGap) {
|
|
297
297
|
const g = res.repoContractPathXGap;
|
|
298
|
-
lines.push(`[finding] coverage: repo_contract.csv is empty but ${g.serviceContracts} service_contract rows + ${g.servicesWithRepo} services with primary_repo_id present — reverse-method Path X (service_contract ⋈ services.primary_repo_id) derivation likely missing (per ADR 0157 §4.2, Phase 0)`);
|
|
298
|
+
lines.push(`[finding] coverage: repo_contract.csv is empty but ${g.serviceContracts} service_contract rows + ${g.servicesWithRepo} services with primary_repo_id present — reverse-method Path X (service_contract ⋈ services.primary_repo_id) derivation likely missing (per M-ADR 0157 §4.2, Phase 0)`);
|
|
299
299
|
}
|
|
300
300
|
if (res.repoContractReverseGap) {
|
|
301
301
|
const g = res.repoContractReverseGap;
|
|
302
|
-
lines.push(`[finding] coverage: repo_contract.csv is empty with ${g.contracts} contracts present and no repo-config.contracts: blocks or service_contract rows — reverse-method derivation via contracts.source_repo_id likely missing (per ADR 0157 §4.2, Phase 0)`);
|
|
302
|
+
lines.push(`[finding] coverage: repo_contract.csv is empty with ${g.contracts} contracts present and no repo-config.contracts: blocks or service_contract rows — reverse-method derivation via contracts.source_repo_id likely missing (per M-ADR 0157 §4.2, Phase 0)`);
|
|
303
303
|
}
|
|
304
304
|
return lines;
|
|
305
305
|
}
|
|
306
306
|
export function renderGlossaryXrefCheck(finding) {
|
|
307
307
|
return finding
|
|
308
308
|
? [
|
|
309
|
-
`[finding] coverage: docs/platform/reference/glossary-alignment-manifest.yaml exists but glossary_xref.csv emits 0 rows — multi-source derivation likely missing (per ADR 0158 §4.5, Phase 0)`,
|
|
309
|
+
`[finding] coverage: docs/platform/reference/glossary-alignment-manifest.yaml exists but glossary_xref.csv emits 0 rows — multi-source derivation likely missing (per M-ADR 0158 §4.5, Phase 0)`,
|
|
310
310
|
]
|
|
311
311
|
: [];
|
|
312
312
|
}
|
|
313
313
|
export function renderDataModelEntitiesCheck(res) {
|
|
314
314
|
const lines = [];
|
|
315
315
|
if (res.entitiesGap) {
|
|
316
|
-
lines.push(`[finding] coverage: ${res.entitiesGap.domainModels} domain-model files catalogued but entities.csv emits 0 rows — reverse-method entity extraction missing (per ADR 0159 Phase 0)`);
|
|
316
|
+
lines.push(`[finding] coverage: ${res.entitiesGap.domainModels} domain-model files catalogued but entities.csv emits 0 rows — reverse-method entity extraction missing (per M-ADR 0159 Phase 0)`);
|
|
317
317
|
}
|
|
318
318
|
if (res.serviceEntityGap) {
|
|
319
319
|
const g = res.serviceEntityGap;
|
|
320
|
-
lines.push(`[finding] coverage: ${g.entities} entities + ${g.services} services catalogued but service_entity.csv emits 0 rows — Data Store Mapping ingestion missing (per ADR 0159 Phase 0)`);
|
|
320
|
+
lines.push(`[finding] coverage: ${g.entities} entities + ${g.services} services catalogued but service_entity.csv emits 0 rows — Data Store Mapping ingestion missing (per M-ADR 0159 Phase 0)`);
|
|
321
321
|
}
|
|
322
322
|
if (res.containerEntityGap) {
|
|
323
323
|
const g = res.containerEntityGap;
|
|
324
|
-
lines.push(`[finding] coverage: ${g.containersWithService} containers map to services + ${g.serviceEntity} service_entity edges present but c4_container_entity.csv emits 0 rows — Phase 3 derivation missing (per ADR 0159 Phase 0)`);
|
|
324
|
+
lines.push(`[finding] coverage: ${g.containersWithService} containers map to services + ${g.serviceEntity} service_entity edges present but c4_container_entity.csv emits 0 rows — Phase 3 derivation missing (per M-ADR 0159 Phase 0)`);
|
|
325
325
|
}
|
|
326
326
|
return lines;
|
|
327
327
|
}
|
|
@@ -329,24 +329,24 @@ export function renderCapabilityEventCheck(res) {
|
|
|
329
329
|
const lines = [];
|
|
330
330
|
if (res.derivableGap) {
|
|
331
331
|
const g = res.derivableGap;
|
|
332
|
-
lines.push(`[finding] coverage: service_event (${g.serviceEvent}) + capability_service (${g.capabilityService}) populated but capability_event emits 0 rows — reverse-derivable edge missing (per ADR 0160 Phase 0)`);
|
|
332
|
+
lines.push(`[finding] coverage: service_event (${g.serviceEvent}) + capability_service (${g.capabilityService}) populated but capability_event emits 0 rows — reverse-derivable edge missing (per M-ADR 0160 Phase 0)`);
|
|
333
333
|
}
|
|
334
334
|
if (res.authoredGap) {
|
|
335
|
-
lines.push(`[finding] coverage: capability_event has ${res.authoredGap.derived} derived rows but 0 authored rows — no traceability.events[] or traceability.contracts.{published,consumed}_events declarations are landing in the catalogue. Governance queries filtering to source=authored will return empty (per ADR 0160 Phase 0)`);
|
|
335
|
+
lines.push(`[finding] coverage: capability_event has ${res.authoredGap.derived} derived rows but 0 authored rows — no traceability.events[] or traceability.contracts.{published,consumed}_events declarations are landing in the catalogue. Governance queries filtering to source=authored will return empty (per M-ADR 0160 Phase 0)`);
|
|
336
336
|
}
|
|
337
337
|
return lines;
|
|
338
338
|
}
|
|
339
339
|
export function renderFeatureEventCheck(res) {
|
|
340
340
|
return res.gap
|
|
341
341
|
? [
|
|
342
|
-
`[finding] coverage: service_event (${res.gap.serviceEvent}) + feature_service (${res.gap.featureService}) populated but feature_event emits 0 rows — reverse-derivable edge missing (per ADR 0161 Phase 0)`,
|
|
342
|
+
`[finding] coverage: service_event (${res.gap.serviceEvent}) + feature_service (${res.gap.featureService}) populated but feature_event emits 0 rows — reverse-derivable edge missing (per M-ADR 0161 Phase 0)`,
|
|
343
343
|
]
|
|
344
344
|
: [];
|
|
345
345
|
}
|
|
346
346
|
export function renderPlatformDependenciesCheck(finding) {
|
|
347
347
|
return finding
|
|
348
348
|
? [
|
|
349
|
-
`[finding] coverage: app-platform-dependencies.yaml declares a platform_dependencies block but product_platform_dependencies.csv emits 0 rows — forward-method ingestion missing (per ADR 0162 Phase 0). Resolves once the builder reads the forward source.`,
|
|
349
|
+
`[finding] coverage: app-platform-dependencies.yaml declares a platform_dependencies block but product_platform_dependencies.csv emits 0 rows — forward-method ingestion missing (per M-ADR 0162 Phase 0). Resolves once the builder reads the forward source.`,
|
|
350
350
|
]
|
|
351
351
|
: [];
|
|
352
352
|
}
|
|
@@ -358,7 +358,7 @@ export function renderFeatureSpecPromotionCheck(res) {
|
|
|
358
358
|
`[finding] coverage: ${f.intermediate} of ${f.total} features are reverse-intermediate ` +
|
|
359
359
|
`(capability-spec/feature-grounding) not yet promoted to feature-spec — ` +
|
|
360
360
|
`unresolvable as realises:/FK targets (${f.pctResolvable}% resolvable, ${f.note}; ` +
|
|
361
|
-
`per ADR 0177 §4.2)`,
|
|
361
|
+
`per M-ADR 0177 §4.2)`,
|
|
362
362
|
];
|
|
363
363
|
}
|
|
364
364
|
export function renderFeatureSurfaceDuplicationCheck(res) {
|
|
@@ -370,7 +370,7 @@ export function renderFeatureSurfaceDuplicationCheck(res) {
|
|
|
370
370
|
`[finding] coverage: ${f.pairs} near-duplicate feature surface(s) across ` +
|
|
371
371
|
`${f.capabilities} ${capWord} — a capability-spec (rollup) and feature-grounding ` +
|
|
372
372
|
`(detailed) slug naming the same surface; reconcile to one slug per surface, ` +
|
|
373
|
-
`detailed slug canonical (per ADR 0177 §4.3)`,
|
|
373
|
+
`detailed slug canonical (per M-ADR 0177 §4.3)`,
|
|
374
374
|
];
|
|
375
375
|
}
|
|
376
376
|
// ─── Scores coverage (M-ADR 0205 §4.5, B2 — the fourteenth check) ─────────
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Deterministic CSV writer for catalogues.
|
|
3
3
|
*
|
|
4
|
-
* Emits headers + sorted rows per ADR 0134 builder contract:
|
|
4
|
+
* Emits headers + sorted rows per M-ADR 0134 builder contract:
|
|
5
5
|
* - column order matches the canonical schema exactly,
|
|
6
6
|
* - rows sorted by primary-key value,
|
|
7
7
|
* - cells with embedded comma/quote/newline are RFC-4180 quoted,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Loader for the optional `.sdd/feature-grounding-aliases.yaml` config
|
|
3
|
-
* per ADR 0143 (schema 2.5.0).
|
|
3
|
+
* per M-ADR 0143 (schema 2.5.0).
|
|
4
4
|
*
|
|
5
5
|
* Adopters use this map to translate display names in
|
|
6
6
|
* `feature-grounding.md` tables (class names, file basenames, route
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Findings collector for the canonical builder per ADR 0134 / builder-spec
|
|
2
|
+
* Findings collector for the canonical builder per M-ADR 0134 / builder-spec
|
|
3
3
|
* §"Emit findings as it parses".
|
|
4
4
|
*
|
|
5
5
|
* Findings are human-readable AND machine-parseable. Format per finding:
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* FK validator per ADR 0134 builder-spec §"Run internal FK validation
|
|
2
|
+
* FK validator per M-ADR 0134 builder-spec §"Run internal FK validation
|
|
3
3
|
* before exiting" + §"External FK handling".
|
|
4
4
|
*
|
|
5
5
|
* For each catalogue's foreign keys:
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* - External FKs (external=true, or external for the build's profile via
|
|
10
10
|
* `externalForProfiles` — schema 2.23.0): every non-empty value is logged
|
|
11
11
|
* as a `[finding] external` line and skipped from validation. The
|
|
12
|
-
* aggregator resolves these post-merge per ADR 0134 §4.5. A required
|
|
12
|
+
* aggregator resolves these post-merge per M-ADR 0134 §4.5. A required
|
|
13
13
|
* (non-nullable) external FK still fails when EMPTY — the value must be
|
|
14
14
|
* named even if it resolves cross-SDD.
|
|
15
15
|
*
|
|
@@ -223,8 +223,8 @@ const ManifestSchema = z.object({
|
|
|
223
223
|
// shape here. Whether the value resolves against the active vocabulary
|
|
224
224
|
// (method ∪ RA-bundle ∪ adopter) is checked in the build step, which has
|
|
225
225
|
// the bundle cache. Absent reads as "unclassified" (with a finding). Named
|
|
226
|
-
// application_archetype to stay distinct from the ADR 0173 domain archetype
|
|
227
|
-
// and the ADR 0169 openui archetype.
|
|
226
|
+
// application_archetype to stay distinct from the M-ADR 0173 domain archetype
|
|
227
|
+
// and the M-ADR 0169 openui archetype.
|
|
228
228
|
application_archetype: z
|
|
229
229
|
.string()
|
|
230
230
|
.regex(/^[a-z][a-z0-9-]*$/, {
|
|
@@ -298,7 +298,7 @@ export async function loadSddManifest(sddPath, options) {
|
|
|
298
298
|
const code = err.code;
|
|
299
299
|
if (code === "ENOENT") {
|
|
300
300
|
throw new Error(`SDD manifest not found at ${sourcePath}\n\n` +
|
|
301
|
-
`Every SDD repo MUST declare an .sdd/sdd-manifest.yaml per ADR 0134 §4.6.\n` +
|
|
301
|
+
`Every SDD repo MUST declare an .sdd/sdd-manifest.yaml per M-ADR 0134 §4.6.\n` +
|
|
302
302
|
`Schema: docs/method/methods/sdd-manifest-schema.yaml in sdd-method.\n` +
|
|
303
303
|
`Bootstrap: \`sdd-cli init\` (when migrated to support manifest authoring).`);
|
|
304
304
|
}
|
|
@@ -905,3 +905,31 @@ coverage:
|
|
|
905
905
|
kind: enum
|
|
906
906
|
scoring: not-applicable
|
|
907
907
|
reason: closed vocabulary, not an artefact
|
|
908
|
+
changes:
|
|
909
|
+
kind: entity
|
|
910
|
+
scoring: not-applicable
|
|
911
|
+
reason: projected from the behaviour store, whose change gate and judge hold its quality (M-ADR 0222, M-ADR 0223)
|
|
912
|
+
change_work_order:
|
|
913
|
+
kind: edge
|
|
914
|
+
scoring: derived-edge
|
|
915
|
+
class: realisation
|
|
916
|
+
impact_flow: both
|
|
917
|
+
reason: derived from agreement records and verdicts
|
|
918
|
+
change_work_item:
|
|
919
|
+
kind: annotation
|
|
920
|
+
scoring: derived-edge
|
|
921
|
+
class: traceability
|
|
922
|
+
impact_flow: none
|
|
923
|
+
reason: derived from each change's proposal
|
|
924
|
+
change_status:
|
|
925
|
+
kind: enum
|
|
926
|
+
scoring: not-applicable
|
|
927
|
+
reason: closed vocabulary, not an artefact
|
|
928
|
+
judge_verdict:
|
|
929
|
+
kind: enum
|
|
930
|
+
scoring: not-applicable
|
|
931
|
+
reason: closed vocabulary, not an artefact
|
|
932
|
+
work_order_status:
|
|
933
|
+
kind: enum
|
|
934
|
+
scoring: not-applicable
|
|
935
|
+
reason: closed vocabulary, not an artefact
|
|
@@ -23,8 +23,8 @@
|
|
|
23
23
|
* release; migration tooling (`sdd-cli migrate <schema> --to <v>`,
|
|
24
24
|
* planned) covers downgrade paths.
|
|
25
25
|
*
|
|
26
|
-
* See ADR 0132 (catalogue-integrity gate's schema-drift digest hook) +
|
|
27
|
-
* ADR 0134 §4.6 (canonical builder + aggregator).
|
|
26
|
+
* See M-ADR 0132 (catalogue-integrity gate's schema-drift digest hook) +
|
|
27
|
+
* M-ADR 0134 §4.6 (canonical builder + aggregator).
|
|
28
28
|
*/
|
|
29
29
|
export const SCHEMA_COMPAT = {
|
|
30
30
|
catalogue_schema: "^4.0.0",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Loader for the canonical catalogue-schema.yaml vendored from sdd-method.
|
|
3
3
|
*
|
|
4
|
-
* Per ADR 0134 §4.6 the canonical builder reads the schema rather than
|
|
4
|
+
* Per M-ADR 0134 §4.6 the canonical builder reads the schema rather than
|
|
5
5
|
* hardcoding column shapes or FK rules. This loader is the only place in
|
|
6
6
|
* the CLI that knows the schema file's location.
|
|
7
7
|
*/
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Loader for the optional `.sdd/screen-validation.yaml` config — the
|
|
3
3
|
* adopter-tunable parameters for screen-spec composition-depth validation
|
|
4
|
-
* (ADR 0168 §4.5) and the archetype overlay (ADR 0169 §4.3).
|
|
4
|
+
* (M-ADR 0168 §4.5) and the archetype overlay (M-ADR 0169 §4.3).
|
|
5
5
|
*
|
|
6
6
|
* Every field is optional and carries a method default; an absent file means
|
|
7
7
|
* "method defaults only" (the vocabulary-free checks all still run). Follows
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* decorative_primitives: # unlocks screen-styling-primitive-as-structure
|
|
14
14
|
* - Spacer
|
|
15
15
|
* - Divider
|
|
16
|
-
* archetype_overlays: # per-platform overlay (ADR 0169 §4.3)
|
|
16
|
+
* archetype_overlays: # per-platform overlay (M-ADR 0169 §4.3)
|
|
17
17
|
* web-generic:
|
|
18
18
|
* strip_prefixes: [Nwc, Nwe] # render-only: stripped when humanising labels
|
|
19
19
|
* overrides:
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// Extracted from builders/services.ts so two callers can share it:
|
|
4
4
|
// - the per-SDD services builder (buildServices), and
|
|
5
5
|
// - the aggregator's federated reverse-metadata enrichment pass
|
|
6
|
-
// (ADR 0163 P2), which reaches member SDDs' arch docs that the
|
|
6
|
+
// (M-ADR 0163 P2), which reaches member SDDs' arch docs that the
|
|
7
7
|
// platform-root's own build never sees.
|
|
8
8
|
//
|
|
9
9
|
// The metadata is read faithfully — not inferred — from three blocks:
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
// `docs/domains/{domain}/product/{capability}.traceability.yaml`.
|
|
9
9
|
//
|
|
10
10
|
// Schema reference: docs/method/methods/capability-traceability-manifest-template.yaml
|
|
11
|
-
// in sdd-method (per ADR 0047 / capability-spec-template.md).
|
|
11
|
+
// in sdd-method (per M-ADR 0047 / capability-spec-template.md).
|
|
12
12
|
import { readdir, readFile, stat } from "node:fs/promises";
|
|
13
13
|
import { join, relative, sep } from "node:path";
|
|
14
14
|
import { parse as parseYaml } from "yaml";
|
|
@@ -84,6 +84,8 @@ export async function loadTraceabilityManifests(opts) {
|
|
|
84
84
|
}
|
|
85
85
|
throw err;
|
|
86
86
|
}
|
|
87
|
+
// A manifest dropped whole takes its capability's traceability with it, so
|
|
88
|
+
// each drop below is an error that fails the build (as for repo-configs).
|
|
87
89
|
const manifests = [];
|
|
88
90
|
for (const path of yamlPaths.sort()) {
|
|
89
91
|
const text = await readFile(path, "utf-8");
|
|
@@ -92,18 +94,18 @@ export async function loadTraceabilityManifests(opts) {
|
|
|
92
94
|
raw = parseYaml(text);
|
|
93
95
|
}
|
|
94
96
|
catch (err) {
|
|
95
|
-
opts.findings.add("convention", `failed to parse YAML at ${relative(opts.sddPath, path)}: ${err.message}
|
|
97
|
+
opts.findings.add("convention", `failed to parse YAML at ${relative(opts.sddPath, path)}: ${err.message} — manifest dropped`, "error", relative(opts.sddPath, path));
|
|
96
98
|
continue;
|
|
97
99
|
}
|
|
98
100
|
if (!raw || typeof raw !== "object") {
|
|
99
|
-
opts.findings.add("convention", `${relative(opts.sddPath, path)}: not an object —
|
|
101
|
+
opts.findings.add("convention", `${relative(opts.sddPath, path)}: not an object — manifest dropped`, "error", relative(opts.sddPath, path));
|
|
100
102
|
continue;
|
|
101
103
|
}
|
|
102
104
|
const obj = raw;
|
|
103
105
|
const cap = obj["capability"] ?? {};
|
|
104
106
|
const capId = String(cap["id"] ?? "").trim();
|
|
105
107
|
if (capId === "") {
|
|
106
|
-
opts.findings.add("convention", `${relative(opts.sddPath, path)}: missing capability.id
|
|
108
|
+
opts.findings.add("convention", `${relative(opts.sddPath, path)}: missing capability.id — manifest dropped`, "error", relative(opts.sddPath, path));
|
|
107
109
|
continue;
|
|
108
110
|
}
|
|
109
111
|
const relPath = relative(opts.sddPath, path);
|
|
@@ -53,7 +53,7 @@ export function findingRows(results, runDate) {
|
|
|
53
53
|
observed_not_declared: r.observedNotDeclared.length,
|
|
54
54
|
needs_triage: r.needsTriage,
|
|
55
55
|
run_date: runDate,
|
|
56
|
-
source_sdd_id: "", // populated by the aggregator per ADR 0134
|
|
56
|
+
source_sdd_id: "", // populated by the aggregator per M-ADR 0134
|
|
57
57
|
platform_sdd_id: "", // stamped at organisation tier per M-ADR 0208
|
|
58
58
|
};
|
|
59
59
|
lines.push(FINDING_COLUMNS.map((c) => csvCell(row[c])).join(","));
|
|
@@ -17,7 +17,7 @@ function resolveSource(targetRepo, source, codeRoot) {
|
|
|
17
17
|
}
|
|
18
18
|
const markdownProviderSignals = async (path, spec) => {
|
|
19
19
|
const out = new Set();
|
|
20
|
-
// `section` (ADR 0180 delta-pilot extension) scopes the scan to one heading block and accepts a plain
|
|
20
|
+
// `section` (M-ADR 0180 delta-pilot extension) scopes the scan to one heading block and accepts a plain
|
|
21
21
|
// "Field" header, so a check can read ONE entity table inside a multi-table data-model doc (e.g.
|
|
22
22
|
// data-model.mermaid.md "### Collection: orders") without duplicating the field list into a bespoke
|
|
23
23
|
// surface file. With no `section` the behaviour is byte-for-byte the legacy one (whole file, strict
|
|
@@ -499,7 +499,7 @@ function printReconcile(chk, r, schemaDir, out) {
|
|
|
499
499
|
if (!chk.reconcile || r.target !== "binding-vs-reality")
|
|
500
500
|
return;
|
|
501
501
|
const rc = chk.reconcile;
|
|
502
|
-
out(`\n--- reconcile ${r.id} -> regenerate \`${rc.block}\` in ${rc.binding} (ADR 0181 §2.3) ---\n`);
|
|
502
|
+
out(`\n--- reconcile ${r.id} -> regenerate \`${rc.block}\` in ${rc.binding} (M-ADR 0181 §2.3) ---\n`);
|
|
503
503
|
out(`# generated from the observed-set (${r.observed} schemas); the binding cannot drift if generated.\n`);
|
|
504
504
|
if (rc.note)
|
|
505
505
|
out(`# NOTE: ${rc.note}\n`);
|
|
@@ -513,7 +513,7 @@ function printReconcile(chk, r, schemaDir, out) {
|
|
|
513
513
|
}
|
|
514
514
|
}
|
|
515
515
|
async function planChecks(opts, stdout) {
|
|
516
|
-
// Resolution order: explicit --config wins; else the ADR 0181 binding (checks derived from it);
|
|
516
|
+
// Resolution order: explicit --config wins; else the M-ADR 0181 binding (checks derived from it);
|
|
517
517
|
// else the conventional .sdd/conformance-checks.yaml; else nothing to do.
|
|
518
518
|
if (!opts.config && hasBinding(opts.targetRepo)) {
|
|
519
519
|
const derived = await deriveChecksFromBinding(opts.targetRepo);
|
|
@@ -523,7 +523,7 @@ async function planChecks(opts, stdout) {
|
|
|
523
523
|
? resolveSource(opts.targetRepo, opts.config, opts.codeRoot)
|
|
524
524
|
: resolve(opts.targetRepo, ".sdd/conformance-checks.yaml");
|
|
525
525
|
if (!existsSync(configPath)) {
|
|
526
|
-
stdout(`[skip] no spec↔implementation binding (.sdd/implementation-binding.yaml or .sdd/implementation-bindings/, ADR 0181) and no ` +
|
|
526
|
+
stdout(`[skip] no spec↔implementation binding (.sdd/implementation-binding.yaml or .sdd/implementation-bindings/, M-ADR 0181) and no ` +
|
|
527
527
|
`checks file at ${configPath}\n`);
|
|
528
528
|
return null;
|
|
529
529
|
}
|
|
@@ -562,7 +562,7 @@ export async function runConformance(opts, stdout = (line) => process.stdout.wri
|
|
|
562
562
|
stdout(JSON.stringify({ checks: results, skipped }, null, 2) + "\n");
|
|
563
563
|
}
|
|
564
564
|
else {
|
|
565
|
-
stdout("Conformance-reverse (advisory; disposition is triage — ADR 0180 §2.3).\n");
|
|
565
|
+
stdout("Conformance-reverse (advisory; disposition is triage — M-ADR 0180 §2.3).\n");
|
|
566
566
|
for (const r of results) {
|
|
567
567
|
printHuman(r, stdout);
|
|
568
568
|
if (opts.reconcile) {
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* source of truth).
|
|
7
7
|
*
|
|
8
8
|
* Replaces the v0.3.0 `generate-claude-md` verb whose rich-content
|
|
9
|
-
* output diverges from the ADR 0148 thin-pointer shape.
|
|
9
|
+
* output diverges from the M-ADR 0148 thin-pointer shape.
|
|
10
10
|
*/
|
|
11
11
|
import { access } from "node:fs/promises";
|
|
12
12
|
import { join } from "node:path";
|
|
@@ -36,7 +36,7 @@ export async function runGenerateBriefing(opts, stdout = (line) => process.stdou
|
|
|
36
36
|
// graceful skip downstream.
|
|
37
37
|
const templatesPresent = await fileExists(join(opts.targetDir, BRIEFING_TEMPLATE_ROOT, "agent-instructions.md.hbs"));
|
|
38
38
|
if (!templatesPresent) {
|
|
39
|
-
stdout(fail(`Briefing templates not found under ${BRIEFING_TEMPLATE_ROOT}/ — sync against a baseline that ships ADR 0148 templates first.`));
|
|
39
|
+
stdout(fail(`Briefing templates not found under ${BRIEFING_TEMPLATE_ROOT}/ — sync against a baseline that ships M-ADR 0148 templates first.`));
|
|
40
40
|
return { exitCode: 1 };
|
|
41
41
|
}
|
|
42
42
|
const result = await syncBriefingFiles({
|