@sdd-method/maintain-cli 0.0.0-stage → 0.1.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.
Files changed (206) hide show
  1. package/LICENSE +201 -0
  2. package/NOTICE +17 -0
  3. package/README.md +6 -2
  4. package/dist/lib/adr-origin.js +59 -0
  5. package/dist/lib/agent-harness.js +28 -0
  6. package/dist/lib/briefing/index.js +13 -0
  7. package/dist/lib/briefing/render.js +123 -0
  8. package/dist/lib/briefing/variables.js +92 -0
  9. package/dist/lib/bundle.js +123 -0
  10. package/dist/lib/catalogue/aggregate.js +2404 -0
  11. package/dist/lib/catalogue/aggregation-manifest-loader.js +173 -0
  12. package/dist/lib/catalogue/application-archetype/expectations.js +119 -0
  13. package/dist/lib/catalogue/application-archetype/vocabulary.js +177 -0
  14. package/dist/lib/catalogue/archetype/maps/android.yaml +66 -0
  15. package/dist/lib/catalogue/archetype/maps/swiftui.yaml +58 -0
  16. package/dist/lib/catalogue/archetype/maps/uikit.yaml +48 -0
  17. package/dist/lib/catalogue/archetype/maps/web-generic.yaml +86 -0
  18. package/dist/lib/catalogue/archetype/openui-archetype-vocabulary.yaml +46 -0
  19. package/dist/lib/catalogue/archetype/resolver.js +103 -0
  20. package/dist/lib/catalogue/archetype/wireframe.js +418 -0
  21. package/dist/lib/catalogue/baseline-check.js +151 -0
  22. package/dist/lib/catalogue/build.js +1502 -0
  23. package/dist/lib/catalogue/builders/adr-supersedes.js +103 -0
  24. package/dist/lib/catalogue/builders/adrs.js +222 -0
  25. package/dist/lib/catalogue/builders/application-conformance-coverage.js +47 -0
  26. package/dist/lib/catalogue/builders/application-data-plane-bindings.js +115 -0
  27. package/dist/lib/catalogue/builders/c4-components.js +229 -0
  28. package/dist/lib/catalogue/builders/c4-containers.js +240 -0
  29. package/dist/lib/catalogue/builders/c4-entity-rollups.js +87 -0
  30. package/dist/lib/catalogue/builders/c4-external-systems.js +194 -0
  31. package/dist/lib/catalogue/builders/c4-l1-candidates.js +107 -0
  32. package/dist/lib/catalogue/builders/c4-systems.js +98 -0
  33. package/dist/lib/catalogue/builders/capabilities.js +488 -0
  34. package/dist/lib/catalogue/builders/capability-domain-model.js +74 -0
  35. package/dist/lib/catalogue/builders/capability-edges.js +256 -0
  36. package/dist/lib/catalogue/builders/capability-spec-walker.js +99 -0
  37. package/dist/lib/catalogue/builders/capability-spec.js +348 -0
  38. package/dist/lib/catalogue/builders/container-dependency.js +183 -0
  39. package/dist/lib/catalogue/builders/contracts.js +402 -0
  40. package/dist/lib/catalogue/builders/data-items.js +344 -0
  41. package/dist/lib/catalogue/builders/data-store-mapping.js +113 -0
  42. package/dist/lib/catalogue/builders/domain-models.js +175 -0
  43. package/dist/lib/catalogue/builders/domains.js +119 -0
  44. package/dist/lib/catalogue/builders/edge-label-merge.js +19 -0
  45. package/dist/lib/catalogue/builders/entities-manifest.js +160 -0
  46. package/dist/lib/catalogue/builders/entities-mermaid.js +189 -0
  47. package/dist/lib/catalogue/builders/entity-persistence.js +102 -0
  48. package/dist/lib/catalogue/builders/entity-slug.js +47 -0
  49. package/dist/lib/catalogue/builders/event-catalog-walker.js +186 -0
  50. package/dist/lib/catalogue/builders/event-edges.js +327 -0
  51. package/dist/lib/catalogue/builders/events.js +168 -0
  52. package/dist/lib/catalogue/builders/evidence-class.js +43 -0
  53. package/dist/lib/catalogue/builders/evidence-target-repo.js +67 -0
  54. package/dist/lib/catalogue/builders/external-system-exemption.js +120 -0
  55. package/dist/lib/catalogue/builders/feature-contract.js +77 -0
  56. package/dist/lib/catalogue/builders/feature-domain-model.js +50 -0
  57. package/dist/lib/catalogue/builders/feature-grounding-walker.js +254 -0
  58. package/dist/lib/catalogue/builders/feature-grounding.js +391 -0
  59. package/dist/lib/catalogue/builders/feature-groups.js +63 -0
  60. package/dist/lib/catalogue/builders/feature-subscription-channels.js +228 -0
  61. package/dist/lib/catalogue/builders/feature-tree-walker.js +295 -0
  62. package/dist/lib/catalogue/builders/features.js +300 -0
  63. package/dist/lib/catalogue/builders/glossary-xref.js +378 -0
  64. package/dist/lib/catalogue/builders/glossary.js +204 -0
  65. package/dist/lib/catalogue/builders/implementations.js +214 -0
  66. package/dist/lib/catalogue/builders/index.js +64 -0
  67. package/dist/lib/catalogue/builders/integration-components.js +344 -0
  68. package/dist/lib/catalogue/builders/integrations.js +181 -0
  69. package/dist/lib/catalogue/builders/persona-c4system.js +149 -0
  70. package/dist/lib/catalogue/builders/persona-container.js +133 -0
  71. package/dist/lib/catalogue/builders/persona-journey-edges.js +133 -0
  72. package/dist/lib/catalogue/builders/personas.js +152 -0
  73. package/dist/lib/catalogue/builders/product-edges.js +106 -0
  74. package/dist/lib/catalogue/builders/product-platform-dependencies.js +405 -0
  75. package/dist/lib/catalogue/builders/products.js +162 -0
  76. package/dist/lib/catalogue/builders/quality-scores.js +635 -0
  77. package/dist/lib/catalogue/builders/repo-capability-exemption.js +61 -0
  78. package/dist/lib/catalogue/builders/repo-dependency.js +127 -0
  79. package/dist/lib/catalogue/builders/repo-edges.js +340 -0
  80. package/dist/lib/catalogue/builders/repositories.js +458 -0
  81. package/dist/lib/catalogue/builders/scaffolds.js +197 -0
  82. package/dist/lib/catalogue/builders/screen-tree.js +222 -0
  83. package/dist/lib/catalogue/builders/screens.js +396 -0
  84. package/dist/lib/catalogue/builders/service-capability-exemption.js +63 -0
  85. package/dist/lib/catalogue/builders/service-contract-consumes.js +186 -0
  86. package/dist/lib/catalogue/builders/service-contract.js +74 -0
  87. package/dist/lib/catalogue/builders/service-entity-tables.js +187 -0
  88. package/dist/lib/catalogue/builders/services.js +232 -0
  89. package/dist/lib/catalogue/builders/system-external-dependency.js +115 -0
  90. package/dist/lib/catalogue/builders/user-journeys.js +253 -0
  91. package/dist/lib/catalogue/canonical-schema.yaml +4117 -0
  92. package/dist/lib/catalogue/cli-version.js +10 -0
  93. package/dist/lib/catalogue/contract-id.js +49 -0
  94. package/dist/lib/catalogue/contract-path-resolution.js +149 -0
  95. package/dist/lib/catalogue/coverage-predicates.js +603 -0
  96. package/dist/lib/catalogue/coverage-render.js +552 -0
  97. package/dist/lib/catalogue/coverage-run.js +115 -0
  98. package/dist/lib/catalogue/csv-reader.js +97 -0
  99. package/dist/lib/catalogue/csv-writer.js +96 -0
  100. package/dist/lib/catalogue/data-item-coverage.js +142 -0
  101. package/dist/lib/catalogue/data-plane-coherence.js +77 -0
  102. package/dist/lib/catalogue/ddl-generator.js +233 -0
  103. package/dist/lib/catalogue/dedupe-keyed-tables.js +0 -0
  104. package/dist/lib/catalogue/engine-validator.js +239 -0
  105. package/dist/lib/catalogue/ext-id.js +76 -0
  106. package/dist/lib/catalogue/feature-grounding-aliases-loader.js +65 -0
  107. package/dist/lib/catalogue/feature-repo-zero-resolution-summary.js +31 -0
  108. package/dist/lib/catalogue/finding-identity.js +183 -0
  109. package/dist/lib/catalogue/findings.js +46 -0
  110. package/dist/lib/catalogue/fk-validator.js +136 -0
  111. package/dist/lib/catalogue/freshness.js +69 -0
  112. package/dist/lib/catalogue/gate-checks.js +338 -0
  113. package/dist/lib/catalogue/graph-projection.js +346 -0
  114. package/dist/lib/catalogue/graph-run.js +64 -0
  115. package/dist/lib/catalogue/impact-run.js +228 -0
  116. package/dist/lib/catalogue/manifest-loader.js +435 -0
  117. package/dist/lib/catalogue/platform-scope.js +7 -0
  118. package/dist/lib/catalogue/population-checks.js +87 -0
  119. package/dist/lib/catalogue/relationship-semantics.js +66 -0
  120. package/dist/lib/catalogue/reverse-product-quality.js +99 -0
  121. package/dist/lib/catalogue/rubric-coverage-map.yaml +871 -0
  122. package/dist/lib/catalogue/runway-vocabulary-loader.js +56 -0
  123. package/dist/lib/catalogue/scaffold-delta.js +261 -0
  124. package/dist/lib/catalogue/schema-compat.js +52 -0
  125. package/dist/lib/catalogue/schema-loader.js +87 -0
  126. package/dist/lib/catalogue/scores-coverage.js +573 -0
  127. package/dist/lib/catalogue/screen-validation-loader.js +89 -0
  128. package/dist/lib/catalogue/service-architecture-parser.js +193 -0
  129. package/dist/lib/catalogue/service-contract-aliases-loader.js +109 -0
  130. package/dist/lib/catalogue/staleness-verdicts.js +345 -0
  131. package/dist/lib/catalogue/traceability-loader.js +350 -0
  132. package/dist/lib/catalogue/validate.js +200 -0
  133. package/dist/lib/catalogue/version.js +18 -0
  134. package/dist/lib/ci-binding/index.js +220 -0
  135. package/dist/lib/ci-binding/module.js +204 -0
  136. package/dist/lib/conformance/binding.js +70 -0
  137. package/dist/lib/context-pull/index.js +151 -0
  138. package/dist/lib/context-pull/resolve.js +70 -0
  139. package/dist/lib/generate-briefing/index.js +77 -0
  140. package/dist/lib/hooks-seed/copilot.js +167 -0
  141. package/dist/lib/hooks-seed/entries.js +47 -0
  142. package/dist/lib/hooks-seed/index.js +17 -0
  143. package/dist/lib/hooks-seed/lifecycle-mapping.js +28 -0
  144. package/dist/lib/hooks-seed/merge.js +128 -0
  145. package/dist/lib/hooks-seed/types.js +20 -0
  146. package/dist/lib/init/ci-workflow.js +98 -0
  147. package/dist/lib/list/discover.js +100 -0
  148. package/dist/lib/list/format.js +84 -0
  149. package/dist/lib/list/index.js +16 -0
  150. package/dist/lib/lock-file.js +437 -0
  151. package/dist/lib/mcp-seed/entries.js +14 -0
  152. package/dist/lib/mcp-seed/index.js +28 -0
  153. package/dist/lib/mcp-seed/merge.js +99 -0
  154. package/dist/lib/mcp-seed/types.js +13 -0
  155. package/dist/lib/pack/builder.js +303 -0
  156. package/dist/lib/pack/index.js +87 -0
  157. package/dist/lib/pack/leakage.js +144 -0
  158. package/dist/lib/pack/log.js +18 -0
  159. package/dist/lib/pack/publish-transform.js +233 -0
  160. package/dist/lib/pack/reference-closure.js +125 -0
  161. package/dist/lib/pack/schema.js +121 -0
  162. package/dist/lib/pack/seed.js +182 -0
  163. package/dist/lib/pack/validate.js +49 -0
  164. package/dist/lib/package-version.js +92 -0
  165. package/dist/lib/repo-kind.js +129 -0
  166. package/dist/lib/scripts.js +7 -0
  167. package/dist/lib/snapshot/catalogue-diff.js +219 -0
  168. package/dist/lib/snapshot/manifest.js +206 -0
  169. package/dist/lib/sync/adr-transitions.js +250 -0
  170. package/dist/lib/sync/apply.js +91 -0
  171. package/dist/lib/sync/briefing-merge.js +90 -0
  172. package/dist/lib/sync/bundle-cache.js +109 -0
  173. package/dist/lib/sync/bundle-source.js +61 -0
  174. package/dist/lib/sync/config.js +72 -0
  175. package/dist/lib/sync/copilot-hooks-merge.js +108 -0
  176. package/dist/lib/sync/diff.js +251 -0
  177. package/dist/lib/sync/index.js +818 -0
  178. package/dist/lib/sync/settings-merge.js +216 -0
  179. package/dist/lib/sync/yaml-block-merge.js +120 -0
  180. package/dist/lib/validate/aggregate.js +51 -0
  181. package/dist/lib/validate/bundle-coherence.js +74 -0
  182. package/dist/lib/validate/dispatch.js +243 -0
  183. package/dist/lib/validate/index.js +110 -0
  184. package/dist/lib/validate/plan.js +54 -0
  185. package/dist/lib/validate/runner.js +85 -0
  186. package/dist/lib/validate/yaml-parse.js +112 -0
  187. package/dist/maintain-bin.js +8 -0
  188. package/dist/maintain-program.js +91 -0
  189. package/dist/maintain-version.json +4 -0
  190. package/dist/verbs/catalogue-maintain.js +110 -0
  191. package/dist/verbs/catalogue-verify.js +114 -0
  192. package/dist/verbs/context.js +39 -0
  193. package/dist/verbs/generate-briefing.js +29 -0
  194. package/dist/verbs/list.js +45 -0
  195. package/dist/verbs/pack-build.js +31 -0
  196. package/dist/verbs/pack-validate.js +17 -0
  197. package/dist/verbs/path-option.js +25 -0
  198. package/dist/verbs/render.js +87 -0
  199. package/dist/verbs/sync.js +110 -0
  200. package/dist/verbs/validate.js +48 -0
  201. package/dist/verify-program.js +122 -0
  202. package/dist/verify-version.json +4 -0
  203. package/package.json +32 -4
  204. package/scripts/validate-app-dependencies.sh +664 -0
  205. package/scripts/validate-app-docs.sh +199 -0
  206. package/scripts/validate-integration-docs.sh +505 -0
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Orchestrator for `sdd-cli catalogue graph` — loads the schema, the
3
+ * vendored rubric-coverage-map (the node/edge kind authority; the schema
4
+ * itself does not declare kind), and the catalogues directory, projects
5
+ * the graph (graph-projection.ts holds the derivation rule), writes the
6
+ * JSONL export, and prints the counts + digest so the figures are stated
7
+ * on every run, not discoverable after the fact.
8
+ *
9
+ * The export is regenerated on every invocation and is NOT committed
10
+ * (M-ADR 0205 §4.6): default output is `<catalogues-dir>-graph.jsonl`
11
+ * beside the catalogues directory, which adopter .gitignore entries cover.
12
+ * Tier is explicit, never inferred, same discipline as every other reader.
13
+ */
14
+ import { existsSync } from "node:fs";
15
+ import { writeFile } from "node:fs/promises";
16
+ import { join, resolve } from "node:path";
17
+ import { readCatalogueCsv } from "./csv-reader.js";
18
+ import { loadCanonicalSchema } from "./schema-loader.js";
19
+ import { defaultCataloguesDir, projectGraph, } from "./graph-projection.js";
20
+ import { loadCatalogueKinds, loadRelationshipSemantics } from "./relationship-semantics.js";
21
+ export * from "./relationship-semantics.js";
22
+ // defaultCataloguesDir lives in graph-projection.ts (read-only), re-exported
23
+ // here for existing importers. Read-only verbs must import it from there:
24
+ // importing it from this module drags the graph WRITER into the verify-only
25
+ // package's closure (build-persona-package's canary; the fdf9453 leak).
26
+ export { defaultCataloguesDir };
27
+ export async function runCatalogueGraph(inputs, write) {
28
+ const sddRoot = resolve(inputs.sddPath ?? process.cwd());
29
+ const tier = inputs.tier ?? "member";
30
+ const dir = resolve(sddRoot, inputs.cataloguesDir ?? defaultCataloguesDir(tier));
31
+ const outPath = inputs.out !== undefined
32
+ ? resolve(sddRoot, inputs.out)
33
+ : `${dir}-graph.jsonl`;
34
+ if (!existsSync(dir)) {
35
+ write(`catalogues directory not found at ${dir}\n` +
36
+ ` Run \`sdd-cli catalogue build\` (or aggregate) first — the graph ` +
37
+ `is derived from built catalogues, never authored.\n`);
38
+ return { exitCode: 2 };
39
+ }
40
+ const schema = await loadCanonicalSchema();
41
+ const kinds = await loadCatalogueKinds();
42
+ const semantics = await loadRelationshipSemantics();
43
+ const rowsByCatalogue = new Map();
44
+ for (const cat of schema.catalogues) {
45
+ const filePath = join(dir, `${cat.name}.csv`);
46
+ if (!existsSync(filePath))
47
+ continue;
48
+ const parsed = await readCatalogueCsv(filePath);
49
+ rowsByCatalogue.set(cat.name, parsed.rows);
50
+ }
51
+ const projection = projectGraph(schema, kinds, rowsByCatalogue, tier, semantics);
52
+ await writeFile(outPath, projection.text, "utf-8");
53
+ const c = projection.counts;
54
+ write(`graph projection (${tier} tier, schema ${schema.schemaVersion})\n`);
55
+ write(` nodes: ${c.nodes}\n`);
56
+ write(` edges: ${c.edges}\n`);
57
+ write(` property records: ${c.properties}\n`);
58
+ write(` omitted (external, resolves at aggregation): ${c.omittedExternal}\n`);
59
+ write(` omitted (unresolved — mirrors FK findings): ${c.omittedUnresolved}\n`);
60
+ write(` digest: sha256:${projection.digest}\n`);
61
+ write(` wrote ${outPath}\n`);
62
+ return { exitCode: 0, counts: c, outPath };
63
+ }
64
+ //# sourceMappingURL=graph-run.js.map
@@ -0,0 +1,228 @@
1
+ /**
2
+ * Transitive impact analysis — `sdd-cli catalogue impact` (M-ADR 0206 §4.6).
3
+ *
4
+ * Impact traverses the graph-projection edge set BY DECLARED SEMANTICS: every
5
+ * relationship carries an impact-flow token in the rubric-coverage-map
6
+ * (M-ADR 0206 §4.1) naming which endpoint RECEIVES impact — `toward-source`
7
+ * (dependency shape: a change at the target propagates to the source),
8
+ * `toward-target` (membership shape: a part's change reaches its whole),
9
+ * `both` (realisation), `none` (xref, lineage records, attributes). One
10
+ * relationship (`service_event`) resolves its flow per row from a named
11
+ * column (§4.2). The closure is the set of nodes impact can reach from the
12
+ * seed along declared propagation directions, computed by recursive SQL
13
+ * (`WITH RECURSIVE`) on the Phase A engine.
14
+ *
15
+ * THE CO-DIRECTIONALITY INVARIANT (§4.4, a condition of 0206's acceptance):
16
+ * the Phase C mirror-dedup heuristic is retired because under the declared
17
+ * tokens every true-mirror pair propagates the SAME direction. That premise
18
+ * is exercised, not assumed: buildImpactPropagation asserts that no node
19
+ * pair receives propagation in BOTH directions from two DIFFERENT
20
+ * single-direction relationship types, and fails loudly naming the pair and
21
+ * types. A single relationship declaring `both` is deliberate bidirectional
22
+ * coupling and is exempt; a self-referential type contributing both
23
+ * directions from different rows (a hierarchy cycle) is likewise exempt.
24
+ * A future token edit that would silently bring the undirected flood back
25
+ * trips this assertion instead.
26
+ *
27
+ * Cycle discipline: the recursion carries NO depth column — recursive UNION
28
+ * deduplicates whole rows, and a depth column makes every lap of a cycle a
29
+ * "new" row: the query that looks more informative is the query that never
30
+ * terminates. As a bare id-set the closure saturates and stops.
31
+ */
32
+ import { existsSync } from "node:fs";
33
+ import { join, resolve } from "node:path";
34
+ import { readCatalogueCsv } from "./csv-reader.js";
35
+ import { loadCanonicalSchema } from "./schema-loader.js";
36
+ import { loadCatalogueKinds, loadRelationshipSemantics, } from "./relationship-semantics.js";
37
+ import { defaultCataloguesDir, projectGraph, } from "./graph-projection.js";
38
+ function resolveFlow(edge, semantics) {
39
+ const decl = edge.type.includes(".")
40
+ ? semantics.entityFks.get(edge.type)
41
+ : semantics.edges.get(edge.type);
42
+ if (decl === undefined) {
43
+ throw new Error(`impact: relationship ${edge.type} has no declaration in the ` +
44
+ `rubric-coverage-map (M-ADR 0206) — sync the vendored map.`);
45
+ }
46
+ if (decl.impactFlow !== undefined)
47
+ return decl.impactFlow;
48
+ const by = decl.impactFlowBy;
49
+ const value = (edge.properties?.[by.column] ?? "").trim();
50
+ const flow = by.values[value];
51
+ if (flow === undefined) {
52
+ throw new Error(`impact: ${edge.type} resolves flow by column '${by.column}' but row ` +
53
+ `value '${value}' is not in the declared map — extend the ` +
54
+ `declaration or fix the row.`);
55
+ }
56
+ return flow;
57
+ }
58
+ /**
59
+ * Resolve every declared edge into propagation steps per its flow, and
60
+ * exercise the §4.4 co-directionality invariant.
61
+ */
62
+ export function buildImpactPropagation(edges, semantics) {
63
+ const out = [];
64
+ const byFlow = new Map();
65
+ let flowNone = 0;
66
+ const pairs = new Map();
67
+ const notePair = (from, to, type) => {
68
+ const [a, b] = from < to ? [from, to] : [to, from];
69
+ const key = `${a}␟${b}`;
70
+ let rec = pairs.get(key);
71
+ if (rec === undefined) {
72
+ rec = { ab: new Set(), ba: new Set() };
73
+ pairs.set(key, rec);
74
+ }
75
+ (from === a ? rec.ab : rec.ba).add(type);
76
+ };
77
+ for (const e of edges) {
78
+ const flow = resolveFlow(e, semantics);
79
+ byFlow.set(flow, (byFlow.get(flow) ?? 0) + 1);
80
+ if (flow === "none") {
81
+ flowNone += 1;
82
+ continue;
83
+ }
84
+ if (flow === "toward-source" || flow === "both") {
85
+ out.push({ from: e.target, to: e.source, type: e.type });
86
+ notePair(e.target, e.source, e.type);
87
+ }
88
+ if (flow === "toward-target" || flow === "both") {
89
+ out.push({ from: e.source, to: e.target, type: e.type });
90
+ notePair(e.source, e.target, e.type);
91
+ }
92
+ }
93
+ // §4.4 invariant, refined on measured data (2026-08-06): a pair fails only
94
+ // when one type contributes EXCLUSIVELY a→b against another contributing
95
+ // EXCLUSIVELY b→a. A type that itself spans both directions on the pair —
96
+ // opposing role-rows of a role-conditional relationship (a service that
97
+ // publishes AND consumes the same event: five real pairs on the reverse
98
+ // estate, one service, all session-broadcast shaped), a self-referential
99
+ // hierarchy cycle, or a declared `both` flow — has DECLARED that pair
100
+ // bidirectional, so other types aligning with either direction are
101
+ // consistent with declarations, not drift. The flipped-token flood shape
102
+ // (two single-direction declarations opposing) still fails, loudly.
103
+ for (const [key, rec] of pairs) {
104
+ const abOnly = [...rec.ab].filter((t) => !rec.ba.has(t));
105
+ const baOnly = [...rec.ba].filter((t) => !rec.ab.has(t));
106
+ if (abOnly.length > 0 && baOnly.length > 0) {
107
+ const [a, b] = key.split("␟");
108
+ throw new Error(`impact: counter-directional reciprocal pair (M-ADR 0206 §4.4): ` +
109
+ `${abOnly[0]} propagates ${a} -> ${b} while ${baOnly[0]} propagates ` +
110
+ `${b} -> ${a}, and neither declares the pair bidirectional. The ` +
111
+ `declared tokens have re-created an undirected pair; fix the ` +
112
+ `classification before trusting any closure.`);
113
+ }
114
+ }
115
+ return { edges: out, flowNone, byFlow };
116
+ }
117
+ function sqlStringLiteral(value) {
118
+ return `'${value.replace(/'/g, "''")}'`;
119
+ }
120
+ /**
121
+ * Closure of `seed` over resolved propagation edges, on the engine.
122
+ * Exported for the fixture controls; the verb goes through runCatalogueImpact.
123
+ */
124
+ export async function computeImpactClosure(propagation, seed) {
125
+ const { DuckDBInstance } = await import("@duckdb/node-api");
126
+ const instance = await DuckDBInstance.create(":memory:");
127
+ const conn = await instance.connect();
128
+ try {
129
+ await conn.run(`CREATE TABLE prop (f VARCHAR, t VARCHAR);`);
130
+ const CHUNK = 500;
131
+ for (let i = 0; i < propagation.length; i += CHUNK) {
132
+ const tuples = propagation
133
+ .slice(i, i + CHUNK)
134
+ .map((e) => `(${sqlStringLiteral(e.from)}, ${sqlStringLiteral(e.to)})`)
135
+ .join(",\n");
136
+ await conn.run(`INSERT INTO prop VALUES\n${tuples};`);
137
+ }
138
+ const seedLit = sqlStringLiteral(seed);
139
+ // CYCLE GUARD: the recursion carries NO depth column, deliberately.
140
+ // Recursive UNION deduplicates whole rows; a depth column makes every
141
+ // lap around a cycle a "new" row (same id, bigger depth), so the query
142
+ // that looks more informative is the query that never terminates — the
143
+ // catalogue graph is not a DAG. As a bare id-set the closure saturates
144
+ // and stops.
145
+ const reader = await conn.runAndReadAll(`WITH RECURSIVE reach(id) AS (\n` +
146
+ ` SELECT t FROM prop WHERE f = ${seedLit}\n` +
147
+ ` UNION\n` +
148
+ ` SELECT p.t FROM prop p JOIN reach r ON p.f = r.id\n` +
149
+ `)\n` +
150
+ `SELECT DISTINCT id FROM reach WHERE id <> ${seedLit} ORDER BY id;`);
151
+ return reader.getRows().map((row) => String(row[0]));
152
+ }
153
+ finally {
154
+ conn.disconnectSync();
155
+ }
156
+ }
157
+ export async function runCatalogueImpact(inputs, write) {
158
+ const sddRoot = resolve(inputs.sddPath ?? process.cwd());
159
+ const tier = inputs.tier ?? "member";
160
+ const dir = resolve(sddRoot, inputs.cataloguesDir ?? defaultCataloguesDir(tier));
161
+ if (!existsSync(dir)) {
162
+ write(`catalogues directory not found at ${dir}\n` +
163
+ ` Run \`sdd-cli catalogue build\` (or aggregate) first.\n`);
164
+ return { exitCode: 2 };
165
+ }
166
+ const schema = await loadCanonicalSchema();
167
+ const kinds = await loadCatalogueKinds();
168
+ const semantics = await loadRelationshipSemantics();
169
+ const rowsByCatalogue = new Map();
170
+ for (const cat of schema.catalogues) {
171
+ const filePath = join(dir, `${cat.name}.csv`);
172
+ if (!existsSync(filePath))
173
+ continue;
174
+ rowsByCatalogue.set(cat.name, (await readCatalogueCsv(filePath)).rows);
175
+ }
176
+ const projection = projectGraph(schema, kinds, rowsByCatalogue, tier);
177
+ const lines = projection.text.trimEnd().split("\n");
178
+ const nodeIds = new Set();
179
+ const edges = [];
180
+ for (const line of lines) {
181
+ const o = JSON.parse(line);
182
+ if (o.t === "node")
183
+ nodeIds.add(o.id);
184
+ else if (o.t === "edge")
185
+ edges.push({
186
+ source: o.source,
187
+ target: o.target,
188
+ type: o.type,
189
+ ...(o.properties !== undefined ? { properties: o.properties } : {}),
190
+ });
191
+ }
192
+ if (!nodeIds.has(inputs.of)) {
193
+ write(`node not found in the projection: ${inputs.of}\n` +
194
+ ` Node ids have the form "<catalogue>/<id>", e.g. contracts/orders-api.\n`);
195
+ return { exitCode: 2 };
196
+ }
197
+ const prop = buildImpactPropagation(edges, semantics);
198
+ const closure = await computeImpactClosure(prop.edges, inputs.of);
199
+ const byCatalogue = new Map();
200
+ for (const id of closure) {
201
+ const cat = id.slice(0, id.indexOf("/"));
202
+ byCatalogue.set(cat, (byCatalogue.get(cat) ?? 0) + 1);
203
+ }
204
+ write(`impact closure of ${inputs.of} (${tier} tier, schema ${schema.schemaVersion})\n`);
205
+ // Required stated lines (M-ADR 0206 §4.6): what the number means, and what
206
+ // was traversed under each declared flow — visible per run, not
207
+ // discoverable from the code.
208
+ write(` semantics: change impact over classified relationships (M-ADR 0206) —\n` +
209
+ ` each relationship traversed per its declared impact-flow; the\n` +
210
+ ` co-directionality invariant is asserted on every run\n`);
211
+ const flowCounts = [...prop.byFlow.entries()]
212
+ .sort()
213
+ .map(([f, n]) => `${f}=${n}`)
214
+ .join(" ");
215
+ write(` declared edges by resolved flow: ${flowCounts}\n`);
216
+ write(` reachable nodes: ${closure.length}\n`);
217
+ for (const [cat, n] of [...byCatalogue.entries()].sort()) {
218
+ write(` ${cat}: ${n}\n`);
219
+ }
220
+ for (const id of closure) {
221
+ write(` ${id}\n`);
222
+ }
223
+ return {
224
+ exitCode: 0,
225
+ result: { seed: inputs.of, closure, byCatalogue },
226
+ };
227
+ }
228
+ //# sourceMappingURL=impact-run.js.map