@sequenceholdings/pipeline-spec 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.
- package/README.md +114 -0
- package/dist/authoring/per-table-ingestion.d.ts +74 -0
- package/dist/authoring/per-table-ingestion.d.ts.map +1 -0
- package/dist/authoring/per-table-ingestion.js +122 -0
- package/dist/authoring/per-table-ingestion.js.map +1 -0
- package/dist/authoring/yaml.d.ts +6 -0
- package/dist/authoring/yaml.d.ts.map +1 -0
- package/dist/authoring/yaml.js +15 -0
- package/dist/authoring/yaml.js.map +1 -0
- package/dist/binding-gaps.d.ts +21 -0
- package/dist/binding-gaps.d.ts.map +1 -0
- package/dist/binding-gaps.js +74 -0
- package/dist/binding-gaps.js.map +1 -0
- package/dist/bodies/ingestion.d.ts +359 -0
- package/dist/bodies/ingestion.d.ts.map +1 -0
- package/dist/bodies/ingestion.js +446 -0
- package/dist/bodies/ingestion.js.map +1 -0
- package/dist/bodies/serving.d.ts +316 -0
- package/dist/bodies/serving.d.ts.map +1 -0
- package/dist/bodies/serving.js +290 -0
- package/dist/bodies/serving.js.map +1 -0
- package/dist/bodies/transformation.d.ts +397 -0
- package/dist/bodies/transformation.d.ts.map +1 -0
- package/dist/bodies/transformation.js +278 -0
- package/dist/bodies/transformation.js.map +1 -0
- package/dist/catalog-binding.d.ts +15 -0
- package/dist/catalog-binding.d.ts.map +1 -0
- package/dist/catalog-binding.js +15 -0
- package/dist/catalog-binding.js.map +1 -0
- package/dist/columns.d.ts +177 -0
- package/dist/columns.d.ts.map +1 -0
- package/dist/columns.js +89 -0
- package/dist/columns.js.map +1 -0
- package/dist/compatibility.d.ts +25 -0
- package/dist/compatibility.d.ts.map +1 -0
- package/dist/compatibility.js +108 -0
- package/dist/compatibility.js.map +1 -0
- package/dist/constants.d.ts +95 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +105 -0
- package/dist/constants.js.map +1 -0
- package/dist/diff.d.ts +36 -0
- package/dist/diff.d.ts.map +1 -0
- package/dist/diff.js +300 -0
- package/dist/diff.js.map +1 -0
- package/dist/documentation.d.ts +22 -0
- package/dist/documentation.d.ts.map +1 -0
- package/dist/documentation.js +43 -0
- package/dist/documentation.js.map +1 -0
- package/dist/envelope.d.ts +1241 -0
- package/dist/envelope.d.ts.map +1 -0
- package/dist/envelope.js +163 -0
- package/dist/envelope.js.map +1 -0
- package/dist/errors.d.ts +30 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +47 -0
- package/dist/errors.js.map +1 -0
- package/dist/graph-references.d.ts +34 -0
- package/dist/graph-references.d.ts.map +1 -0
- package/dist/graph-references.js +81 -0
- package/dist/graph-references.js.map +1 -0
- package/dist/graph.d.ts +112 -0
- package/dist/graph.d.ts.map +1 -0
- package/dist/graph.js +546 -0
- package/dist/graph.js.map +1 -0
- package/dist/hash.d.ts +28 -0
- package/dist/hash.d.ts.map +1 -0
- package/dist/hash.js +91 -0
- package/dist/hash.js.map +1 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +27 -0
- package/dist/index.js.map +1 -0
- package/dist/issues.d.ts +14 -0
- package/dist/issues.d.ts.map +1 -0
- package/dist/issues.js +27 -0
- package/dist/issues.js.map +1 -0
- package/dist/loader.d.ts +50 -0
- package/dist/loader.d.ts.map +1 -0
- package/dist/loader.js +241 -0
- package/dist/loader.js.map +1 -0
- package/dist/migrations/contracts.d.ts +38 -0
- package/dist/migrations/contracts.d.ts.map +1 -0
- package/dist/migrations/contracts.js +175 -0
- package/dist/migrations/contracts.js.map +1 -0
- package/dist/migrations/manifest.d.ts +137 -0
- package/dist/migrations/manifest.d.ts.map +1 -0
- package/dist/migrations/manifest.js +137 -0
- package/dist/migrations/manifest.js.map +1 -0
- package/dist/operations.d.ts +214 -0
- package/dist/operations.d.ts.map +1 -0
- package/dist/operations.js +275 -0
- package/dist/operations.js.map +1 -0
- package/dist/orm-satisfies.d.ts +132 -0
- package/dist/orm-satisfies.d.ts.map +1 -0
- package/dist/orm-satisfies.js +119 -0
- package/dist/orm-satisfies.js.map +1 -0
- package/dist/primitives.d.ts +11 -0
- package/dist/primitives.d.ts.map +1 -0
- package/dist/primitives.js +20 -0
- package/dist/primitives.js.map +1 -0
- package/dist/resolve.d.ts +124 -0
- package/dist/resolve.d.ts.map +1 -0
- package/dist/resolve.js +194 -0
- package/dist/resolve.js.map +1 -0
- package/dist/secret-scan.d.ts +34 -0
- package/dist/secret-scan.d.ts.map +1 -0
- package/dist/secret-scan.js +98 -0
- package/dist/secret-scan.js.map +1 -0
- package/dist/serving-compatibility.d.ts +14 -0
- package/dist/serving-compatibility.d.ts.map +1 -0
- package/dist/serving-compatibility.js +19 -0
- package/dist/serving-compatibility.js.map +1 -0
- package/dist/snapshot-transport.d.ts +83 -0
- package/dist/snapshot-transport.d.ts.map +1 -0
- package/dist/snapshot-transport.js +42 -0
- package/dist/snapshot-transport.js.map +1 -0
- package/dist/suggestions.d.ts +3 -0
- package/dist/suggestions.d.ts.map +1 -0
- package/dist/suggestions.js +26 -0
- package/dist/suggestions.js.map +1 -0
- package/dist/types.d.ts +72 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +119 -0
- package/dist/types.js.map +1 -0
- package/package.json +52 -0
package/dist/graph.js
ADDED
|
@@ -0,0 +1,546 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { fullSourceShapeEqual, postgresDestinationKey } from './snapshot-transport.js';
|
|
3
|
+
import { canonicalJson } from './hash.js';
|
|
4
|
+
import { resolveCatalogBinding } from './catalog-binding.js';
|
|
5
|
+
import { columnMapSchema } from './columns.js';
|
|
6
|
+
import { checkServingProjectionCompatibility } from './serving-compatibility.js';
|
|
7
|
+
import { feedBronzeTable, ingestionSourceIdentity } from './bodies/ingestion.js';
|
|
8
|
+
import { transformationOutputCatalog } from './resolve.js';
|
|
9
|
+
import { consumedReferences, softColumns, triggerTargets, unresolvedSchemaRefs, upstreamStages, } from './graph-references.js';
|
|
10
|
+
import { checkServingSatisfiesOrmContract, ormContractCatalogKey, } from './orm-satisfies.js';
|
|
11
|
+
import { nearMisses } from './suggestions.js';
|
|
12
|
+
/**
|
|
13
|
+
* Offline repo-level graph validation: a Pipeline's stages form a DAG through
|
|
14
|
+
* declared inputs/outputs. `validateSpecGraph` resolves references, enforces
|
|
15
|
+
* single-writer-per-physical-asset, rejects cycles, and runs column checks —
|
|
16
|
+
* with ZERO I/O, so the CI gate can run without network or database.
|
|
17
|
+
*/
|
|
18
|
+
export const GRAPH_FINDING_CODES = [
|
|
19
|
+
'snapshot_source_shape_mismatch',
|
|
20
|
+
'duplicate_stage_id',
|
|
21
|
+
'single_writer_violation',
|
|
22
|
+
'unresolved_reference',
|
|
23
|
+
'unresolved_trigger_target',
|
|
24
|
+
'cycle_detected',
|
|
25
|
+
'column_not_produced',
|
|
26
|
+
'projection_column_missing',
|
|
27
|
+
'projection_incompatible',
|
|
28
|
+
'sync_mode_incompatible',
|
|
29
|
+
'no_inputs_declared',
|
|
30
|
+
'unresolved_schema_ref',
|
|
31
|
+
'orm_contract_unavailable',
|
|
32
|
+
'orm_contract_hash_mismatch',
|
|
33
|
+
'orm_contract_pk_mismatch',
|
|
34
|
+
'orm_contract_incompatible',
|
|
35
|
+
'serving_source_catalog_mismatch',
|
|
36
|
+
];
|
|
37
|
+
/**
|
|
38
|
+
* Cross-Pipeline references resolve against a registry **asset export**
|
|
39
|
+
* supplied by the caller — keeps the SDK offline-capable. Keys are logical
|
|
40
|
+
* asset ids (`<stage>.<asset>`, e.g. `billing-silver.silver.coding_usage`).
|
|
41
|
+
*
|
|
42
|
+
* Evolution contract: `schema_version` is the explicit format version — the
|
|
43
|
+
* registry bumps it on breaking export changes and consumers reject versions
|
|
44
|
+
* they don't understand. Objects stay STRICT in v1 (unknown keys are a
|
|
45
|
+
* version bump, never silently ignored), so producers can't leak fields the
|
|
46
|
+
* gate doesn't validate.
|
|
47
|
+
*/
|
|
48
|
+
export const externalAssetsExportSchema = z.strictObject({
|
|
49
|
+
schema_version: z.literal(1),
|
|
50
|
+
assets: z.record(z.string().min(1), z.strictObject({
|
|
51
|
+
columns: columnMapSchema.optional(),
|
|
52
|
+
})),
|
|
53
|
+
});
|
|
54
|
+
function transformationPhysicalAsset({ spec, asset, deployCatalog, deployTarget, }) {
|
|
55
|
+
// Environment-aware callers pass the deploy catalog so an unpinned writer
|
|
56
|
+
// (`banksouth.gold.loans`) collides with a writer that restates
|
|
57
|
+
// `config.catalog: banksouth`. Offline validate omits it and keys only
|
|
58
|
+
// pinned stages as `<catalog>.<asset>`.
|
|
59
|
+
if (typeof deployCatalog === 'string' && deployCatalog.length > 0) {
|
|
60
|
+
return `${transformationOutputCatalog(spec, deployCatalog, deployTarget)}.${asset}`;
|
|
61
|
+
}
|
|
62
|
+
const catalog = resolveCatalogBinding({
|
|
63
|
+
binding: spec.config?.catalog,
|
|
64
|
+
deployTarget,
|
|
65
|
+
});
|
|
66
|
+
return catalog ? `${catalog}.${asset}` : asset;
|
|
67
|
+
}
|
|
68
|
+
function producedAssets(spec, deployCatalog, deployTarget, bindings) {
|
|
69
|
+
switch (spec.type) {
|
|
70
|
+
case 'ingestion':
|
|
71
|
+
// Feeds are schemaless at the contract level (bronze is raw). Their
|
|
72
|
+
// single-writer key is the CATALOG-QUALIFIED bronze FQN
|
|
73
|
+
// (`src_<source>.bronze.<feed>`) because per-source catalogs are
|
|
74
|
+
// ACCOUNT-level assets shared across deployments. The qualified name
|
|
75
|
+
// is the real shared namespace. Serving physicals stay
|
|
76
|
+
// deployment-relative (`public.x`). Transformation physicals are
|
|
77
|
+
// keyed below — unqualified unless `config.catalog` pins a parallel UC
|
|
78
|
+
// namespace, or fully qualified when the deploy catalog is supplied.
|
|
79
|
+
return Object.keys(spec.feeds).map((feed) => ({
|
|
80
|
+
id: `${spec.stage}.${feed}`,
|
|
81
|
+
stage: spec.stage,
|
|
82
|
+
physical: feedBronzeTable({ source: ingestionSourceIdentity(spec), feed }),
|
|
83
|
+
}));
|
|
84
|
+
case 'transformation':
|
|
85
|
+
return Object.entries(spec.outputs).map(([asset, output]) => {
|
|
86
|
+
const columns = softColumns(output.columns);
|
|
87
|
+
const physical = transformationPhysicalAsset({ spec, asset, deployCatalog, deployTarget });
|
|
88
|
+
return {
|
|
89
|
+
id: `${spec.stage}.${asset}`,
|
|
90
|
+
stage: spec.stage,
|
|
91
|
+
physical,
|
|
92
|
+
...(output.write_scope ? { writeScope: output.write_scope } : {}),
|
|
93
|
+
...(columns !== undefined ? { columns } : {}),
|
|
94
|
+
};
|
|
95
|
+
});
|
|
96
|
+
case 'serving': {
|
|
97
|
+
const privateOnly = spec.expose.public_view_access === 'orm_only';
|
|
98
|
+
const columns = softColumns(spec.projection.columns);
|
|
99
|
+
const transport = spec.transport;
|
|
100
|
+
const [exposureSchema, exposureRelation] = spec.expose.view.split('.');
|
|
101
|
+
if (!exposureSchema || !exposureRelation)
|
|
102
|
+
throw new Error('serving exposure must be schema.relation');
|
|
103
|
+
// Private serving contributes an ORM writer claim without publishing
|
|
104
|
+
// the sync naming key as a consumable asset.
|
|
105
|
+
const physicals = privateOnly ? [] : transport?.kind === 'postgres_snapshot_landing_v1'
|
|
106
|
+
? [transport.landing, transport.buffer, { schema: exposureSchema, relation: exposureRelation }]
|
|
107
|
+
.map(target => postgresDestinationKey({
|
|
108
|
+
bindingId: bindings?.[transport.binding]?.bindingId ?? transport.binding,
|
|
109
|
+
database: bindings?.[transport.binding]?.database ?? transport.database, ...target,
|
|
110
|
+
}))
|
|
111
|
+
: [spec.expose.view, ...(spec.expose.reporting_table ? [spec.expose.reporting_table] : [])];
|
|
112
|
+
const binding = spec.orm_binding ?? spec.satisfies;
|
|
113
|
+
if (binding)
|
|
114
|
+
for (const environment of deployTarget ? [deployTarget] : spec.environments) {
|
|
115
|
+
physicals.push(`orm:${canonicalJson([environment, binding.namespace, binding.table])}`);
|
|
116
|
+
}
|
|
117
|
+
return physicals.map((physical, index) => ({
|
|
118
|
+
id: `${spec.stage}.${index === 0 && !privateOnly ? spec.expose.view : physical}`, stage: spec.stage, physical,
|
|
119
|
+
...(columns !== undefined ? { columns } : {}),
|
|
120
|
+
}));
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Every `after:` target must resolve to a stage — in-repo, or present in the
|
|
126
|
+
* external asset export (a stage "exists externally" when any exported asset
|
|
127
|
+
* key carries its `<stage>.` prefix). A typo'd target would otherwise be
|
|
128
|
+
* silently dropped by cycle detection and produce an undeployable schedule.
|
|
129
|
+
*/
|
|
130
|
+
function checkTriggerTargets(spec, stageIds, externalStages, findings) {
|
|
131
|
+
for (const target of triggerTargets(spec)) {
|
|
132
|
+
if (stageIds.has(target) || externalStages.has(target))
|
|
133
|
+
continue;
|
|
134
|
+
const suggestions = nearMisses(target, [...stageIds, ...externalStages]);
|
|
135
|
+
findings.push({
|
|
136
|
+
code: 'unresolved_trigger_target',
|
|
137
|
+
severity: 'error',
|
|
138
|
+
stage: spec.stage,
|
|
139
|
+
asset: target,
|
|
140
|
+
suggestions,
|
|
141
|
+
message: `'${spec.stage}' trigger.after references stage '${target}', which no stage in this Pipeline or the asset export declares` +
|
|
142
|
+
(suggestions.length > 0 ? ` — did you mean: ${suggestions.join(', ')}?` : ''),
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
function findCycle(stages) {
|
|
147
|
+
const byId = new Map(stages.map((spec) => [spec.stage, spec]));
|
|
148
|
+
const visiting = new Set();
|
|
149
|
+
const done = new Set();
|
|
150
|
+
const stack = [];
|
|
151
|
+
const visit = (id) => {
|
|
152
|
+
if (done.has(id))
|
|
153
|
+
return null;
|
|
154
|
+
if (visiting.has(id))
|
|
155
|
+
return [...stack.slice(stack.indexOf(id)), id];
|
|
156
|
+
const spec = byId.get(id);
|
|
157
|
+
if (!spec)
|
|
158
|
+
return null;
|
|
159
|
+
visiting.add(id);
|
|
160
|
+
stack.push(id);
|
|
161
|
+
for (const upstream of upstreamStages(spec)) {
|
|
162
|
+
const cycle = visit(upstream);
|
|
163
|
+
if (cycle)
|
|
164
|
+
return cycle;
|
|
165
|
+
}
|
|
166
|
+
stack.pop();
|
|
167
|
+
visiting.delete(id);
|
|
168
|
+
done.add(id);
|
|
169
|
+
return null;
|
|
170
|
+
};
|
|
171
|
+
for (const spec of stages) {
|
|
172
|
+
const cycle = visit(spec.stage);
|
|
173
|
+
if (cycle)
|
|
174
|
+
return cycle;
|
|
175
|
+
}
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Asset graph nodes + single-writer-per-physical-asset. Logical ids differ
|
|
180
|
+
* (`<stage>.<asset>`) but physical names share one namespace; two writers of
|
|
181
|
+
* `gold.loans` in the same catalog would clobber each other. A transformation
|
|
182
|
+
* that pins `config.catalog` is keyed `<catalog>.<asset>` so parallel source
|
|
183
|
+
* catalogs can share an asset name. When `options.catalog` is the deploy
|
|
184
|
+
* catalog, unpinned writers are keyed the same way so they collide with a
|
|
185
|
+
* restated `config.catalog` equal to that target. The registry-wired check
|
|
186
|
+
* (M6) extends this across Pipelines per deployment.
|
|
187
|
+
*/
|
|
188
|
+
function collectAssets(stages, findings, deployCatalog, deployTarget, bindings) {
|
|
189
|
+
const assetsById = new Map();
|
|
190
|
+
const writersByPhysical = new Map();
|
|
191
|
+
for (const spec of stages) {
|
|
192
|
+
for (const asset of producedAssets(spec, deployCatalog, deployTarget, bindings)) {
|
|
193
|
+
assetsById.set(asset.id, asset);
|
|
194
|
+
const writers = writersByPhysical.get(asset.physical) ?? [];
|
|
195
|
+
writers.push(asset);
|
|
196
|
+
writersByPhysical.set(asset.physical, writers);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
for (const [physical, writers] of writersByPhysical) {
|
|
200
|
+
if (writers.length > 1 && !haveDisjointCompatibleScopes(writers)) {
|
|
201
|
+
findings.push({
|
|
202
|
+
code: 'single_writer_violation',
|
|
203
|
+
severity: 'error',
|
|
204
|
+
asset: physical,
|
|
205
|
+
consumers: writers.map((writer) => writer.stage),
|
|
206
|
+
message: `physical asset '${physical}' is declared by multiple stages: ${writers
|
|
207
|
+
.map((writer) => `'${writer.stage}'`)
|
|
208
|
+
.join(', ')} — writers must have disjoint scopes on the same column and identical schemas, or exactly one writer`,
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
return assetsById;
|
|
213
|
+
}
|
|
214
|
+
function haveDisjointCompatibleScopes(writers) {
|
|
215
|
+
const first = writers[0];
|
|
216
|
+
if (!first?.writeScope || !first.columns)
|
|
217
|
+
return false;
|
|
218
|
+
const signature = (columns) => canonicalJson(Object.fromEntries(Object.entries(columns).map(([name, column]) => [name, {
|
|
219
|
+
type: column.type,
|
|
220
|
+
nullable: column.nullable,
|
|
221
|
+
key: column.key,
|
|
222
|
+
...(column.domain ? { domain: column.domain } : {}),
|
|
223
|
+
}])));
|
|
224
|
+
const firstSignature = signature(first.columns);
|
|
225
|
+
const scopes = new Set();
|
|
226
|
+
for (const writer of writers) {
|
|
227
|
+
const scope = writer.writeScope;
|
|
228
|
+
if (!scope || scope.column !== first.writeScope.column || scopes.has(scope.value))
|
|
229
|
+
return false;
|
|
230
|
+
if (!writer.columns || signature(writer.columns) !== firstSignature)
|
|
231
|
+
return false;
|
|
232
|
+
scopes.add(scope.value);
|
|
233
|
+
}
|
|
234
|
+
return true;
|
|
235
|
+
}
|
|
236
|
+
/** Check physical ownership across local and already deployed stages. */
|
|
237
|
+
export function validateWriteOwnership(stages, options) {
|
|
238
|
+
const findings = [];
|
|
239
|
+
const localAssets = collectAssets(stages, [], options?.catalog, options?.deployTarget, options?.postgresSnapshotBindings);
|
|
240
|
+
const localPhysical = new Set([...localAssets.values()].map((asset) => asset.physical));
|
|
241
|
+
collectAssets([...stages, ...(options?.externalStages ?? [])], findings, options?.catalog, options?.deployTarget, options?.postgresSnapshotBindings);
|
|
242
|
+
return findings.filter((finding) => finding.asset !== undefined && localPhysical.has(finding.asset));
|
|
243
|
+
}
|
|
244
|
+
/** Reference resolution (with near-miss suggestions) + column-subset checks. */
|
|
245
|
+
function checkReferences(spec, index, findings) {
|
|
246
|
+
if (spec.type === 'transformation' &&
|
|
247
|
+
spec.inputs.length === 0 &&
|
|
248
|
+
spec.config?.raw_passthrough !== true) {
|
|
249
|
+
// Legal only as a scaffold state — a transformation with no declared
|
|
250
|
+
// inputs has no lineage edges.
|
|
251
|
+
findings.push({
|
|
252
|
+
code: 'no_inputs_declared',
|
|
253
|
+
severity: 'warning',
|
|
254
|
+
stage: spec.stage,
|
|
255
|
+
message: `'${spec.stage}' declares no inputs — wire its real inputs so the Pipeline DAG has lineage edges`,
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
for (const reference of consumedReferences(spec)) {
|
|
259
|
+
const inRepo = index.assetsById.get(reference.id);
|
|
260
|
+
const externalAsset = inRepo ? undefined : index.external[reference.id];
|
|
261
|
+
if (!inRepo && !externalAsset) {
|
|
262
|
+
const candidates = [...index.assetsById.keys(), ...Object.keys(index.external)];
|
|
263
|
+
const suggestions = nearMisses(reference.id, candidates);
|
|
264
|
+
findings.push({
|
|
265
|
+
code: 'unresolved_reference',
|
|
266
|
+
severity: 'error',
|
|
267
|
+
stage: spec.stage,
|
|
268
|
+
asset: reference.id,
|
|
269
|
+
suggestions,
|
|
270
|
+
message: `'${spec.stage}' (${reference.path}) references '${reference.id}', which no stage in this Pipeline or the asset export declares` +
|
|
271
|
+
(suggestions.length > 0 ? ` — did you mean: ${suggestions.join(', ')}?` : ''),
|
|
272
|
+
});
|
|
273
|
+
continue;
|
|
274
|
+
}
|
|
275
|
+
const producerColumns = inRepo?.columns ?? externalAsset?.columns;
|
|
276
|
+
if (!reference.columns || reference.loose || !producerColumns)
|
|
277
|
+
continue;
|
|
278
|
+
for (const column of reference.columns) {
|
|
279
|
+
if (!(column in producerColumns)) {
|
|
280
|
+
findings.push({
|
|
281
|
+
code: 'column_not_produced',
|
|
282
|
+
severity: 'error',
|
|
283
|
+
stage: spec.stage,
|
|
284
|
+
asset: reference.id,
|
|
285
|
+
consumers: [spec.stage],
|
|
286
|
+
message: `'${spec.stage}' (${reference.path}) requires column '${column}' from '${reference.id}', which does not produce it`,
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
function transformationPublishIsParallel({ spec, deployCatalog, deployTarget, }) {
|
|
293
|
+
const catalog = resolveCatalogBinding({
|
|
294
|
+
binding: spec.config?.catalog,
|
|
295
|
+
deployTarget,
|
|
296
|
+
});
|
|
297
|
+
if (!catalog)
|
|
298
|
+
return { parallel: false };
|
|
299
|
+
if (typeof deployCatalog === 'string' &&
|
|
300
|
+
deployCatalog.length > 0 &&
|
|
301
|
+
catalog === deployCatalog) {
|
|
302
|
+
return { parallel: false, catalog };
|
|
303
|
+
}
|
|
304
|
+
return { parallel: true, catalog };
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* When a transformation producer writes a parallel UC namespace via
|
|
308
|
+
* `config.catalog`, serving must declare the same catalog. `resolveSpec` is
|
|
309
|
+
* per-spec and cannot see the producer, so omitting `source.catalog` would
|
|
310
|
+
* silently SNAPSHOT-sync the deploy-catalog copy (live JH gold on banksouth).
|
|
311
|
+
* Restating `config.catalog` as the deploy catalog is not parallel — serving
|
|
312
|
+
* should omit `source.catalog` (or restate the same deploy catalog).
|
|
313
|
+
*/
|
|
314
|
+
function checkServingProducerCatalog(spec, producerSpec, sourceId, findings, options) {
|
|
315
|
+
const publish = transformationPublishIsParallel({
|
|
316
|
+
spec: producerSpec,
|
|
317
|
+
deployCatalog: options?.catalog,
|
|
318
|
+
deployTarget: options?.deployTarget,
|
|
319
|
+
});
|
|
320
|
+
const sourceCatalog = resolveCatalogBinding({
|
|
321
|
+
binding: spec.source.catalog,
|
|
322
|
+
deployTarget: options?.deployTarget,
|
|
323
|
+
});
|
|
324
|
+
if (!publish.parallel) {
|
|
325
|
+
// Graph compatibility is checked against this in-repo producer. An
|
|
326
|
+
// explicit catalog override would sync a same-named table from another
|
|
327
|
+
// UC catalog whose contract was never validated.
|
|
328
|
+
if (sourceCatalog !== undefined && sourceCatalog !== options?.catalog) {
|
|
329
|
+
findings.push({
|
|
330
|
+
code: 'serving_source_catalog_mismatch',
|
|
331
|
+
severity: 'error',
|
|
332
|
+
stage: spec.stage,
|
|
333
|
+
asset: sourceId,
|
|
334
|
+
message: `'${spec.stage}' source.catalog ('${sourceCatalog}') is only valid when ` +
|
|
335
|
+
`producer '${producerSpec.stage}' declares config.catalog (a parallel UC namespace). ` +
|
|
336
|
+
`This producer writes the deploy catalog — omit source.catalog.`,
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
if (sourceCatalog === publish.catalog)
|
|
342
|
+
return;
|
|
343
|
+
findings.push({
|
|
344
|
+
code: 'serving_source_catalog_mismatch',
|
|
345
|
+
severity: 'error',
|
|
346
|
+
stage: spec.stage,
|
|
347
|
+
asset: sourceId,
|
|
348
|
+
message: `'${spec.stage}' source.catalog must equal producer '${producerSpec.stage}' ` +
|
|
349
|
+
`config.catalog ('${publish.catalog}') — omitting it would sync the deploy-catalog ` +
|
|
350
|
+
`copy of '${spec.source.output}'. Got ${sourceCatalog === undefined ? 'unset' : `'${sourceCatalog}'`}.`,
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
/** `source.catalog` is only verifiable against an in-repo transformation producer. */
|
|
354
|
+
function checkServingExternalCatalog(spec, sourceId, findings, deployTarget) {
|
|
355
|
+
const sourceCatalog = resolveCatalogBinding({
|
|
356
|
+
binding: spec.source.catalog,
|
|
357
|
+
deployTarget,
|
|
358
|
+
});
|
|
359
|
+
if (sourceCatalog === undefined)
|
|
360
|
+
return;
|
|
361
|
+
// Reviewed private snapshots retain their source copies independently of
|
|
362
|
+
// the producer. Complete source contracts still apply; Atlas separately
|
|
363
|
+
// requires the deployment-owned destination and exact stage fingerprint.
|
|
364
|
+
const namespace = spec.orm_binding?.namespace;
|
|
365
|
+
const targetAllowed = namespace === 'banksouth_relationships'
|
|
366
|
+
? deployTarget === undefined || ['staging', 'dev'].includes(deployTarget)
|
|
367
|
+
: namespace === 'banksouth_fis' && (deployTarget === undefined || deployTarget === 'staging');
|
|
368
|
+
if (spec.source.external && spec.source.columns && spec.expose.public_view_access === 'orm_only' &&
|
|
369
|
+
/^dev_[a-z][a-z0-9_]*$/.test(sourceCatalog) && targetAllowed)
|
|
370
|
+
return;
|
|
371
|
+
findings.push({
|
|
372
|
+
code: 'serving_source_catalog_mismatch',
|
|
373
|
+
severity: 'error',
|
|
374
|
+
stage: spec.stage,
|
|
375
|
+
asset: sourceId,
|
|
376
|
+
message: `'${spec.stage}' source.catalog ('${sourceCatalog}') requires an in-repo ` +
|
|
377
|
+
`transformation producer that declares config.catalog — external asset ` +
|
|
378
|
+
`'${sourceId}' cannot be verified. Omit source.catalog.`,
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* Serving-specific offline checks: projection ⊆ source output (with type /
|
|
383
|
+
* nullability / domain compatibility), write-pattern × sync_mode sanity, and
|
|
384
|
+
* optional ORM `satisfies` contract enforcement.
|
|
385
|
+
*/
|
|
386
|
+
function checkServing(spec, stagesById, index, findings, options) {
|
|
387
|
+
const sourceId = `${spec.source.stage}.${spec.source.output}`;
|
|
388
|
+
const producer = (spec.source.external ? spec.source.columns : undefined) ??
|
|
389
|
+
index.assetsById.get(sourceId)?.columns ??
|
|
390
|
+
index.external[sourceId]?.columns;
|
|
391
|
+
const projection = softColumns(spec.projection.columns);
|
|
392
|
+
checkSnapshotSourceShape({ spec, producer, sourceId, findings });
|
|
393
|
+
// An unresolved projection ref was already reported as unresolved_schema_ref.
|
|
394
|
+
if (producer && projection) {
|
|
395
|
+
for (const finding of checkServingProjectionCompatibility({ producer, projection })) {
|
|
396
|
+
findings.push({
|
|
397
|
+
code: finding.code === 'missing_column' ? 'projection_column_missing' : 'projection_incompatible',
|
|
398
|
+
severity: finding.severity,
|
|
399
|
+
stage: spec.stage,
|
|
400
|
+
asset: sourceId,
|
|
401
|
+
consumers: [spec.stage],
|
|
402
|
+
message: `'${spec.stage}' projection: ${finding.message}`,
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
const producerSpec = stagesById.get(spec.source.stage);
|
|
407
|
+
if (producerSpec?.type === 'transformation') {
|
|
408
|
+
const output = producerSpec.outputs[spec.source.output];
|
|
409
|
+
checkServingProducerCatalog(spec, producerSpec, sourceId, findings, options);
|
|
410
|
+
// An overwrite (full-recompute, materialized-view-style) source only
|
|
411
|
+
// supports SNAPSHOT sync; TRIGGERED/CONTINUOUS need a CDF-capable
|
|
412
|
+
// relation. Full CDF capability is a plan-time (live catalog) check.
|
|
413
|
+
if (output && output.write_pattern === 'overwrite' && spec.sync_mode !== 'SNAPSHOT') {
|
|
414
|
+
findings.push({
|
|
415
|
+
code: 'sync_mode_incompatible',
|
|
416
|
+
severity: 'error',
|
|
417
|
+
stage: spec.stage,
|
|
418
|
+
asset: sourceId,
|
|
419
|
+
message: `'${spec.stage}' declares sync_mode ${spec.sync_mode} over '${sourceId}', which is written with write_pattern 'overwrite' — overwrite sources support SNAPSHOT only`,
|
|
420
|
+
});
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
else {
|
|
424
|
+
checkServingExternalCatalog(spec, sourceId, findings, options?.deployTarget);
|
|
425
|
+
}
|
|
426
|
+
checkServingSatisfies(spec, projection, findings, options?.ormContracts);
|
|
427
|
+
}
|
|
428
|
+
function checkServingSatisfies(spec, projection, findings, ormContracts) {
|
|
429
|
+
if (!spec.satisfies)
|
|
430
|
+
return;
|
|
431
|
+
if (ormContracts === undefined) {
|
|
432
|
+
findings.push({
|
|
433
|
+
code: 'orm_contract_unavailable',
|
|
434
|
+
severity: 'error',
|
|
435
|
+
stage: spec.stage,
|
|
436
|
+
consumers: [spec.stage],
|
|
437
|
+
message: `'${spec.stage}' declares satisfies but no ORM contract catalog was supplied — ` +
|
|
438
|
+
`commit orm-contracts.json beside the stage specs or run ` +
|
|
439
|
+
`\`seq-studio pipeline validate --orm-contracts <path>\` (fail closed; drift checks must not be skipped)`,
|
|
440
|
+
});
|
|
441
|
+
return;
|
|
442
|
+
}
|
|
443
|
+
if (!projection)
|
|
444
|
+
return;
|
|
445
|
+
const key = ormContractCatalogKey(spec.satisfies);
|
|
446
|
+
const contractFindings = checkServingSatisfiesOrmContract({
|
|
447
|
+
projection: { columns: projection, primary_key: spec.projection.primary_key },
|
|
448
|
+
satisfies: spec.satisfies,
|
|
449
|
+
contract: ormContracts[key],
|
|
450
|
+
});
|
|
451
|
+
for (const finding of contractFindings) {
|
|
452
|
+
const code = finding.code === 'orm_contract_unavailable' ||
|
|
453
|
+
finding.code === 'orm_contract_hash_mismatch' ||
|
|
454
|
+
finding.code === 'orm_contract_pk_mismatch'
|
|
455
|
+
? finding.code
|
|
456
|
+
: 'orm_contract_incompatible';
|
|
457
|
+
findings.push({
|
|
458
|
+
code,
|
|
459
|
+
severity: finding.severity,
|
|
460
|
+
stage: spec.stage,
|
|
461
|
+
consumers: [spec.stage],
|
|
462
|
+
message: `'${spec.stage}' satisfies: ${finding.message}`,
|
|
463
|
+
});
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
/**
|
|
467
|
+
* Validate a Pipeline's stage graph offline. `externalAssets` (a registry
|
|
468
|
+
* export) resolves cross-Pipeline references; without it, every reference
|
|
469
|
+
* must resolve in-repo. Zero I/O.
|
|
470
|
+
*
|
|
471
|
+
* Pass `options.ormContracts` to enforce serving `satisfies:` against active
|
|
472
|
+
* ORM synced-table contracts (SEQ-2499).
|
|
473
|
+
*/
|
|
474
|
+
export function validateSpecGraph(definitions, externalAssets, options) {
|
|
475
|
+
const findings = [];
|
|
476
|
+
// Duplicate stage ids (parseSpecSources also rejects these; direct callers get the same guarantee).
|
|
477
|
+
const stagesById = new Map();
|
|
478
|
+
for (const spec of definitions) {
|
|
479
|
+
if (stagesById.has(spec.stage)) {
|
|
480
|
+
findings.push({
|
|
481
|
+
code: 'duplicate_stage_id',
|
|
482
|
+
severity: 'error',
|
|
483
|
+
stage: spec.stage,
|
|
484
|
+
message: `duplicate stage id '${spec.stage}'`,
|
|
485
|
+
});
|
|
486
|
+
continue;
|
|
487
|
+
}
|
|
488
|
+
stagesById.set(spec.stage, spec);
|
|
489
|
+
}
|
|
490
|
+
const stages = [...stagesById.values()];
|
|
491
|
+
const index = {
|
|
492
|
+
assetsById: collectAssets(stages, findings, options?.catalog, options?.deployTarget, options?.postgresSnapshotBindings),
|
|
493
|
+
external: externalAssets?.assets ?? {},
|
|
494
|
+
};
|
|
495
|
+
// Stage ids known to the graph: in-repo, plus stages the asset export
|
|
496
|
+
// implies (`<stage>.<asset>` keys) so cross-Pipeline trigger targets resolve.
|
|
497
|
+
const stageIds = new Set(stagesById.keys());
|
|
498
|
+
const externalStages = new Set(Object.keys(index.external)
|
|
499
|
+
.map((key) => key.split('.')[0])
|
|
500
|
+
.filter((stage) => stage !== undefined && stage.length > 0));
|
|
501
|
+
for (const spec of stages) {
|
|
502
|
+
for (const { path, ref } of unresolvedSchemaRefs(spec)) {
|
|
503
|
+
findings.push({
|
|
504
|
+
code: 'unresolved_schema_ref',
|
|
505
|
+
severity: 'error',
|
|
506
|
+
stage: spec.stage,
|
|
507
|
+
message: `'${spec.stage}' (${path}) holds an unresolved schema_ref '${ref}' — load specs through parseSpecSources/loadSpecDirectory (column checks for this position were skipped)`,
|
|
508
|
+
});
|
|
509
|
+
}
|
|
510
|
+
checkReferences(spec, index, findings);
|
|
511
|
+
checkTriggerTargets(spec, stageIds, externalStages, findings);
|
|
512
|
+
if (spec.type === 'transformation') {
|
|
513
|
+
for (const target of spec.trigger.refresh_serving ?? []) {
|
|
514
|
+
if (stageIds.has(target) || externalStages.has(target))
|
|
515
|
+
continue;
|
|
516
|
+
findings.push({
|
|
517
|
+
code: 'unresolved_trigger_target', severity: 'error', stage: spec.stage,
|
|
518
|
+
message: `'${spec.stage}' trigger.refresh_serving target '${target}' is not declared or exported`,
|
|
519
|
+
});
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
if (spec.type === 'serving') {
|
|
523
|
+
checkServing(spec, stagesById, index, findings, options);
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
// Acyclicity across input edges and trigger.after edges.
|
|
527
|
+
const cycle = findCycle(stages);
|
|
528
|
+
if (cycle) {
|
|
529
|
+
findings.push({
|
|
530
|
+
code: 'cycle_detected',
|
|
531
|
+
severity: 'error',
|
|
532
|
+
cycle_path: cycle,
|
|
533
|
+
message: `stage graph has a cycle: ${cycle.join(' → ')}`,
|
|
534
|
+
});
|
|
535
|
+
}
|
|
536
|
+
return { ok: findings.every((finding) => finding.severity !== 'error'), findings };
|
|
537
|
+
}
|
|
538
|
+
function checkSnapshotSourceShape({ spec, producer, sourceId, findings }) {
|
|
539
|
+
if (spec.transport?.kind === 'postgres_snapshot_landing_v1' && (!producer ||
|
|
540
|
+
!fullSourceShapeEqual({ actual: producer, expected: spec.transport.full_source_columns }))) {
|
|
541
|
+
findings.push({ code: 'snapshot_source_shape_mismatch', severity: 'error', stage: spec.stage, asset: sourceId,
|
|
542
|
+
message: `'${spec.stage}' snapshot transport requires the exact complete producer column/type/nullability shape; a projection subset is not full raw fidelity`,
|
|
543
|
+
});
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
//# sourceMappingURL=graph.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graph.js","sourceRoot":"","sources":["../src/graph.ts"],"names":[],"mappings":"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"}
|
package/dist/hash.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { StageSpec } from './envelope.js';
|
|
2
|
+
/**
|
|
3
|
+
* Key-sorted, undefined-skipped JSON — identical specs serialize identically
|
|
4
|
+
* regardless of YAML key order, so hashes are stable across processes and
|
|
5
|
+
* authoring styles. The same canonical form is used for resolved snapshots.
|
|
6
|
+
*/
|
|
7
|
+
export declare function canonicalJson(value: unknown): string;
|
|
8
|
+
/** Hash of the full canonical portable spec — changes on ANY edit. */
|
|
9
|
+
export declare function computeSpecHash(spec: StageSpec): string;
|
|
10
|
+
/**
|
|
11
|
+
* The contract-bearing surface of a spec: what downstream consumers depend
|
|
12
|
+
* on. Cosmetic edits do NOT appear here, so they never churn `contract_hash`
|
|
13
|
+
* — that includes top-level fields (title, runbook, owners, alerts) AND the
|
|
14
|
+
* NESTED `description` keys on feeds, outputs, columns, and projection
|
|
15
|
+
* columns, plus ingestion `columns` and `column_descriptions`. Everything else in these
|
|
16
|
+
* objects is contract-bearing:
|
|
17
|
+
*
|
|
18
|
+
* - ingestion → source identity + feeds (batch semantics, keys, cursors,
|
|
19
|
+
* formats, pii). The source identity (`source.system` / `worker.data_source`)
|
|
20
|
+
* determines every derived bronze name, so renaming it IS a contract change;
|
|
21
|
+
* the CREDENTIAL is a deployment binding, deliberately NOT contract surface.
|
|
22
|
+
* - transformation → outputs (columns + write/violation/compat posture)
|
|
23
|
+
* - serving → source, projection, sync_mode, exposed view, orm_binding, satisfies
|
|
24
|
+
*/
|
|
25
|
+
export declare function contractSurface(spec: StageSpec): Record<string, unknown>;
|
|
26
|
+
/** Hash of just the contract-bearing surface — stable across cosmetic edits. */
|
|
27
|
+
export declare function computeContractHash(spec: StageSpec): string;
|
|
28
|
+
//# sourceMappingURL=hash.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hash.d.ts","sourceRoot":"","sources":["../src/hash.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAA;AAE9C;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAQpD;AAKD,sEAAsE;AACtE,wBAAgB,eAAe,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,CAEvD;AAgBD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAsCxE;AAED,gFAAgF;AAChF,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,SAAS,GAAG,MAAM,CAE3D"}
|