@sdd-method/sdd-cli 1.1.0 → 1.3.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/lib/catalogue/aggregate.d.ts.map +1 -1
- package/dist/lib/catalogue/aggregate.js +5 -4
- package/dist/lib/catalogue/aggregate.js.map +1 -1
- package/dist/lib/catalogue/build.d.ts.map +1 -1
- package/dist/lib/catalogue/build.js +16 -7
- package/dist/lib/catalogue/build.js.map +1 -1
- package/dist/lib/catalogue/builders/capability-edges.d.ts.map +1 -1
- package/dist/lib/catalogue/builders/capability-edges.js +10 -1
- package/dist/lib/catalogue/builders/capability-edges.js.map +1 -1
- package/dist/lib/catalogue/builders/capability-spec.d.ts +9 -3
- package/dist/lib/catalogue/builders/capability-spec.d.ts.map +1 -1
- package/dist/lib/catalogue/builders/capability-spec.js +9 -3
- package/dist/lib/catalogue/builders/capability-spec.js.map +1 -1
- package/dist/lib/catalogue/builders/index.d.ts +2 -0
- package/dist/lib/catalogue/builders/index.d.ts.map +1 -1
- package/dist/lib/catalogue/builders/index.js +1 -0
- package/dist/lib/catalogue/builders/index.js.map +1 -1
- package/dist/lib/catalogue/builders/quality-scores.d.ts +14 -0
- package/dist/lib/catalogue/builders/quality-scores.d.ts.map +1 -0
- package/dist/lib/catalogue/builders/quality-scores.js +321 -0
- package/dist/lib/catalogue/builders/quality-scores.js.map +1 -0
- package/dist/lib/catalogue/builders/services.d.ts.map +1 -1
- package/dist/lib/catalogue/builders/services.js +5 -1
- package/dist/lib/catalogue/builders/services.js.map +1 -1
- package/dist/lib/catalogue/canonical-schema.yaml +255 -6
- package/dist/lib/catalogue/coverage-predicates.d.ts +176 -0
- package/dist/lib/catalogue/coverage-predicates.d.ts.map +1 -0
- package/dist/lib/catalogue/coverage-predicates.js +603 -0
- package/dist/lib/catalogue/coverage-predicates.js.map +1 -0
- package/dist/lib/catalogue/coverage-render.d.ts +54 -0
- package/dist/lib/catalogue/coverage-render.d.ts.map +1 -0
- package/dist/lib/catalogue/coverage-render.js +432 -0
- package/dist/lib/catalogue/coverage-render.js.map +1 -0
- package/dist/lib/catalogue/coverage-run.d.ts +33 -0
- package/dist/lib/catalogue/coverage-run.d.ts.map +1 -0
- package/dist/lib/catalogue/coverage-run.js +97 -0
- package/dist/lib/catalogue/coverage-run.js.map +1 -0
- package/dist/lib/catalogue/ddl-generator.d.ts +80 -0
- package/dist/lib/catalogue/ddl-generator.d.ts.map +1 -0
- package/dist/lib/catalogue/ddl-generator.js +215 -0
- package/dist/lib/catalogue/ddl-generator.js.map +1 -0
- package/dist/lib/catalogue/engine-validator.d.ts +103 -0
- package/dist/lib/catalogue/engine-validator.d.ts.map +1 -0
- package/dist/lib/catalogue/engine-validator.js +221 -0
- package/dist/lib/catalogue/engine-validator.js.map +1 -0
- package/dist/lib/catalogue/enum-validator.d.ts.map +1 -1
- package/dist/lib/catalogue/enum-validator.js +15 -0
- package/dist/lib/catalogue/enum-validator.js.map +1 -1
- package/dist/lib/catalogue/fk-validator.d.ts +6 -0
- package/dist/lib/catalogue/fk-validator.d.ts.map +1 -1
- package/dist/lib/catalogue/fk-validator.js +6 -0
- package/dist/lib/catalogue/fk-validator.js.map +1 -1
- package/dist/lib/catalogue/gate-checks.d.ts +117 -0
- package/dist/lib/catalogue/gate-checks.d.ts.map +1 -0
- package/dist/lib/catalogue/gate-checks.js +261 -0
- package/dist/lib/catalogue/gate-checks.js.map +1 -0
- package/dist/lib/catalogue/parity-harness.d.ts +48 -0
- package/dist/lib/catalogue/parity-harness.d.ts.map +1 -0
- package/dist/lib/catalogue/parity-harness.js +76 -0
- package/dist/lib/catalogue/parity-harness.js.map +1 -0
- package/dist/lib/catalogue/schema-compat.d.ts +3 -3
- package/dist/lib/catalogue/schema-compat.js +3 -3
- package/dist/lib/catalogue/scores-coverage.d.ts +138 -0
- package/dist/lib/catalogue/scores-coverage.d.ts.map +1 -0
- package/dist/lib/catalogue/scores-coverage.js +346 -0
- package/dist/lib/catalogue/scores-coverage.js.map +1 -0
- package/dist/lib/catalogue/validate.d.ts.map +1 -1
- package/dist/lib/catalogue/validate.js +6 -11
- package/dist/lib/catalogue/validate.js.map +1 -1
- package/dist/lib/mcp/parse/gate-registry.d.ts +63 -4
- package/dist/lib/mcp/parse/gate-registry.d.ts.map +1 -1
- package/dist/lib/mcp/parse/gate-registry.js +127 -31
- package/dist/lib/mcp/parse/gate-registry.js.map +1 -1
- package/dist/lib/mcp/resources/gates.d.ts.map +1 -1
- package/dist/lib/mcp/resources/gates.js +13 -27
- package/dist/lib/mcp/resources/gates.js.map +1 -1
- package/dist/lib/mcp/tools/query-gate-status.d.ts.map +1 -1
- package/dist/lib/mcp/tools/query-gate-status.js +13 -27
- package/dist/lib/mcp/tools/query-gate-status.js.map +1 -1
- package/dist/verbs/catalogue.d.ts.map +1 -1
- package/dist/verbs/catalogue.js +24 -0
- package/dist/verbs/catalogue.js.map +1 -1
- package/package.json +3 -2
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Coverage mode — `sdd-cli catalogue validate --coverage` (A4 CS-2).
|
|
3
|
+
*
|
|
4
|
+
* Runs the thirteen engine coverage predicates against a catalogues
|
|
5
|
+
* directory and prints EXACTLY the lines the reference shell scripts
|
|
6
|
+
* printed (coverage-render.ts holds the text contract), in a fixed block
|
|
7
|
+
* order: the four catalogue-classics (repo-capability, service-capability,
|
|
8
|
+
* event, contract), then the nine Phase-0 gate checks in the
|
|
9
|
+
* catalogue-integrity-gate's step order. Nothing else is written to
|
|
10
|
+
* stdout — the gate swaps N script invocations for one CLI call and the
|
|
11
|
+
* stream stays parseable by the same baseline machinery.
|
|
12
|
+
*
|
|
13
|
+
* Exit code is 0 in normal operation, exactly as the reference scripts:
|
|
14
|
+
* gating is the findings baseline's job, never this mode's. A classifier
|
|
15
|
+
* probe failure throws (the references exit 2).
|
|
16
|
+
*
|
|
17
|
+
* The one deliberately-unported check is check-repo-config-coverage.sh:
|
|
18
|
+
* it reads the AUTHORING surface, is text-shaped by design (A0's
|
|
19
|
+
* classification), and stays shell.
|
|
20
|
+
*/
|
|
21
|
+
import { existsSync } from "node:fs";
|
|
22
|
+
import { join, resolve } from "node:path";
|
|
23
|
+
import { readCatalogueCsv } from "./csv-reader.js";
|
|
24
|
+
import { createEngineSession } from "./engine-validator.js";
|
|
25
|
+
import { loadCanonicalSchema } from "./schema-loader.js";
|
|
26
|
+
import { runContractCoverage, runEventCoverage, runRepoCapabilityCoverage, runServiceCapabilityCoverage, } from "./coverage-predicates.js";
|
|
27
|
+
import { runCapabilityEventCheck, runDataModelEntitiesCheck, runEventCatalogueCheck, runFeatureEventCheck, runFeatureSpecPromotionCheck, runFeatureSurfaceDuplicationCheck, runGlossaryXrefCheck, runPlatformDependenciesCheck, runRepoEdgesCheck, } from "./gate-checks.js";
|
|
28
|
+
import { runScoresCoverage } from "./scores-coverage.js";
|
|
29
|
+
import { renderCapabilityEventCheck, renderContractCoverage, renderDataModelEntitiesCheck, renderEventCatalogueCheck, renderEventCoverage, renderFeatureEventCheck, renderFeatureSpecPromotionCheck, renderFeatureSurfaceDuplicationCheck, renderGlossaryXrefCheck, renderPlatformDependenciesCheck, renderRepoCapability, renderRepoEdgesCheck, renderScoresCoverage, renderServiceCapability, } from "./coverage-render.js";
|
|
30
|
+
export async function runCatalogueCoverage(inputs, write) {
|
|
31
|
+
const sddRoot = resolve(inputs.sddPath ?? process.cwd());
|
|
32
|
+
const dir = resolve(sddRoot, inputs.cataloguesDir ?? "catalogues");
|
|
33
|
+
const tier = inputs.tier ?? "member";
|
|
34
|
+
const schema = await loadCanonicalSchema();
|
|
35
|
+
const present = (name) => existsSync(join(dir, `${name}.csv`));
|
|
36
|
+
const rowsByCatalogue = new Map();
|
|
37
|
+
for (const cat of schema.catalogues) {
|
|
38
|
+
if (!present(cat.name))
|
|
39
|
+
continue;
|
|
40
|
+
const parsed = await readCatalogueCsv(join(dir, `${cat.name}.csv`));
|
|
41
|
+
rowsByCatalogue.set(cat.name, parsed.rows);
|
|
42
|
+
}
|
|
43
|
+
const session = await createEngineSession(schema, rowsByCatalogue);
|
|
44
|
+
const lines = [];
|
|
45
|
+
try {
|
|
46
|
+
// The four catalogue-classics, each anchored on its population file
|
|
47
|
+
// exactly as the reference scripts anchor (absent file → silent).
|
|
48
|
+
if (present("repositories")) {
|
|
49
|
+
const r = await runRepoCapabilityCoverage(session);
|
|
50
|
+
lines.push(...renderRepoCapability(r.findings, r.metrics));
|
|
51
|
+
}
|
|
52
|
+
if (present("services")) {
|
|
53
|
+
const r = await runServiceCapabilityCoverage(session, {
|
|
54
|
+
tier,
|
|
55
|
+
repoCapabilityAvailable: present("repo_capability"),
|
|
56
|
+
});
|
|
57
|
+
lines.push(...renderServiceCapability(r.findings, r.metrics, tier));
|
|
58
|
+
}
|
|
59
|
+
if (present("events")) {
|
|
60
|
+
const r = await runEventCoverage(session, { tier });
|
|
61
|
+
lines.push(...renderEventCoverage(r, tier));
|
|
62
|
+
}
|
|
63
|
+
if (present("contracts")) {
|
|
64
|
+
const r = await runContractCoverage(session, { tier, sddRoot });
|
|
65
|
+
lines.push(...renderContractCoverage(r, tier));
|
|
66
|
+
}
|
|
67
|
+
// The nine Phase-0 gate checks, in the gate's step order.
|
|
68
|
+
const eventCatalogue = await runEventCatalogueCheck(session, {
|
|
69
|
+
sddRoot,
|
|
70
|
+
eventsPresent: present("events"),
|
|
71
|
+
});
|
|
72
|
+
lines.push(...renderEventCatalogueCheck(eventCatalogue.gaps));
|
|
73
|
+
lines.push(...renderRepoEdgesCheck(await runRepoEdgesCheck(session, { sddRoot })));
|
|
74
|
+
lines.push(...renderGlossaryXrefCheck((await runGlossaryXrefCheck(session, {
|
|
75
|
+
sddRoot,
|
|
76
|
+
xrefPresent: present("glossary_xref"),
|
|
77
|
+
})).finding));
|
|
78
|
+
lines.push(...renderDataModelEntitiesCheck(await runDataModelEntitiesCheck(session)));
|
|
79
|
+
lines.push(...renderCapabilityEventCheck(await runCapabilityEventCheck(session)));
|
|
80
|
+
lines.push(...renderFeatureEventCheck(await runFeatureEventCheck(session)));
|
|
81
|
+
lines.push(...renderPlatformDependenciesCheck((await runPlatformDependenciesCheck(session, { sddRoot })).finding));
|
|
82
|
+
lines.push(...renderFeatureSpecPromotionCheck(await runFeatureSpecPromotionCheck(session)));
|
|
83
|
+
lines.push(...renderFeatureSurfaceDuplicationCheck(await runFeatureSurfaceDuplicationCheck(session)));
|
|
84
|
+
// The fourteenth check (M-ADR 0205 §4.5, Phase B): every eligible artefact
|
|
85
|
+
// carries a current score. Last in the block order because it is the newest
|
|
86
|
+
// and the baselines hold the stream positionally-agnostic but ordered.
|
|
87
|
+
const available = new Set(schema.catalogues.map((c) => c.name).filter((n) => present(n)));
|
|
88
|
+
lines.push(...renderScoresCoverage(await runScoresCoverage(session, { tier, available, sddRoot }), tier));
|
|
89
|
+
}
|
|
90
|
+
finally {
|
|
91
|
+
session.dispose();
|
|
92
|
+
}
|
|
93
|
+
for (const line of lines)
|
|
94
|
+
write(`${line}\n`);
|
|
95
|
+
return { exitCode: 0 };
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=coverage-run.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coverage-run.js","sourceRoot":"","sources":["../../../src/lib/catalogue/coverage-run.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Schema→DDL generator — M-ADR 0205 §4.3 (engine-evolution Phase A1).
|
|
3
|
+
*
|
|
4
|
+
* Emits, from the loaded canonical schema:
|
|
5
|
+
* (a) CREATE TABLE DDL for every declared catalogue, typed per the
|
|
6
|
+
* schema's column types; and
|
|
7
|
+
* (b) a deterministic list of constraint-violation queries (fk | pk |
|
|
8
|
+
* enum) whose row semantics mirror fk-validator.ts and
|
|
9
|
+
* enum-validator.ts EXACTLY — the Phase A2 dual-run comparison
|
|
10
|
+
* (old path vs engine path, count AND list) depends on that
|
|
11
|
+
* equivalence, so any semantic change here must change there too:
|
|
12
|
+
* - fk: a required (non-nullable, non-external) FK fails when
|
|
13
|
+
* empty; a non-empty value must resolve against the target
|
|
14
|
+
* catalogue's primary keys unless the FK is effective-external
|
|
15
|
+
* (declared `external`, or external for the build's profile via
|
|
16
|
+
* `externalForProfiles`) — mirroring FkValidationOptions.
|
|
17
|
+
* - pk: duplicate non-empty primary-key values.
|
|
18
|
+
* - enum: a non-empty (trimmed) bound-column value outside the
|
|
19
|
+
* bound enum's declared set. Emptiness is nullability's concern,
|
|
20
|
+
* not the enum's, exactly as in enum-validator.ts.
|
|
21
|
+
*
|
|
22
|
+
* Determinism per M-ADR 0205 §4.2: emission order is the schema's own
|
|
23
|
+
* declaration order; every query carries a total ORDER BY.
|
|
24
|
+
*
|
|
25
|
+
* Digest coupling per §4.3 is inherited, not re-implemented: this module
|
|
26
|
+
* reads the schema through loadCanonicalSchema, and the vendored copy it
|
|
27
|
+
* loads is guarded by canonical-schema-drift.test.ts.
|
|
28
|
+
*
|
|
29
|
+
* There is NO hand-maintained DDL anywhere: an unknown column type or a
|
|
30
|
+
* binding to an unknown enum throws at generation time — loud, never a
|
|
31
|
+
* silent fallback (the known*Ids.has() lesson).
|
|
32
|
+
*/
|
|
33
|
+
import type { CanonicalSchema, ForeignKeyDef } from "./schema-loader.js";
|
|
34
|
+
import type { FkValidationOptions } from "./fk-validator.js";
|
|
35
|
+
/** Engine type for a schema column type; throws on an unmapped type. */
|
|
36
|
+
export declare function sqlType(catalogue: string, column: string, type: string): string;
|
|
37
|
+
/**
|
|
38
|
+
* The one definition of effective-external, shared with the engine
|
|
39
|
+
* validator so the three consumers (fk-validator.ts, the query generator,
|
|
40
|
+
* engine-validator.ts) cannot drift: declared `external`, or external for
|
|
41
|
+
* the build's profile via `externalForProfiles`.
|
|
42
|
+
*/
|
|
43
|
+
export declare function isEffectiveExternal(fk: ForeignKeyDef, options: FkValidationOptions): boolean;
|
|
44
|
+
/**
|
|
45
|
+
* One CREATE TABLE statement per catalogue, in schema declaration order.
|
|
46
|
+
* Plain typed columns only: enforcement of PK/FK/enum semantics lives in
|
|
47
|
+
* the violation queries, whose findings-shaped output (never a load
|
|
48
|
+
* abort) is what the validators' exit contracts need.
|
|
49
|
+
*/
|
|
50
|
+
export declare function generateTableDdl(schema: CanonicalSchema): readonly string[];
|
|
51
|
+
export type ConstraintKind = "fk" | "pk" | "enum";
|
|
52
|
+
export interface ConstraintQuery {
|
|
53
|
+
readonly catalogue: string;
|
|
54
|
+
readonly kind: ConstraintKind;
|
|
55
|
+
/** The constrained column (fk/enum) or the primary-key column (pk). */
|
|
56
|
+
readonly column: string;
|
|
57
|
+
/** For fk: the "{catalogue}.{column}" target. For enum: the enum name. */
|
|
58
|
+
readonly target?: string;
|
|
59
|
+
/**
|
|
60
|
+
* SELECT returning one row per violation with a total ORDER BY.
|
|
61
|
+
* fk/enum rows: (row_pk, value). pk rows: (row_pk, n).
|
|
62
|
+
*/
|
|
63
|
+
readonly sql: string;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* The violation-query set for a schema, mirroring the in-memory
|
|
67
|
+
* validators' semantics under the same options they take.
|
|
68
|
+
*/
|
|
69
|
+
export declare function generateConstraintQueries(schema: CanonicalSchema, options?: FkValidationOptions): readonly ConstraintQuery[];
|
|
70
|
+
/**
|
|
71
|
+
* Dangling-value queries for the FKs the main set SKIPS as
|
|
72
|
+
* effective-external — one query per skipped FK, returning the rows the
|
|
73
|
+
* in-memory path logs as `[finding] external` (unresolved non-empty
|
|
74
|
+
* values; resolution happens at aggregation). Empty when
|
|
75
|
+
* treatExternalAsInternal is set, exactly as the main set then skips
|
|
76
|
+
* nothing. Kept separate from generateConstraintQueries because these
|
|
77
|
+
* rows are FINDINGS, not failures — the exit contracts differ.
|
|
78
|
+
*/
|
|
79
|
+
export declare function generateExternalFindingQueries(schema: CanonicalSchema, options?: FkValidationOptions): readonly ConstraintQuery[];
|
|
80
|
+
//# sourceMappingURL=ddl-generator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ddl-generator.d.ts","sourceRoot":"","sources":["../../../src/lib/catalogue/ddl-generator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,KAAK,EACV,eAAe,EAEf,aAAa,EACd,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAY7D,wEAAwE;AACxE,wBAAgB,OAAO,CACrB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,GACX,MAAM,CAQR;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,EAAE,EAAE,aAAa,EACjB,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAMT;AAeD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,eAAe,GAAG,SAAS,MAAM,EAAE,CAO3E;AAED,MAAM,MAAM,cAAc,GAAG,IAAI,GAAG,IAAI,GAAG,MAAM,CAAC;AAElD,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;IAC9B,uEAAuE;IACvE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,0EAA0E;IAC1E,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB;;;OAGG;IACH,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,eAAe,EACvB,OAAO,GAAE,mBAAwB,GAChC,SAAS,eAAe,EAAE,CA8F5B;AAED;;;;;;;;GAQG;AACH,wBAAgB,8BAA8B,CAC5C,MAAM,EAAE,eAAe,EACvB,OAAO,GAAE,mBAAwB,GAChC,SAAS,eAAe,EAAE,CA6B5B"}
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Schema→DDL generator — M-ADR 0205 §4.3 (engine-evolution Phase A1).
|
|
3
|
+
*
|
|
4
|
+
* Emits, from the loaded canonical schema:
|
|
5
|
+
* (a) CREATE TABLE DDL for every declared catalogue, typed per the
|
|
6
|
+
* schema's column types; and
|
|
7
|
+
* (b) a deterministic list of constraint-violation queries (fk | pk |
|
|
8
|
+
* enum) whose row semantics mirror fk-validator.ts and
|
|
9
|
+
* enum-validator.ts EXACTLY — the Phase A2 dual-run comparison
|
|
10
|
+
* (old path vs engine path, count AND list) depends on that
|
|
11
|
+
* equivalence, so any semantic change here must change there too:
|
|
12
|
+
* - fk: a required (non-nullable, non-external) FK fails when
|
|
13
|
+
* empty; a non-empty value must resolve against the target
|
|
14
|
+
* catalogue's primary keys unless the FK is effective-external
|
|
15
|
+
* (declared `external`, or external for the build's profile via
|
|
16
|
+
* `externalForProfiles`) — mirroring FkValidationOptions.
|
|
17
|
+
* - pk: duplicate non-empty primary-key values.
|
|
18
|
+
* - enum: a non-empty (trimmed) bound-column value outside the
|
|
19
|
+
* bound enum's declared set. Emptiness is nullability's concern,
|
|
20
|
+
* not the enum's, exactly as in enum-validator.ts.
|
|
21
|
+
*
|
|
22
|
+
* Determinism per M-ADR 0205 §4.2: emission order is the schema's own
|
|
23
|
+
* declaration order; every query carries a total ORDER BY.
|
|
24
|
+
*
|
|
25
|
+
* Digest coupling per §4.3 is inherited, not re-implemented: this module
|
|
26
|
+
* reads the schema through loadCanonicalSchema, and the vendored copy it
|
|
27
|
+
* loads is guarded by canonical-schema-drift.test.ts.
|
|
28
|
+
*
|
|
29
|
+
* There is NO hand-maintained DDL anywhere: an unknown column type or a
|
|
30
|
+
* binding to an unknown enum throws at generation time — loud, never a
|
|
31
|
+
* silent fallback (the known*Ids.has() lesson).
|
|
32
|
+
*/
|
|
33
|
+
/** Closed map from schema column types to engine column types. */
|
|
34
|
+
const TYPE_MAP = {
|
|
35
|
+
string: "VARCHAR",
|
|
36
|
+
int: "INTEGER",
|
|
37
|
+
integer: "INTEGER",
|
|
38
|
+
number: "DOUBLE",
|
|
39
|
+
date: "DATE",
|
|
40
|
+
boolean: "BOOLEAN",
|
|
41
|
+
};
|
|
42
|
+
/** Engine type for a schema column type; throws on an unmapped type. */
|
|
43
|
+
export function sqlType(catalogue, column, type) {
|
|
44
|
+
const mapped = TYPE_MAP[type];
|
|
45
|
+
if (!mapped) {
|
|
46
|
+
throw new Error(`ddl-generator: ${catalogue}.${column} declares unmapped column type "${type}" — extend TYPE_MAP deliberately, never default`);
|
|
47
|
+
}
|
|
48
|
+
return mapped;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* The one definition of effective-external, shared with the engine
|
|
52
|
+
* validator so the three consumers (fk-validator.ts, the query generator,
|
|
53
|
+
* engine-validator.ts) cannot drift: declared `external`, or external for
|
|
54
|
+
* the build's profile via `externalForProfiles`.
|
|
55
|
+
*/
|
|
56
|
+
export function isEffectiveExternal(fk, options) {
|
|
57
|
+
return (fk.external ||
|
|
58
|
+
(options.profile !== undefined &&
|
|
59
|
+
(fk.externalForProfiles ?? []).includes(options.profile)));
|
|
60
|
+
}
|
|
61
|
+
function quote(identifier) {
|
|
62
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(identifier)) {
|
|
63
|
+
throw new Error(`ddl-generator: identifier "${identifier}" is outside the schema's naming form — refusing to interpolate it into SQL`);
|
|
64
|
+
}
|
|
65
|
+
return `"${identifier}"`;
|
|
66
|
+
}
|
|
67
|
+
function sqlStringLiteral(value) {
|
|
68
|
+
return `'${value.replace(/'/g, "''")}'`;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* One CREATE TABLE statement per catalogue, in schema declaration order.
|
|
72
|
+
* Plain typed columns only: enforcement of PK/FK/enum semantics lives in
|
|
73
|
+
* the violation queries, whose findings-shaped output (never a load
|
|
74
|
+
* abort) is what the validators' exit contracts need.
|
|
75
|
+
*/
|
|
76
|
+
export function generateTableDdl(schema) {
|
|
77
|
+
return schema.catalogues.map((cat) => {
|
|
78
|
+
const cols = cat.columns
|
|
79
|
+
.map((c) => ` ${quote(c.name)} ${sqlType(cat.name, c.name, c.type)}`)
|
|
80
|
+
.join(",\n");
|
|
81
|
+
return `CREATE TABLE ${quote(cat.name)} (\n${cols}\n);`;
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* The violation-query set for a schema, mirroring the in-memory
|
|
86
|
+
* validators' semantics under the same options they take.
|
|
87
|
+
*/
|
|
88
|
+
export function generateConstraintQueries(schema, options = {}) {
|
|
89
|
+
const catalogueNames = new Set(schema.catalogues.map((c) => c.name));
|
|
90
|
+
const queries = [];
|
|
91
|
+
for (const cat of schema.catalogues) {
|
|
92
|
+
queries.push(pkQuery(cat));
|
|
93
|
+
for (const fk of cat.foreignKeys) {
|
|
94
|
+
const [targetCat, targetCol] = fk.references.split(".");
|
|
95
|
+
if (!targetCat || !targetCol) {
|
|
96
|
+
throw new Error(`ddl-generator: malformed FK reference "${fk.references}" on ${cat.name}.${fk.column}`);
|
|
97
|
+
}
|
|
98
|
+
if (!catalogueNames.has(targetCat)) {
|
|
99
|
+
throw new Error(`ddl-generator: FK ${cat.name}.${fk.column} references unknown catalogue "${targetCat}"`);
|
|
100
|
+
}
|
|
101
|
+
if (!cat.columns.some((c) => c.name === fk.column)) {
|
|
102
|
+
throw new Error(`ddl-generator: FK column ${cat.name}.${fk.column} is not a declared column — the schema 3.1.3 vacuous-binding class`);
|
|
103
|
+
}
|
|
104
|
+
const effectiveExternal = isEffectiveExternal(fk, options);
|
|
105
|
+
// Mirrors fk-validator.ts exactly: the required-empty clause is keyed
|
|
106
|
+
// on the DECLARED external flag; the dangling clause is keyed on
|
|
107
|
+
// effective-external (unless the aggregator asks for internal
|
|
108
|
+
// treatment).
|
|
109
|
+
const checkEmpty = !fk.nullable && !fk.external;
|
|
110
|
+
const checkDangling = !effectiveExternal || options.treatExternalAsInternal === true;
|
|
111
|
+
if (!checkEmpty && !checkDangling)
|
|
112
|
+
continue;
|
|
113
|
+
const t = quote(cat.name);
|
|
114
|
+
const col = quote(fk.column);
|
|
115
|
+
const pk = quote(cat.primaryKey);
|
|
116
|
+
const clauses = [];
|
|
117
|
+
if (checkEmpty) {
|
|
118
|
+
clauses.push(`(t.${col} IS NULL OR t.${col} = '')`);
|
|
119
|
+
}
|
|
120
|
+
if (checkDangling) {
|
|
121
|
+
clauses.push(`(t.${col} IS NOT NULL AND t.${col} <> '' AND NOT EXISTS (` +
|
|
122
|
+
`SELECT 1 FROM ${quote(targetCat)} r WHERE r.${quote(targetCol)} = t.${col}))`);
|
|
123
|
+
}
|
|
124
|
+
queries.push({
|
|
125
|
+
catalogue: cat.name,
|
|
126
|
+
kind: "fk",
|
|
127
|
+
column: fk.column,
|
|
128
|
+
target: fk.references,
|
|
129
|
+
sql: `SELECT t.${pk} AS row_pk, COALESCE(t.${col}, '') AS value FROM ${t} t ` +
|
|
130
|
+
`WHERE ${clauses.join(" OR ")} ORDER BY row_pk, value;`,
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
for (const [column, enumRef] of Object.entries(cat.columnEnums)) {
|
|
134
|
+
const enumName = enumRef.replace(/^enums\./, "");
|
|
135
|
+
const enumDef = schema.enums[enumName];
|
|
136
|
+
if (!enumDef) {
|
|
137
|
+
throw new Error(`ddl-generator: ${cat.name}.${column} binds unknown enum "${enumRef}" — a binding that names no enum must not validate as vacuously true`);
|
|
138
|
+
}
|
|
139
|
+
if (!cat.columns.some((c) => c.name === column)) {
|
|
140
|
+
throw new Error(`ddl-generator: ${cat.name}.${column} binds a column the catalogue does not declare — the schema 3.1.3 vacuous-binding class`);
|
|
141
|
+
}
|
|
142
|
+
const allowed = enumDef.values
|
|
143
|
+
.map((v) => sqlStringLiteral(v.value))
|
|
144
|
+
.join(", ");
|
|
145
|
+
const t = quote(cat.name);
|
|
146
|
+
const col = quote(column);
|
|
147
|
+
const pk = quote(cat.primaryKey);
|
|
148
|
+
queries.push({
|
|
149
|
+
catalogue: cat.name,
|
|
150
|
+
kind: "enum",
|
|
151
|
+
column,
|
|
152
|
+
target: enumName,
|
|
153
|
+
sql:
|
|
154
|
+
// TRIM in the projection too: enum-validator.ts records the
|
|
155
|
+
// TRIMMED value in its violation objects, and A2's count-and-list
|
|
156
|
+
// parity compares those objects field-for-field.
|
|
157
|
+
`SELECT t.${pk} AS row_pk, TRIM(t.${col}) AS value FROM ${t} t ` +
|
|
158
|
+
`WHERE t.${col} IS NOT NULL AND TRIM(t.${col}) <> '' ` +
|
|
159
|
+
`AND TRIM(t.${col}) NOT IN (${allowed}) ORDER BY row_pk, value;`,
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return queries;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Dangling-value queries for the FKs the main set SKIPS as
|
|
167
|
+
* effective-external — one query per skipped FK, returning the rows the
|
|
168
|
+
* in-memory path logs as `[finding] external` (unresolved non-empty
|
|
169
|
+
* values; resolution happens at aggregation). Empty when
|
|
170
|
+
* treatExternalAsInternal is set, exactly as the main set then skips
|
|
171
|
+
* nothing. Kept separate from generateConstraintQueries because these
|
|
172
|
+
* rows are FINDINGS, not failures — the exit contracts differ.
|
|
173
|
+
*/
|
|
174
|
+
export function generateExternalFindingQueries(schema, options = {}) {
|
|
175
|
+
if (options.treatExternalAsInternal === true)
|
|
176
|
+
return [];
|
|
177
|
+
const queries = [];
|
|
178
|
+
for (const cat of schema.catalogues) {
|
|
179
|
+
for (const fk of cat.foreignKeys) {
|
|
180
|
+
if (!isEffectiveExternal(fk, options))
|
|
181
|
+
continue;
|
|
182
|
+
const [targetCat, targetCol] = fk.references.split(".");
|
|
183
|
+
if (!targetCat || !targetCol) {
|
|
184
|
+
throw new Error(`ddl-generator: malformed FK reference "${fk.references}" on ${cat.name}.${fk.column}`);
|
|
185
|
+
}
|
|
186
|
+
const t = quote(cat.name);
|
|
187
|
+
const col = quote(fk.column);
|
|
188
|
+
const pk = quote(cat.primaryKey);
|
|
189
|
+
queries.push({
|
|
190
|
+
catalogue: cat.name,
|
|
191
|
+
kind: "fk",
|
|
192
|
+
column: fk.column,
|
|
193
|
+
target: fk.references,
|
|
194
|
+
sql: `SELECT t.${pk} AS row_pk, t.${col} AS value FROM ${t} t ` +
|
|
195
|
+
`WHERE t.${col} IS NOT NULL AND t.${col} <> '' AND NOT EXISTS (` +
|
|
196
|
+
`SELECT 1 FROM ${quote(targetCat)} r WHERE r.${quote(targetCol)} = t.${col}) ` +
|
|
197
|
+
`ORDER BY row_pk, value;`,
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return queries;
|
|
202
|
+
}
|
|
203
|
+
function pkQuery(cat) {
|
|
204
|
+
const t = quote(cat.name);
|
|
205
|
+
const pk = quote(cat.primaryKey);
|
|
206
|
+
return {
|
|
207
|
+
catalogue: cat.name,
|
|
208
|
+
kind: "pk",
|
|
209
|
+
column: cat.primaryKey,
|
|
210
|
+
sql: `SELECT ${pk} AS row_pk, COUNT(*) AS n FROM ${t} ` +
|
|
211
|
+
`WHERE ${pk} IS NOT NULL AND ${pk} <> '' ` +
|
|
212
|
+
`GROUP BY ${pk} HAVING COUNT(*) > 1 ORDER BY row_pk;`,
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
//# sourceMappingURL=ddl-generator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ddl-generator.js","sourceRoot":"","sources":["../../../src/lib/catalogue/ddl-generator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Engine-path FK/PK/enum validation — M-ADR 0205 §4.4 (Phase A2).
|
|
3
|
+
*
|
|
4
|
+
* Runs the ddl-generator's queries on the embedded engine and returns
|
|
5
|
+
* results in the SAME shapes as fk-validator.ts / enum-validator.ts, so
|
|
6
|
+
* the parity harness can compare count AND list, field for field. The
|
|
7
|
+
* input is the same rowsByCatalogue map the in-memory validators take:
|
|
8
|
+
* A2 compares the two VALIDATION implementations on identical parsed
|
|
9
|
+
* input — CSV-read equivalence is deliberately out of this comparison's
|
|
10
|
+
* scope and belongs to the cutover evaluation.
|
|
11
|
+
*
|
|
12
|
+
* The engine package is a devDependency until cutover (M-ADR 0205 §4.1's
|
|
13
|
+
* no-fallback rule governs how it eventually ships). It is imported
|
|
14
|
+
* dynamically inside the entry function so merely loading this module
|
|
15
|
+
* never requires it: no production path imports the engine today, and an
|
|
16
|
+
* adopter install without the package only fails if something actually
|
|
17
|
+
* calls it — loudly.
|
|
18
|
+
*
|
|
19
|
+
* PK-duplicate detection has NO in-memory counterpart at validate time
|
|
20
|
+
* (builders dedupe at emission instead), so pkDuplicates is engine-only
|
|
21
|
+
* information: reported, never part of the parity claim — you cannot
|
|
22
|
+
* claim agreement with an instrument that does not exist.
|
|
23
|
+
*/
|
|
24
|
+
import type { CanonicalSchema } from "./schema-loader.js";
|
|
25
|
+
import type { CatalogueRow } from "./csv-writer.js";
|
|
26
|
+
import type { FindingsLog } from "./findings.js";
|
|
27
|
+
import type { FkValidationOptions, FkValidationResult } from "./fk-validator.js";
|
|
28
|
+
import type { EnumValidationResult } from "./enum-validator.js";
|
|
29
|
+
export interface PkDuplicate {
|
|
30
|
+
readonly catalogue: string;
|
|
31
|
+
readonly rowPk: string;
|
|
32
|
+
readonly count: number;
|
|
33
|
+
}
|
|
34
|
+
export interface TypeNonconformance {
|
|
35
|
+
readonly catalogue: string;
|
|
36
|
+
readonly column: string;
|
|
37
|
+
readonly declaredType: string;
|
|
38
|
+
readonly value: string;
|
|
39
|
+
readonly rows: number;
|
|
40
|
+
}
|
|
41
|
+
export interface ExternalFindingDetail {
|
|
42
|
+
readonly catalogue: string;
|
|
43
|
+
readonly column: string;
|
|
44
|
+
readonly target: string;
|
|
45
|
+
/** Display-ready: "?" when the referencing row has a NULL primary key. */
|
|
46
|
+
readonly rowPk: string;
|
|
47
|
+
readonly value: string;
|
|
48
|
+
}
|
|
49
|
+
export interface EngineValidationResult {
|
|
50
|
+
readonly fk: FkValidationResult;
|
|
51
|
+
readonly enums: EnumValidationResult;
|
|
52
|
+
/** One entry per unresolved value on an effective-external FK — the rows behind fk.externalFindings. */
|
|
53
|
+
readonly externalFindingDetails: readonly ExternalFindingDetail[];
|
|
54
|
+
/** Engine-only: no in-memory counterpart exists at validate time. */
|
|
55
|
+
readonly pkDuplicates: readonly PkDuplicate[];
|
|
56
|
+
/**
|
|
57
|
+
* Engine-only: non-empty values in typed (non-string) columns the engine
|
|
58
|
+
* cannot read as the declared type. The load uses TRY_CAST so one such
|
|
59
|
+
* cell cannot abort a whole run, but the miss is REPORTED, never
|
|
60
|
+
* smoothed — the in-memory path types nothing, so this class was
|
|
61
|
+
* invisible before the engine existed. Outside the parity claim: the
|
|
62
|
+
* compared validators only read string columns.
|
|
63
|
+
*/
|
|
64
|
+
readonly typeNonconformances: readonly TypeNonconformance[];
|
|
65
|
+
}
|
|
66
|
+
export interface EngineConnection {
|
|
67
|
+
run(sql: string): Promise<unknown>;
|
|
68
|
+
runAndReadAll(sql: string): Promise<{
|
|
69
|
+
getRows(): unknown[][];
|
|
70
|
+
}>;
|
|
71
|
+
}
|
|
72
|
+
export interface EngineSession {
|
|
73
|
+
readonly conn: EngineConnection;
|
|
74
|
+
dispose(): void;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* One loaded engine: schema DDL applied, every provided catalogue's rows
|
|
78
|
+
* inserted. Shared by the FK/PK/enum path and the coverage predicates so
|
|
79
|
+
* there is exactly one load semantics to reason about.
|
|
80
|
+
*/
|
|
81
|
+
export declare function createEngineSession(schema: CanonicalSchema, rowsByCatalogue: ReadonlyMap<string, readonly CatalogueRow[]>): Promise<EngineSession>;
|
|
82
|
+
export declare function validateWithEngine(schema: CanonicalSchema, rowsByCatalogue: ReadonlyMap<string, readonly CatalogueRow[]>, options?: FkValidationOptions): Promise<EngineValidationResult>;
|
|
83
|
+
/**
|
|
84
|
+
* The A4 cutover surface: runs the engine validation and writes findings
|
|
85
|
+
* into the caller's FindingsLog with BYTE-IDENTICAL text to what
|
|
86
|
+
* fk-validator.ts / enum-validator.ts wrote — adopters' committed
|
|
87
|
+
* findings baselines hold those literal lines, so the text is a
|
|
88
|
+
* compatibility contract, not a style choice. Line ORDER within a
|
|
89
|
+
* category follows the engine's total ORDER BY (M-ADR 0205 §4.2) and may
|
|
90
|
+
* differ from the old file-order rendering; baselines compare by
|
|
91
|
+
* membership, so ordering is free — declared in the change-set anyway.
|
|
92
|
+
*/
|
|
93
|
+
export declare function validateWithEngineToLog(schema: CanonicalSchema, rowsByCatalogue: ReadonlyMap<string, readonly CatalogueRow[]>, findings: FindingsLog, options?: FkValidationOptions, extras?: {
|
|
94
|
+
/**
|
|
95
|
+
* False at the aggregation tier, which has never emitted enum
|
|
96
|
+
* findings — the cutover changes no tier's finding surface.
|
|
97
|
+
*/
|
|
98
|
+
readonly logEnumFindings?: boolean;
|
|
99
|
+
}): Promise<{
|
|
100
|
+
fk: FkValidationResult;
|
|
101
|
+
enums: EnumValidationResult;
|
|
102
|
+
}>;
|
|
103
|
+
//# sourceMappingURL=engine-validator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine-validator.d.ts","sourceRoot":"","sources":["../../../src/lib/catalogue/engine-validator.ts"],"names":[],"mappings":"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"}
|