@sdd-method/sdd-cli 1.0.1 → 1.2.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 (118) hide show
  1. package/dist/lib/catalogue/aggregate.d.ts.map +1 -1
  2. package/dist/lib/catalogue/aggregate.js +116 -8
  3. package/dist/lib/catalogue/aggregate.js.map +1 -1
  4. package/dist/lib/catalogue/build.d.ts.map +1 -1
  5. package/dist/lib/catalogue/build.js +2 -6
  6. package/dist/lib/catalogue/build.js.map +1 -1
  7. package/dist/lib/catalogue/builders/capability-spec.d.ts +9 -3
  8. package/dist/lib/catalogue/builders/capability-spec.d.ts.map +1 -1
  9. package/dist/lib/catalogue/builders/capability-spec.js +9 -3
  10. package/dist/lib/catalogue/builders/capability-spec.js.map +1 -1
  11. package/dist/lib/catalogue/builders/external-system-exemption.d.ts.map +1 -1
  12. package/dist/lib/catalogue/builders/external-system-exemption.js +32 -3
  13. package/dist/lib/catalogue/builders/external-system-exemption.js.map +1 -1
  14. package/dist/lib/catalogue/builders/product-edges.d.ts.map +1 -1
  15. package/dist/lib/catalogue/builders/product-edges.js +9 -0
  16. package/dist/lib/catalogue/builders/product-edges.js.map +1 -1
  17. package/dist/lib/catalogue/builders/product-platform-dependencies.d.ts +12 -0
  18. package/dist/lib/catalogue/builders/product-platform-dependencies.d.ts.map +1 -1
  19. package/dist/lib/catalogue/builders/product-platform-dependencies.js +99 -0
  20. package/dist/lib/catalogue/builders/product-platform-dependencies.js.map +1 -1
  21. package/dist/lib/catalogue/canonical-schema.yaml +64 -11
  22. package/dist/lib/catalogue/contract-path-resolution.d.ts +55 -0
  23. package/dist/lib/catalogue/contract-path-resolution.d.ts.map +1 -0
  24. package/dist/lib/catalogue/contract-path-resolution.js +149 -0
  25. package/dist/lib/catalogue/contract-path-resolution.js.map +1 -0
  26. package/dist/lib/catalogue/coverage-predicates.d.ts +176 -0
  27. package/dist/lib/catalogue/coverage-predicates.d.ts.map +1 -0
  28. package/dist/lib/catalogue/coverage-predicates.js +603 -0
  29. package/dist/lib/catalogue/coverage-predicates.js.map +1 -0
  30. package/dist/lib/catalogue/coverage-render.d.ts +39 -0
  31. package/dist/lib/catalogue/coverage-render.d.ts.map +1 -0
  32. package/dist/lib/catalogue/coverage-render.js +347 -0
  33. package/dist/lib/catalogue/coverage-render.js.map +1 -0
  34. package/dist/lib/catalogue/coverage-run.d.ts +33 -0
  35. package/dist/lib/catalogue/coverage-run.d.ts.map +1 -0
  36. package/dist/lib/catalogue/coverage-run.js +91 -0
  37. package/dist/lib/catalogue/coverage-run.js.map +1 -0
  38. package/dist/lib/catalogue/ddl-generator.d.ts +80 -0
  39. package/dist/lib/catalogue/ddl-generator.d.ts.map +1 -0
  40. package/dist/lib/catalogue/ddl-generator.js +215 -0
  41. package/dist/lib/catalogue/ddl-generator.js.map +1 -0
  42. package/dist/lib/catalogue/engine-validator.d.ts +103 -0
  43. package/dist/lib/catalogue/engine-validator.d.ts.map +1 -0
  44. package/dist/lib/catalogue/engine-validator.js +221 -0
  45. package/dist/lib/catalogue/engine-validator.js.map +1 -0
  46. package/dist/lib/catalogue/enum-validator.d.ts.map +1 -1
  47. package/dist/lib/catalogue/enum-validator.js +15 -0
  48. package/dist/lib/catalogue/enum-validator.js.map +1 -1
  49. package/dist/lib/catalogue/fk-validator.d.ts +6 -0
  50. package/dist/lib/catalogue/fk-validator.d.ts.map +1 -1
  51. package/dist/lib/catalogue/fk-validator.js +6 -0
  52. package/dist/lib/catalogue/fk-validator.js.map +1 -1
  53. package/dist/lib/catalogue/gate-checks.d.ts +117 -0
  54. package/dist/lib/catalogue/gate-checks.d.ts.map +1 -0
  55. package/dist/lib/catalogue/gate-checks.js +261 -0
  56. package/dist/lib/catalogue/gate-checks.js.map +1 -0
  57. package/dist/lib/catalogue/parity-harness.d.ts +48 -0
  58. package/dist/lib/catalogue/parity-harness.d.ts.map +1 -0
  59. package/dist/lib/catalogue/parity-harness.js +76 -0
  60. package/dist/lib/catalogue/parity-harness.js.map +1 -0
  61. package/dist/lib/catalogue/schema-compat.d.ts +3 -3
  62. package/dist/lib/catalogue/schema-compat.js +3 -3
  63. package/dist/lib/catalogue/validate.d.ts.map +1 -1
  64. package/dist/lib/catalogue/validate.js +6 -11
  65. package/dist/lib/catalogue/validate.js.map +1 -1
  66. package/dist/lib/sync/apply.d.ts +29 -1
  67. package/dist/lib/sync/apply.d.ts.map +1 -1
  68. package/dist/lib/sync/apply.js +77 -2
  69. package/dist/lib/sync/apply.js.map +1 -1
  70. package/dist/lib/sync/index.d.ts.map +1 -1
  71. package/dist/lib/sync/index.js +23 -1
  72. package/dist/lib/sync/index.js.map +1 -1
  73. package/dist/lib/sync/settings-merge.d.ts +29 -0
  74. package/dist/lib/sync/settings-merge.d.ts.map +1 -1
  75. package/dist/lib/sync/settings-merge.js +31 -0
  76. package/dist/lib/sync/settings-merge.js.map +1 -1
  77. package/dist/lib/validate/dispatch.d.ts.map +1 -1
  78. package/dist/lib/validate/dispatch.js +19 -17
  79. package/dist/lib/validate/dispatch.js.map +1 -1
  80. package/dist/lib/validate/index.d.ts.map +1 -1
  81. package/dist/lib/validate/index.js +23 -4
  82. package/dist/lib/validate/index.js.map +1 -1
  83. package/dist/verbs/catalogue.d.ts.map +1 -1
  84. package/dist/verbs/catalogue.js +24 -0
  85. package/dist/verbs/catalogue.js.map +1 -1
  86. package/dist/verbs/conformance.d.ts.map +1 -1
  87. package/dist/verbs/conformance.js +3 -2
  88. package/dist/verbs/conformance.js.map +1 -1
  89. package/dist/verbs/contracts.d.ts.map +1 -1
  90. package/dist/verbs/contracts.js +3 -2
  91. package/dist/verbs/contracts.js.map +1 -1
  92. package/dist/verbs/generate-briefing.d.ts.map +1 -1
  93. package/dist/verbs/generate-briefing.js +2 -1
  94. package/dist/verbs/generate-briefing.js.map +1 -1
  95. package/dist/verbs/init.d.ts.map +1 -1
  96. package/dist/verbs/init.js +3 -2
  97. package/dist/verbs/init.js.map +1 -1
  98. package/dist/verbs/pack.d.ts.map +1 -1
  99. package/dist/verbs/pack.js +2 -1
  100. package/dist/verbs/pack.js.map +1 -1
  101. package/dist/verbs/path-option.d.ts +22 -0
  102. package/dist/verbs/path-option.d.ts.map +1 -0
  103. package/dist/verbs/path-option.js +25 -0
  104. package/dist/verbs/path-option.js.map +1 -0
  105. package/dist/verbs/plan.d.ts.map +1 -1
  106. package/dist/verbs/plan.js +2 -1
  107. package/dist/verbs/plan.js.map +1 -1
  108. package/dist/verbs/scaffold.d.ts.map +1 -1
  109. package/dist/verbs/scaffold.js +2 -1
  110. package/dist/verbs/scaffold.js.map +1 -1
  111. package/dist/verbs/sync.d.ts.map +1 -1
  112. package/dist/verbs/sync.js +2 -1
  113. package/dist/verbs/sync.js.map +1 -1
  114. package/dist/verbs/validate.d.ts.map +1 -1
  115. package/dist/verbs/validate.js +3 -2
  116. package/dist/verbs/validate.js.map +1 -1
  117. package/package.json +3 -2
  118. package/scripts/validate-app-dependencies.sh +378 -58
@@ -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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"}
@@ -0,0 +1,221 @@
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 { generateConstraintQueries, generateExternalFindingQueries, generateTableDdl, sqlType, } from "./ddl-generator.js";
25
+ const INSERT_CHUNK = 500;
26
+ function sqlStringLiteral(value) {
27
+ return `'${value.replace(/'/g, "''")}'`;
28
+ }
29
+ /**
30
+ * One loaded engine: schema DDL applied, every provided catalogue's rows
31
+ * inserted. Shared by the FK/PK/enum path and the coverage predicates so
32
+ * there is exactly one load semantics to reason about.
33
+ */
34
+ export async function createEngineSession(schema, rowsByCatalogue) {
35
+ const { DuckDBInstance } = await import("@duckdb/node-api");
36
+ const instance = await DuckDBInstance.create(":memory:");
37
+ const conn = await instance.connect();
38
+ for (const ddl of generateTableDdl(schema)) {
39
+ await conn.run(ddl);
40
+ }
41
+ await loadRows(conn, schema, rowsByCatalogue);
42
+ return { conn, dispose: () => conn.disconnectSync() };
43
+ }
44
+ export async function validateWithEngine(schema, rowsByCatalogue, options = {}) {
45
+ const session = await createEngineSession(schema, rowsByCatalogue);
46
+ const conn = session.conn;
47
+ try {
48
+ const typeNonconformances = await findTypeNonconformances(conn, schema, rowsByCatalogue);
49
+ const failures = [];
50
+ const enumViolations = [];
51
+ const pkDuplicates = [];
52
+ for (const q of generateConstraintQueries(schema, options)) {
53
+ const reader = await conn.runAndReadAll(q.sql);
54
+ for (const row of reader.getRows()) {
55
+ if (q.kind === "fk") {
56
+ failures.push({
57
+ catalogue: q.catalogue,
58
+ column: q.column,
59
+ referencingRow: String(row[0] ?? ""),
60
+ value: String(row[1] ?? ""),
61
+ target: q.target,
62
+ });
63
+ }
64
+ else if (q.kind === "enum") {
65
+ const enumDef = schema.enums[q.target];
66
+ enumViolations.push({
67
+ catalogue: q.catalogue,
68
+ column: q.column,
69
+ rowPk: row[0] === null || row[0] === undefined ? "<no-pk>" : String(row[0]),
70
+ value: String(row[1] ?? ""),
71
+ allowed: enumDef.values.map((v) => v.value).join(" | "),
72
+ });
73
+ }
74
+ else {
75
+ pkDuplicates.push({
76
+ catalogue: q.catalogue,
77
+ rowPk: String(row[0] ?? ""),
78
+ count: Number(row[1]),
79
+ });
80
+ }
81
+ }
82
+ }
83
+ const externalFindingDetails = [];
84
+ for (const q of generateExternalFindingQueries(schema, options)) {
85
+ const reader = await conn.runAndReadAll(q.sql);
86
+ for (const row of reader.getRows()) {
87
+ externalFindingDetails.push({
88
+ catalogue: q.catalogue,
89
+ column: q.column,
90
+ target: q.target,
91
+ rowPk: row[0] === null || row[0] === undefined ? "?" : String(row[0]),
92
+ value: String(row[1] ?? ""),
93
+ });
94
+ }
95
+ }
96
+ return {
97
+ fk: {
98
+ internalPass: failures.length === 0,
99
+ internalFailures: failures,
100
+ externalFindings: externalFindingDetails.length,
101
+ },
102
+ enums: { pass: enumViolations.length === 0, violations: enumViolations },
103
+ externalFindingDetails,
104
+ pkDuplicates,
105
+ typeNonconformances,
106
+ };
107
+ }
108
+ finally {
109
+ session.dispose();
110
+ }
111
+ }
112
+ /**
113
+ * The A4 cutover surface: runs the engine validation and writes findings
114
+ * into the caller's FindingsLog with BYTE-IDENTICAL text to what
115
+ * fk-validator.ts / enum-validator.ts wrote — adopters' committed
116
+ * findings baselines hold those literal lines, so the text is a
117
+ * compatibility contract, not a style choice. Line ORDER within a
118
+ * category follows the engine's total ORDER BY (M-ADR 0205 §4.2) and may
119
+ * differ from the old file-order rendering; baselines compare by
120
+ * membership, so ordering is free — declared in the change-set anyway.
121
+ */
122
+ export async function validateWithEngineToLog(schema, rowsByCatalogue, findings, options = {}, extras = {}) {
123
+ const logEnumFindings = extras.logEnumFindings !== false;
124
+ const res = await validateWithEngine(schema, rowsByCatalogue, options);
125
+ for (const d of res.externalFindingDetails) {
126
+ findings.add("external", `${d.catalogue}.${d.column} → ${d.target}=${d.value} ` +
127
+ `(referencing row pk=${d.rowPk}; resolves at aggregation)`);
128
+ }
129
+ if (logEnumFindings) {
130
+ const enumNameByCatalogueColumn = new Map();
131
+ for (const cat of schema.catalogues) {
132
+ for (const [column, enumRef] of Object.entries(cat.columnEnums)) {
133
+ enumNameByCatalogueColumn.set(`${cat.name}.${column}`, enumRef.replace(/^enums\./, ""));
134
+ }
135
+ }
136
+ for (const v of res.enums.violations) {
137
+ const enumName = enumNameByCatalogueColumn.get(`${v.catalogue}.${v.column}`);
138
+ findings.add("divergence", `${v.catalogue}.${v.column}: row ${v.rowPk} value "${v.value}" is outside the bound enum ${enumName} (${v.allowed})`, "error");
139
+ }
140
+ }
141
+ return { fk: res.fk, enums: res.enums };
142
+ }
143
+ async function loadRows(conn, schema, rowsByCatalogue) {
144
+ for (const cat of schema.catalogues) {
145
+ const rows = rowsByCatalogue.get(cat.name) ?? [];
146
+ if (rows.length === 0)
147
+ continue;
148
+ for (let i = 0; i < rows.length; i += INSERT_CHUNK) {
149
+ const chunk = rows.slice(i, i + INSERT_CHUNK);
150
+ const tuples = chunk
151
+ .map((row) => `(${cat.columns
152
+ .map((c) => literal(row[c.name], cat.name, c.name, c.type))
153
+ .join(", ")})`)
154
+ .join(",\n");
155
+ await conn.run(`INSERT INTO "${cat.name}" VALUES\n${tuples};`);
156
+ }
157
+ }
158
+ }
159
+ /**
160
+ * Renders one cell. String columns keep the empty string AS an empty
161
+ * string — the in-memory validators' emptiness predicates see '' from the
162
+ * CSV reader, and the generated queries test both NULL and ''. Non-string
163
+ * columns TRY_CAST with '' becoming NULL: one uncastable cell must not
164
+ * abort a whole run (measured on a real estate: a prose value in a
165
+ * date-typed column), and the miss is not smoothed either —
166
+ * findTypeNonconformances re-derives every such cell with the engine's
167
+ * own cast semantics and reports it.
168
+ */
169
+ function literal(value, catalogue, column, type) {
170
+ const s = value === null || value === undefined ? "" : String(value);
171
+ if (type === "string")
172
+ return sqlStringLiteral(s);
173
+ if (s === "")
174
+ return "NULL";
175
+ return `TRY_CAST(${sqlStringLiteral(s)} AS ${sqlType(catalogue, column, type)})`;
176
+ }
177
+ /**
178
+ * Exact engine-semantics detection of the cells TRY_CAST nulled: the
179
+ * distinct non-empty values of every typed column are re-checked with the
180
+ * SAME cast the load used — a JS re-implementation of the engine's parsers
181
+ * would be a second opinion pretending to be the first.
182
+ */
183
+ async function findTypeNonconformances(conn, schema, rowsByCatalogue) {
184
+ const out = [];
185
+ for (const cat of schema.catalogues) {
186
+ const rows = rowsByCatalogue.get(cat.name) ?? [];
187
+ if (rows.length === 0)
188
+ continue;
189
+ for (const col of cat.columns) {
190
+ if (col.type === "string")
191
+ continue;
192
+ const counts = new Map();
193
+ for (const row of rows) {
194
+ const v = row[col.name];
195
+ const s = v === null || v === undefined ? "" : String(v);
196
+ if (s === "")
197
+ continue;
198
+ counts.set(s, (counts.get(s) ?? 0) + 1);
199
+ }
200
+ if (counts.size === 0)
201
+ continue;
202
+ const engineType = sqlType(cat.name, col.name, col.type);
203
+ const values = [...counts.keys()].sort();
204
+ const tuples = values.map((v) => `(${sqlStringLiteral(v)})`).join(", ");
205
+ const reader = await conn.runAndReadAll(`SELECT v FROM (VALUES ${tuples}) t(v) ` +
206
+ `WHERE TRY_CAST(v AS ${engineType}) IS NULL ORDER BY v;`);
207
+ for (const row of reader.getRows()) {
208
+ const value = String(row[0]);
209
+ out.push({
210
+ catalogue: cat.name,
211
+ column: col.name,
212
+ declaredType: col.type,
213
+ value,
214
+ rows: counts.get(value) ?? 0,
215
+ });
216
+ }
217
+ }
218
+ }
219
+ return out;
220
+ }
221
+ //# sourceMappingURL=engine-validator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine-validator.js","sourceRoot":"","sources":["../../../src/lib/catalogue/engine-validator.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"enum-validator.d.ts","sourceRoot":"","sources":["../../../src/lib/catalogue/enum-validator.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAE1D,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,SAAS,aAAa,EAAE,CAAC;CAC/C;AAED,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,eAAe,EACvB,eAAe,EAAE,WAAW,CAAC,MAAM,EAAE,SAAS,YAAY,EAAE,CAAC,EAC7D,QAAQ,EAAE,WAAW,GACpB,oBAAoB,CAmCtB"}
1
+ {"version":3,"file":"enum-validator.d.ts","sourceRoot":"","sources":["../../../src/lib/catalogue/enum-validator.ts"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAE1D,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,UAAU,EAAE,SAAS,aAAa,EAAE,CAAC;CAC/C;AAED,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,eAAe,EACvB,eAAe,EAAE,WAAW,CAAC,MAAM,EAAE,SAAS,YAAY,EAAE,CAAC,EAC7D,QAAQ,EAAE,WAAW,GACpB,oBAAoB,CAgDtB"}
@@ -16,6 +16,12 @@
16
16
  //
17
17
  // reads: the in-memory rows of every schema catalogue carrying a
18
18
  // `column_enums` block (no filesystem access of its own).
19
+ //
20
+ // POST-CUTOVER ROLE (M-ADR 0205 §4.4, A4): no production path calls this
21
+ // module — validate/build/aggregate run the engine path. It remains as
22
+ // the reference side of the standing differential (parity-harness.ts and
23
+ // the estate sweep driver), so implementation drift between the two gets
24
+ // caught by the suite instead of lurking.
19
25
  export function validateColumnEnums(schema, rowsByCatalogue, findings) {
20
26
  const violations = [];
21
27
  for (const cat of schema.catalogues) {
@@ -29,6 +35,15 @@ export function validateColumnEnums(schema, rowsByCatalogue, findings) {
29
35
  findings.add("convention", `${cat.name}.${column}: column_enums references unknown enum "${enumRef}" — nothing to validate against`, "error");
30
36
  continue;
31
37
  }
38
+ if (!cat.columns.some((c) => c.name === column)) {
39
+ // A binding to a column the catalogue does not declare reads every
40
+ // row's absent cell as empty and skips it — vacuously green. That
41
+ // is how repositories.service_type (the authoring field's name, not
42
+ // the column's) validated as true from 3.0.0 until schema 3.1.3
43
+ // corrected it. Same discipline as the unknown-enum case above.
44
+ findings.add("convention", `${cat.name}.${column}: column_enums binds a column the catalogue does not declare — the binding validates nothing`, "error");
45
+ continue;
46
+ }
32
47
  const allowedSet = new Set(enumDef.values.map((v) => v.value));
33
48
  const allowed = enumDef.values.map((v) => v.value).join(" | ");
34
49
  for (const row of rowsByCatalogue.get(cat.name) ?? []) {
@@ -1 +1 @@
1
- {"version":3,"file":"enum-validator.js","sourceRoot":"","sources":["../../../src/lib/catalogue/enum-validator.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,0DAA0D;AAC1D,EAAE;AACF,4EAA4E;AAC5E,sEAAsE;AACtE,2EAA2E;AAC3E,0EAA0E;AAC1E,0EAA0E;AAC1E,2EAA2E;AAC3E,2DAA2D;AAC3D,EAAE;AACF,2EAA2E;AAC3E,4EAA4E;AAC5E,0EAA0E;AAC1E,8CAA8C;AAC9C,EAAE;AACF,iEAAiE;AACjE,0DAA0D;AAmB1D,MAAM,UAAU,mBAAmB,CACjC,MAAuB,EACvB,eAA6D,EAC7D,QAAqB;IAErB,MAAM,UAAU,GAAoB,EAAE,CAAC;IAEvC,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;QACpC,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC;YAChE,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;YACjD,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;YACvC,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,8DAA8D;gBAC9D,+DAA+D;gBAC/D,uDAAuD;gBACvD,QAAQ,CAAC,GAAG,CACV,YAAY,EACZ,GAAG,GAAG,CAAC,IAAI,IAAI,MAAM,2CAA2C,OAAO,iCAAiC,EACxG,OAAO,CACR,CAAC;gBACF,SAAS;YACX,CAAC;YACD,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;YAC/D,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC/D,KAAK,MAAM,GAAG,IAAI,eAAe,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;gBACtD,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;gBAC/C,IAAI,KAAK,KAAK,EAAE,IAAI,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC;oBAAE,SAAS;gBACpD,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,SAAS,CAAC,CAAC;gBACvD,UAAU,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;gBACxE,QAAQ,CAAC,GAAG,CACV,YAAY,EACZ,GAAG,GAAG,CAAC,IAAI,IAAI,MAAM,SAAS,KAAK,WAAW,KAAK,+BAA+B,QAAQ,KAAK,OAAO,GAAG,EACzG,OAAO,CACR,CAAC;YACJ,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,UAAU,EAAE,CAAC;AACvD,CAAC"}
1
+ {"version":3,"file":"enum-validator.js","sourceRoot":"","sources":["../../../src/lib/catalogue/enum-validator.ts"],"names":[],"mappings":"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"}
@@ -14,6 +14,12 @@
14
14
  * named even if it resolves cross-SDD.
15
15
  *
16
16
  * Returns a structured result; the caller decides exit code + reporting.
17
+ *
18
+ * POST-CUTOVER ROLE (M-ADR 0205 §4.4, A4): no production path calls this
19
+ * module — validate/build/aggregate run the engine path. It remains as the
20
+ * reference side of the standing differential (parity-harness.ts and the
21
+ * estate sweep driver), so implementation drift between the two gets
22
+ * caught by the suite instead of lurking.
17
23
  */
18
24
  import type { CanonicalSchema } from "./schema-loader.js";
19
25
  import type { CatalogueRow } from "./csv-writer.js";
@@ -1 +1 @@
1
- {"version":3,"file":"fk-validator.d.ts","sourceRoot":"","sources":["../../../src/lib/catalogue/fk-validator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEjD,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B,QAAQ,CAAC,gBAAgB,EAAE,SAAS,SAAS,EAAE,CAAC;IAChD,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;CACnC;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,mBAAmB;IAClC;;;;;OAKG;IACH,QAAQ,CAAC,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAC3C;;;;;;;OAOG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,eAAe,EACvB,eAAe,EAAE,WAAW,CAAC,MAAM,EAAE,SAAS,YAAY,EAAE,CAAC,EAC7D,QAAQ,EAAE,WAAW,EACrB,OAAO,GAAE,mBAAwB,GAChC,kBAAkB,CA4FpB"}
1
+ {"version":3,"file":"fk-validator.d.ts","sourceRoot":"","sources":["../../../src/lib/catalogue/fk-validator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEjD,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B,QAAQ,CAAC,gBAAgB,EAAE,SAAS,SAAS,EAAE,CAAC;IAChD,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;CACnC;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,mBAAmB;IAClC;;;;;OAKG;IACH,QAAQ,CAAC,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAC3C;;;;;;;OAOG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,eAAe,EACvB,eAAe,EAAE,WAAW,CAAC,MAAM,EAAE,SAAS,YAAY,EAAE,CAAC,EAC7D,QAAQ,EAAE,WAAW,EACrB,OAAO,GAAE,mBAAwB,GAChC,kBAAkB,CA4FpB"}