@kaelio/ktx 0.1.0-rc.6 → 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/assets/python/{kaelio_ktx-0.1.0rc6-py3-none-any.whl → kaelio_ktx-0.1.0-py3-none-any.whl} +0 -0
- package/assets/python/manifest.json +4 -4
- package/dist/commands/mcp-commands.js +11 -3
- package/dist/commands/mcp-commands.test.js +30 -1
- package/dist/ingest.test.js +2 -26
- package/dist/next-steps.js +1 -1
- package/dist/next-steps.test.js +2 -0
- package/dist/runtime-requirements.d.ts +1 -2
- package/dist/runtime-requirements.js +0 -7
- package/dist/runtime-requirements.test.js +2 -2
- package/dist/setup-agents.d.ts +11 -3
- package/dist/setup-agents.js +397 -134
- package/dist/setup-agents.test.js +359 -61
- package/dist/setup-runtime.d.ts +0 -1
- package/dist/setup-runtime.js +0 -1
- package/dist/setup-runtime.test.js +7 -13
- package/dist/setup.d.ts +3 -0
- package/dist/setup.js +51 -25
- package/dist/setup.test.js +112 -16
- package/node_modules/@ktx/connector-clickhouse/dist/package-exports.test.js +1 -1
- package/node_modules/@ktx/context/dist/core/git.service.d.ts +0 -1
- package/node_modules/@ktx/context/dist/core/git.service.js +0 -12
- package/node_modules/@ktx/context/dist/ingest/adapters/historic-sql/historic-sql.adapter.d.ts +1 -2
- package/node_modules/@ktx/context/dist/ingest/adapters/historic-sql/historic-sql.adapter.js +0 -18
- package/node_modules/@ktx/context/dist/ingest/adapters/historic-sql/local-ingest-acceptance.test.js +6 -6
- package/node_modules/@ktx/context/dist/ingest/adapters/historic-sql/post-processor.d.ts +4 -0
- package/node_modules/@ktx/context/dist/ingest/adapters/historic-sql/post-processor.js +38 -0
- package/node_modules/@ktx/context/dist/ingest/adapters/historic-sql/post-processor.test.js +63 -0
- package/node_modules/@ktx/context/dist/ingest/adapters/historic-sql/projection.d.ts +0 -5
- package/node_modules/@ktx/context/dist/ingest/adapters/historic-sql/projection.js +0 -48
- package/node_modules/@ktx/context/dist/ingest/adapters/historic-sql/projection.test.js +0 -83
- package/node_modules/@ktx/context/dist/ingest/index.d.ts +2 -1
- package/node_modules/@ktx/context/dist/ingest/index.js +1 -0
- package/node_modules/@ktx/context/dist/ingest/ingest-bundle.runner.d.ts +0 -2
- package/node_modules/@ktx/context/dist/ingest/ingest-bundle.runner.isolated-diff.test.js +0 -166
- package/node_modules/@ktx/context/dist/ingest/ingest-bundle.runner.js +45 -235
- package/node_modules/@ktx/context/dist/ingest/ingest-bundle.runner.test.js +38 -193
- package/node_modules/@ktx/context/dist/ingest/local-bundle-ingest.test.js +3 -22
- package/node_modules/@ktx/context/dist/ingest/local-bundle-runtime.js +4 -0
- package/node_modules/@ktx/context/dist/ingest/local-ingest.js +7 -0
- package/node_modules/@ktx/context/dist/ingest/memory-flow/schema.d.ts +4 -4
- package/node_modules/@ktx/context/dist/ingest/memory-flow/schema.js +1 -1
- package/node_modules/@ktx/context/dist/ingest/memory-flow/types.d.ts +1 -1
- package/node_modules/@ktx/context/dist/ingest/ports.d.ts +20 -1
- package/node_modules/@ktx/context/dist/ingest/report-snapshot.d.ts +2 -73
- package/node_modules/@ktx/context/dist/ingest/report-snapshot.js +0 -27
- package/node_modules/@ktx/context/dist/ingest/reports.d.ts +5 -23
- package/node_modules/@ktx/context/dist/ingest/reports.js +24 -7
- package/node_modules/@ktx/context/dist/ingest/types.d.ts +0 -33
- package/node_modules/@ktx/context/dist/package-exports.test.js +1 -2
- package/package.json +4 -4
- package/node_modules/@ktx/context/dist/ingest/finalization-scope.d.ts +0 -22
- package/node_modules/@ktx/context/dist/ingest/finalization-scope.js +0 -95
- package/node_modules/@ktx/context/dist/ingest/finalization-scope.test.js +0 -114
- /package/node_modules/@ktx/context/dist/ingest/{finalization-scope.test.d.ts → adapters/historic-sql/post-processor.test.d.ts} +0 -0
|
@@ -177,8 +177,6 @@ export async function projectHistoricSqlEvidence(input) {
|
|
|
177
177
|
stalePatternPagesMarked: 0,
|
|
178
178
|
archivedPatternPages: 0,
|
|
179
179
|
touchedSources: [],
|
|
180
|
-
changedWikiPageKeys: [],
|
|
181
|
-
actions: [],
|
|
182
180
|
warnings: [],
|
|
183
181
|
};
|
|
184
182
|
const touchedKeys = new Set();
|
|
@@ -186,14 +184,6 @@ export async function projectHistoricSqlEvidence(input) {
|
|
|
186
184
|
const manifest = stagedManifestSchema.parse(await readJson(join(rawDir, 'manifest.json')));
|
|
187
185
|
const currentTables = await currentStagedTables(rawDir);
|
|
188
186
|
const evidence = await loadEvidence(input.workdir, input.runId);
|
|
189
|
-
if (input.overrideReplay && evidence.length === 0) {
|
|
190
|
-
result.warnings.push('historic-sql finalization skipped stale/archive cleanup during override replay without current-run evidence');
|
|
191
|
-
return result;
|
|
192
|
-
}
|
|
193
|
-
if (evidence.length === 0) {
|
|
194
|
-
result.warnings.push('historic-sql finalization skipped because no current-run evidence was emitted');
|
|
195
|
-
return result;
|
|
196
|
-
}
|
|
197
187
|
const tableEvidence = evidence.filter((entry) => entry.kind === 'table_usage');
|
|
198
188
|
const patternEvidence = evidence.filter((entry) => entry.kind === 'pattern');
|
|
199
189
|
const schemaRoot = join(input.workdir, 'semantic-layer', input.connectionId, '_schema');
|
|
@@ -217,14 +207,6 @@ export async function projectHistoricSqlEvidence(input) {
|
|
|
217
207
|
touchedKeys.add(key);
|
|
218
208
|
result.touchedSources.push({ connectionId: input.connectionId, sourceName });
|
|
219
209
|
}
|
|
220
|
-
result.actions.push({
|
|
221
|
-
target: 'sl',
|
|
222
|
-
type: 'updated',
|
|
223
|
-
key: sourceName,
|
|
224
|
-
targetConnectionId: input.connectionId,
|
|
225
|
-
detail: `Merged historic-SQL usage for ${matchingEvidence.table}`,
|
|
226
|
-
rawPaths: [matchingEvidence.rawPath],
|
|
227
|
-
});
|
|
228
210
|
}
|
|
229
211
|
}
|
|
230
212
|
else if (entry.usage && !currentTables.has(tableRef)) {
|
|
@@ -238,13 +220,6 @@ export async function projectHistoricSqlEvidence(input) {
|
|
|
238
220
|
touchedKeys.add(key);
|
|
239
221
|
result.touchedSources.push({ connectionId: input.connectionId, sourceName });
|
|
240
222
|
}
|
|
241
|
-
result.actions.push({
|
|
242
|
-
target: 'sl',
|
|
243
|
-
type: 'updated',
|
|
244
|
-
key: sourceName,
|
|
245
|
-
targetConnectionId: input.connectionId,
|
|
246
|
-
detail: `Marked historic-SQL usage stale for ${tableRef}`,
|
|
247
|
-
});
|
|
248
223
|
}
|
|
249
224
|
}
|
|
250
225
|
}
|
|
@@ -279,14 +254,6 @@ export async function projectHistoricSqlEvidence(input) {
|
|
|
279
254
|
await writeFile(pagePath, renderMarkdownPage(frontmatter, renderPatternMarkdown(pattern)), 'utf-8');
|
|
280
255
|
writtenKeys.add(key);
|
|
281
256
|
result.patternPagesWritten += 1;
|
|
282
|
-
result.changedWikiPageKeys.push(key);
|
|
283
|
-
result.actions.push({
|
|
284
|
-
target: 'wiki',
|
|
285
|
-
type: reusable ? 'updated' : 'created',
|
|
286
|
-
key,
|
|
287
|
-
detail: `Projected historic-SQL pattern ${pattern.pattern.title}`,
|
|
288
|
-
rawPaths: [pattern.rawPath],
|
|
289
|
-
});
|
|
290
257
|
}
|
|
291
258
|
for (const page of patternPages) {
|
|
292
259
|
if (writtenKeys.has(page.key))
|
|
@@ -295,26 +262,11 @@ export async function projectHistoricSqlEvidence(input) {
|
|
|
295
262
|
const tags = [...new Set([...stringArray(page.frontmatter.tags), 'archived'])];
|
|
296
263
|
await writeFile(page.path, renderMarkdownPage({ ...page.frontmatter, tags, archived_since: manifest.fetchedAt }, page.content), 'utf-8');
|
|
297
264
|
result.archivedPatternPages += 1;
|
|
298
|
-
result.changedWikiPageKeys.push(page.key);
|
|
299
|
-
result.actions.push({
|
|
300
|
-
target: 'wiki',
|
|
301
|
-
type: 'updated',
|
|
302
|
-
key: page.key,
|
|
303
|
-
detail: `Archived stale historic-SQL pattern page ${page.key}`,
|
|
304
|
-
});
|
|
305
265
|
continue;
|
|
306
266
|
}
|
|
307
267
|
const tags = [...new Set([...stringArray(page.frontmatter.tags), 'stale'])];
|
|
308
268
|
await writeFile(page.path, renderMarkdownPage({ ...page.frontmatter, tags, stale_since: manifest.fetchedAt }, page.content), 'utf-8');
|
|
309
269
|
result.stalePatternPagesMarked += 1;
|
|
310
|
-
result.changedWikiPageKeys.push(page.key);
|
|
311
|
-
result.actions.push({
|
|
312
|
-
target: 'wiki',
|
|
313
|
-
type: 'updated',
|
|
314
|
-
key: page.key,
|
|
315
|
-
detail: `Marked historic-SQL pattern page ${page.key} stale`,
|
|
316
|
-
});
|
|
317
270
|
}
|
|
318
|
-
result.changedWikiPageKeys = [...new Set(result.changedWikiPageKeys)].sort();
|
|
319
271
|
return result;
|
|
320
272
|
}
|
|
@@ -64,13 +64,6 @@ describe('projectHistoricSqlEvidence', () => {
|
|
|
64
64
|
});
|
|
65
65
|
const result = await projectHistoricSqlEvidence({ workdir, connectionId: 'warehouse', syncId: 'sync-1', runId: 'run-1' });
|
|
66
66
|
expect(result.touchedSources).toEqual([{ connectionId: 'warehouse', sourceName: 'orders' }]);
|
|
67
|
-
expect(result.actions).toEqual(expect.arrayContaining([
|
|
68
|
-
expect.objectContaining({
|
|
69
|
-
target: 'sl',
|
|
70
|
-
key: 'orders',
|
|
71
|
-
rawPaths: ['tables/public.orders.json'],
|
|
72
|
-
}),
|
|
73
|
-
]));
|
|
74
67
|
const shard = YAML.parse(await readFile(join(workdir, 'semantic-layer/warehouse/_schema/public.yaml'), 'utf-8'));
|
|
75
68
|
expect(shard.tables.orders.usage).toEqual({
|
|
76
69
|
ownerNote: 'keep me',
|
|
@@ -150,14 +143,6 @@ describe('projectHistoricSqlEvidence', () => {
|
|
|
150
143
|
});
|
|
151
144
|
const result = await projectHistoricSqlEvidence({ workdir, connectionId: 'warehouse', syncId: 'sync-1', runId: 'run-1' });
|
|
152
145
|
expect(result.patternPagesWritten).toBe(1);
|
|
153
|
-
expect(result.changedWikiPageKeys).toContain('historic-sql-old-order-lifecycle');
|
|
154
|
-
expect(result.actions).toEqual(expect.arrayContaining([
|
|
155
|
-
expect.objectContaining({
|
|
156
|
-
target: 'wiki',
|
|
157
|
-
key: 'historic-sql-old-order-lifecycle',
|
|
158
|
-
rawPaths: ['patterns-input.json'],
|
|
159
|
-
}),
|
|
160
|
-
]));
|
|
161
146
|
await expect(readFile(join(workdir, 'wiki/global/historic-sql-old-order-lifecycle.md'), 'utf-8')).resolves.toContain('Order Lifecycle Analysis');
|
|
162
147
|
await expect(readFile(join(workdir, 'wiki/global/historic-sql-retired-pattern.md'), 'utf-8')).resolves.toContain('stale_since: "2026-05-11T00:00:00.000Z"');
|
|
163
148
|
});
|
|
@@ -289,19 +274,6 @@ describe('projectHistoricSqlEvidence', () => {
|
|
|
289
274
|
probeWarnings: [],
|
|
290
275
|
staleArchiveAfterDays: 90,
|
|
291
276
|
});
|
|
292
|
-
await writeJson(workdir, '.ktx/ingest-evidence/historic-sql/run-1/customers.json', {
|
|
293
|
-
kind: 'table_usage',
|
|
294
|
-
connectionId: 'warehouse',
|
|
295
|
-
table: 'public.customers',
|
|
296
|
-
rawPath: 'tables/public.customers.json',
|
|
297
|
-
usage: {
|
|
298
|
-
narrative: 'Customers were queried.',
|
|
299
|
-
frequencyTier: 'low',
|
|
300
|
-
commonFilters: [],
|
|
301
|
-
commonJoins: [],
|
|
302
|
-
staleSince: null,
|
|
303
|
-
},
|
|
304
|
-
});
|
|
305
277
|
await writeText(workdir, 'wiki/global/historic-sql-old-template.md', [
|
|
306
278
|
'---',
|
|
307
279
|
YAML.stringify({
|
|
@@ -322,9 +294,6 @@ describe('projectHistoricSqlEvidence', () => {
|
|
|
322
294
|
const result = await projectHistoricSqlEvidence({ workdir, connectionId: 'warehouse', syncId: 'sync-1', runId: 'run-1' });
|
|
323
295
|
expect(result.staleTablesMarked).toBe(1);
|
|
324
296
|
expect(result.touchedSources).toEqual([{ connectionId: 'warehouse', sourceName: 'orders' }]);
|
|
325
|
-
const staleAction = result.actions.find((action) => action.target === 'sl' && action.key === 'orders');
|
|
326
|
-
expect(staleAction).toEqual(expect.objectContaining({ target: 'sl', key: 'orders' }));
|
|
327
|
-
expect(staleAction?.rawPaths).toBeUndefined();
|
|
328
297
|
const shard = YAML.parse(await readFile(join(workdir, 'semantic-layer/warehouse/_schema/public.yaml'), 'utf-8'));
|
|
329
298
|
expect(shard.tables.orders.usage).toEqual({
|
|
330
299
|
ownerNote: 'keep analyst annotation',
|
|
@@ -337,56 +306,4 @@ describe('projectHistoricSqlEvidence', () => {
|
|
|
337
306
|
});
|
|
338
307
|
await expect(readFile(join(workdir, 'wiki/global/historic-sql-old-template.md'), 'utf-8')).resolves.toContain('Old body');
|
|
339
308
|
});
|
|
340
|
-
it('does not mark stale or archive pages when override replay has no current-run evidence', async () => {
|
|
341
|
-
const workdir = await tempWorkdir();
|
|
342
|
-
await writeText(workdir, 'semantic-layer/warehouse/_schema/public.yaml', YAML.stringify({
|
|
343
|
-
tables: {
|
|
344
|
-
orders: {
|
|
345
|
-
table: 'public.orders',
|
|
346
|
-
usage: {
|
|
347
|
-
narrative: 'Orders were active before.',
|
|
348
|
-
frequencyTier: 'high',
|
|
349
|
-
commonFilters: ['status'],
|
|
350
|
-
commonGroupBys: ['status'],
|
|
351
|
-
commonJoins: [],
|
|
352
|
-
},
|
|
353
|
-
columns: [{ name: 'id', type: 'string' }],
|
|
354
|
-
},
|
|
355
|
-
},
|
|
356
|
-
}));
|
|
357
|
-
await writeJson(workdir, 'raw-sources/warehouse/historic-sql/override-sync/manifest.json', {
|
|
358
|
-
source: 'historic-sql',
|
|
359
|
-
connectionId: 'warehouse',
|
|
360
|
-
dialect: 'postgres',
|
|
361
|
-
fetchedAt: '2026-05-11T00:00:00.000Z',
|
|
362
|
-
windowStart: '2026-02-10T00:00:00.000Z',
|
|
363
|
-
windowEnd: '2026-05-11T00:00:00.000Z',
|
|
364
|
-
snapshotRowCount: 0,
|
|
365
|
-
touchedTableCount: 0,
|
|
366
|
-
parseFailures: 0,
|
|
367
|
-
warnings: [],
|
|
368
|
-
probeWarnings: [],
|
|
369
|
-
staleArchiveAfterDays: 90,
|
|
370
|
-
});
|
|
371
|
-
const result = await projectHistoricSqlEvidence({
|
|
372
|
-
workdir,
|
|
373
|
-
connectionId: 'warehouse',
|
|
374
|
-
syncId: 'override-sync',
|
|
375
|
-
runId: 'override-run',
|
|
376
|
-
overrideReplay: {
|
|
377
|
-
priorJobId: 'prior-job',
|
|
378
|
-
priorRunId: 'prior-run',
|
|
379
|
-
priorSyncId: 'prior-sync',
|
|
380
|
-
evictionRawPaths: ['tables/public/orders.json'],
|
|
381
|
-
},
|
|
382
|
-
});
|
|
383
|
-
expect(result.tableUsageMerged).toBe(0);
|
|
384
|
-
expect(result.staleTablesMarked).toBe(0);
|
|
385
|
-
expect(result.patternPagesWritten).toBe(0);
|
|
386
|
-
expect(result.stalePatternPagesMarked).toBe(0);
|
|
387
|
-
expect(result.archivedPatternPages).toBe(0);
|
|
388
|
-
expect(result.touchedSources).toEqual([]);
|
|
389
|
-
expect(result.changedWikiPageKeys).toEqual([]);
|
|
390
|
-
expect(result.actions).toEqual([]);
|
|
391
|
-
});
|
|
392
309
|
});
|
|
@@ -77,6 +77,7 @@ export { stageHistoricSqlAggregatedSnapshot } from './adapters/historic-sql/stag
|
|
|
77
77
|
export { historicSqlEvidenceEnvelopeSchema, historicSqlEvidencePath, historicSqlPatternEvidenceSchema, historicSqlTableUsageEvidenceSchema, serializeHistoricSqlEvidence, } from './adapters/historic-sql/evidence.js';
|
|
78
78
|
export type { HistoricSqlEvidenceEnvelope, HistoricSqlPatternEvidence, HistoricSqlTableUsageEvidence, } from './adapters/historic-sql/evidence.js';
|
|
79
79
|
export { createEmitHistoricSqlEvidenceTool } from './adapters/historic-sql/evidence-tool.js';
|
|
80
|
+
export { HistoricSqlProjectionPostProcessor } from './adapters/historic-sql/post-processor.js';
|
|
80
81
|
export { projectHistoricSqlEvidence } from './adapters/historic-sql/projection.js';
|
|
81
82
|
export type { HistoricSqlProjectionInput, HistoricSqlProjectionResult } from './adapters/historic-sql/projection.js';
|
|
82
83
|
export { patternOutputSchema, patternsArraySchema, tableUsageOutputSchema, } from './adapters/historic-sql/skill-schemas.js';
|
|
@@ -150,5 +151,5 @@ export { buildReconcileSystemPrompt, buildReconcileToolSet, buildReconcileUserPr
|
|
|
150
151
|
export type { ReconciliationOutcome } from './stages/stage-4-reconciliation.js';
|
|
151
152
|
export { runReconciliationStage4 } from './stages/stage-4-reconciliation.js';
|
|
152
153
|
export type { StageIndex } from './stages/stage-index.types.js';
|
|
153
|
-
export type { ChunkResult, DiffSet, EvictionUnit, FetchContext, IngestBundleJob, IngestBundleRef, IngestBundleResult, IngestDiffSummary, IngestJobContext, IngestJobPhase, IngestTrigger, ScopeDescriptor, SourceAdapter, SourceFetchIssue, SourceFetchReport, TriageLane, TriageSignals, UnresolvedCardInfo, WorkUnit, DeterministicProjectionContext, ProjectionResult,
|
|
154
|
+
export type { ChunkResult, DiffSet, EvictionUnit, FetchContext, IngestBundleJob, IngestBundleRef, IngestBundleResult, IngestDiffSummary, IngestJobContext, IngestJobPhase, IngestTrigger, ScopeDescriptor, SourceAdapter, SourceFetchIssue, SourceFetchReport, TriageLane, TriageSignals, UnresolvedCardInfo, WorkUnit, DeterministicProjectionContext, ProjectionResult, } from './types.js';
|
|
154
155
|
export * from './wiki-body-refs.js';
|
|
@@ -51,6 +51,7 @@ export { SnowflakeHistoricSqlQueryHistoryReader } from './adapters/historic-sql/
|
|
|
51
51
|
export { stageHistoricSqlAggregatedSnapshot } from './adapters/historic-sql/stage-unified.js';
|
|
52
52
|
export { historicSqlEvidenceEnvelopeSchema, historicSqlEvidencePath, historicSqlPatternEvidenceSchema, historicSqlTableUsageEvidenceSchema, serializeHistoricSqlEvidence, } from './adapters/historic-sql/evidence.js';
|
|
53
53
|
export { createEmitHistoricSqlEvidenceTool } from './adapters/historic-sql/evidence-tool.js';
|
|
54
|
+
export { HistoricSqlProjectionPostProcessor } from './adapters/historic-sql/post-processor.js';
|
|
54
55
|
export { projectHistoricSqlEvidence } from './adapters/historic-sql/projection.js';
|
|
55
56
|
export { patternOutputSchema, patternsArraySchema, tableUsageOutputSchema, } from './adapters/historic-sql/skill-schemas.js';
|
|
56
57
|
export { HISTORIC_SQL_SOURCE_KEY, aggregatedTemplateSchema, historicSqlUnifiedPullConfigSchema, stagedManifestSchema, stagedPatternsInputSchema, stagedTableInputSchema, } from './adapters/historic-sql/types.js';
|
|
@@ -32,13 +32,11 @@ export declare class IngestBundleRunner {
|
|
|
32
32
|
private buildWikiIndex;
|
|
33
33
|
private buildSlIndex;
|
|
34
34
|
private tableRefExistsInSemanticLayer;
|
|
35
|
-
private loadSourcesByConnection;
|
|
36
35
|
private resolveContextCuratorBudget;
|
|
37
36
|
private filterWorkUnitsForTriage;
|
|
38
37
|
private createTrace;
|
|
39
38
|
private errorMessage;
|
|
40
39
|
private buildProvenancePlan;
|
|
41
|
-
private partitionFinalizationActionsForProvenance;
|
|
42
40
|
private toReportProvenanceRows;
|
|
43
41
|
private toReportWorkUnits;
|
|
44
42
|
private provenanceValidationTraceData;
|
|
@@ -104,24 +104,6 @@ function makeWikiService(root) {
|
|
|
104
104
|
content: content.trim(),
|
|
105
105
|
};
|
|
106
106
|
}),
|
|
107
|
-
writePage: vi.fn(async (_scope, _scopeId, key, frontmatter, content) => {
|
|
108
|
-
await mkdir(join(root, 'wiki/global'), { recursive: true });
|
|
109
|
-
const refs = (frontmatter.refs ?? []).map((ref) => ` - ${ref}`).join('\n');
|
|
110
|
-
const slRefs = (frontmatter.sl_refs ?? []).map((ref) => ` - ${ref}`).join('\n');
|
|
111
|
-
await writeFile(join(root, 'wiki/global', `${key}.md`), [
|
|
112
|
-
'---',
|
|
113
|
-
`summary: ${frontmatter.summary ?? key}`,
|
|
114
|
-
`usage_mode: ${frontmatter.usage_mode ?? 'auto'}`,
|
|
115
|
-
'refs:',
|
|
116
|
-
refs,
|
|
117
|
-
'sl_refs:',
|
|
118
|
-
slRefs,
|
|
119
|
-
'---',
|
|
120
|
-
'',
|
|
121
|
-
content,
|
|
122
|
-
'',
|
|
123
|
-
].join('\n'));
|
|
124
|
-
}),
|
|
125
107
|
syncFromCommit: vi.fn(),
|
|
126
108
|
};
|
|
127
109
|
}
|
|
@@ -1776,152 +1758,4 @@ describe('IngestBundleRunner isolated diff path', () => {
|
|
|
1776
1758
|
await rm(runtime.homeDir, { recursive: true, force: true });
|
|
1777
1759
|
}
|
|
1778
1760
|
});
|
|
1779
|
-
it('runs finalization before wiki sl-ref repair and final gates', async () => {
|
|
1780
|
-
const runtime = await makeRealGitRuntime();
|
|
1781
|
-
try {
|
|
1782
|
-
const { deps, adapter } = makeDeps(runtime);
|
|
1783
|
-
adapter.chunk.mockResolvedValue({
|
|
1784
|
-
workUnits: [{ unitKey: 'wiki-page', rawFiles: ['cards/source.json'], peerFileIndex: [], dependencyPaths: [] }],
|
|
1785
|
-
});
|
|
1786
|
-
adapter.finalize = vi.fn(async ({ workdir }) => {
|
|
1787
|
-
await mkdir(join(workdir, 'semantic-layer/warehouse'), { recursive: true });
|
|
1788
|
-
await mkdir(join(workdir, 'wiki/global'), { recursive: true });
|
|
1789
|
-
await writeFile(join(workdir, 'semantic-layer/warehouse/mart_account_segments.yaml'), 'name: mart_account_segments\ngrain: [account_id]\ncolumns: [{name: account_id, type: string}]\njoins: []\nmeasures:\n - name: total_contract_arr\n expr: sum(contract_arr)\n');
|
|
1790
|
-
await writeFile(join(workdir, 'wiki/global/finalized-accounts.md'), '---\nsummary: Finalized accounts\nusage_mode: auto\nsl_refs:\n - mart_account_segments\n - missing_source\n---\n\nAccounts use `mart_account_segments.total_contract_arr`.\n');
|
|
1791
|
-
return {
|
|
1792
|
-
warnings: [],
|
|
1793
|
-
errors: [],
|
|
1794
|
-
touchedSources: [{ connectionId: 'warehouse', sourceName: 'mart_account_segments' }],
|
|
1795
|
-
changedWikiPageKeys: ['finalized-accounts'],
|
|
1796
|
-
actions: [
|
|
1797
|
-
{
|
|
1798
|
-
target: 'sl',
|
|
1799
|
-
type: 'created',
|
|
1800
|
-
key: 'mart_account_segments',
|
|
1801
|
-
detail: 'Finalized accounts',
|
|
1802
|
-
targetConnectionId: 'warehouse',
|
|
1803
|
-
rawPaths: ['cards/source.json'],
|
|
1804
|
-
},
|
|
1805
|
-
{
|
|
1806
|
-
target: 'wiki',
|
|
1807
|
-
type: 'created',
|
|
1808
|
-
key: 'finalized-accounts',
|
|
1809
|
-
detail: 'Finalized wiki',
|
|
1810
|
-
rawPaths: ['cards/source.json'],
|
|
1811
|
-
},
|
|
1812
|
-
],
|
|
1813
|
-
};
|
|
1814
|
-
});
|
|
1815
|
-
deps.agentRunner.runLoop = vi.fn(async () => ({ stopReason: 'natural' }));
|
|
1816
|
-
const runner = new IngestBundleRunner(deps);
|
|
1817
|
-
await mockStageRawFiles(runner, runtime, [['cards/source.json', 'h1']]);
|
|
1818
|
-
await runner.run({
|
|
1819
|
-
jobId: 'job-finalization',
|
|
1820
|
-
connectionId: 'warehouse',
|
|
1821
|
-
sourceKey: 'metabase',
|
|
1822
|
-
trigger: 'upload',
|
|
1823
|
-
bundleRef: { kind: 'upload', uploadId: 'upload' },
|
|
1824
|
-
});
|
|
1825
|
-
const trace = await readFile(join(runtime.configDir, '.ktx/ingest-traces/job-finalization/trace.jsonl'), 'utf-8');
|
|
1826
|
-
expect(trace.indexOf('finalization_committed')).toBeLessThan(trace.indexOf('wiki_sl_refs_repaired'));
|
|
1827
|
-
expect(trace.indexOf('wiki_sl_refs_repaired')).toBeLessThan(trace.indexOf('final_artifact_gates'));
|
|
1828
|
-
await expect(readFile(join(runtime.configDir, 'wiki/global/finalized-accounts.md'), 'utf-8')).resolves.toContain('sl_refs:\n - mart_account_segments');
|
|
1829
|
-
}
|
|
1830
|
-
finally {
|
|
1831
|
-
await rm(runtime.homeDir, { recursive: true, force: true });
|
|
1832
|
-
}
|
|
1833
|
-
});
|
|
1834
|
-
it('fails when finalization edits a path already changed earlier in the run', async () => {
|
|
1835
|
-
const runtime = await makeRealGitRuntime();
|
|
1836
|
-
try {
|
|
1837
|
-
const { deps, adapter } = makeDeps(runtime);
|
|
1838
|
-
adapter.chunk.mockResolvedValue({
|
|
1839
|
-
workUnits: [{ unitKey: 'wiki-page', rawFiles: ['cards/source.json'], peerFileIndex: [], dependencyPaths: [] }],
|
|
1840
|
-
});
|
|
1841
|
-
let currentSession = null;
|
|
1842
|
-
deps.toolsetFactory.createIngestWuToolset = vi.fn((toolSession) => {
|
|
1843
|
-
currentSession = toolSession;
|
|
1844
|
-
return { toRuntimeTools: vi.fn(() => ({})) };
|
|
1845
|
-
});
|
|
1846
|
-
deps.agentRunner.runLoop = vi.fn(async () => {
|
|
1847
|
-
const root = rootOfConfig(currentSession.configService, runtime.configDir);
|
|
1848
|
-
await mkdir(join(root, 'wiki/global'), { recursive: true });
|
|
1849
|
-
await writeFile(join(root, 'wiki/global/orders.md'), '---\nsummary: Orders\nusage_mode: auto\n---\n\nWU body\n');
|
|
1850
|
-
currentSession.actions.push({
|
|
1851
|
-
target: 'wiki',
|
|
1852
|
-
type: 'created',
|
|
1853
|
-
key: 'orders',
|
|
1854
|
-
detail: 'WU orders',
|
|
1855
|
-
rawPaths: ['cards/source.json'],
|
|
1856
|
-
});
|
|
1857
|
-
await currentSession.gitService.commitFiles(['wiki/global/orders.md'], 'wu orders', 'KTX Test', 'system@ktx.local');
|
|
1858
|
-
return { stopReason: 'natural' };
|
|
1859
|
-
});
|
|
1860
|
-
adapter.finalize = vi.fn(async ({ workdir }) => {
|
|
1861
|
-
await writeFile(join(workdir, 'wiki/global/orders.md'), '---\nsummary: Orders\nusage_mode: auto\n---\n\nFinalized body\n');
|
|
1862
|
-
return {
|
|
1863
|
-
warnings: [],
|
|
1864
|
-
errors: [],
|
|
1865
|
-
touchedSources: [],
|
|
1866
|
-
changedWikiPageKeys: ['orders'],
|
|
1867
|
-
actions: [{ target: 'wiki', type: 'updated', key: 'orders', detail: 'Conflicting finalization' }],
|
|
1868
|
-
};
|
|
1869
|
-
});
|
|
1870
|
-
const runner = new IngestBundleRunner(deps);
|
|
1871
|
-
await mockStageRawFiles(runner, runtime, [['cards/source.json', 'h1']]);
|
|
1872
|
-
await expect(runner.run({
|
|
1873
|
-
jobId: 'job-finalization-overlap',
|
|
1874
|
-
connectionId: 'warehouse',
|
|
1875
|
-
sourceKey: 'metabase',
|
|
1876
|
-
trigger: 'upload',
|
|
1877
|
-
bundleRef: { kind: 'upload', uploadId: 'upload' },
|
|
1878
|
-
})).rejects.toThrow(/finalization modified path\(s\) already changed earlier in this run: wiki\/global\/orders\.md/);
|
|
1879
|
-
}
|
|
1880
|
-
finally {
|
|
1881
|
-
await rm(runtime.homeDir, { recursive: true, force: true });
|
|
1882
|
-
}
|
|
1883
|
-
});
|
|
1884
|
-
it('rejects finalization writes to unauthorized semantic-layer targets', async () => {
|
|
1885
|
-
const runtime = await makeRealGitRuntime();
|
|
1886
|
-
try {
|
|
1887
|
-
const { deps, adapter } = makeDeps(runtime);
|
|
1888
|
-
adapter.chunk.mockResolvedValue({ workUnits: [] });
|
|
1889
|
-
adapter.finalize = vi.fn(async ({ workdir }) => {
|
|
1890
|
-
await mkdir(join(workdir, 'semantic-layer/other-warehouse'), { recursive: true });
|
|
1891
|
-
await writeFile(join(workdir, 'semantic-layer/other-warehouse/orders.yaml'), 'name: orders\ngrain: [order_id]\ncolumns: [{name: order_id, type: string}]\njoins: []\nmeasures: []\n');
|
|
1892
|
-
return {
|
|
1893
|
-
warnings: [],
|
|
1894
|
-
errors: [],
|
|
1895
|
-
touchedSources: [{ connectionId: 'other-warehouse', sourceName: 'orders' }],
|
|
1896
|
-
changedWikiPageKeys: [],
|
|
1897
|
-
actions: [
|
|
1898
|
-
{
|
|
1899
|
-
target: 'sl',
|
|
1900
|
-
type: 'created',
|
|
1901
|
-
key: 'orders',
|
|
1902
|
-
targetConnectionId: 'other-warehouse',
|
|
1903
|
-
detail: 'Forbidden target',
|
|
1904
|
-
rawPaths: ['cards/source.json'],
|
|
1905
|
-
},
|
|
1906
|
-
],
|
|
1907
|
-
};
|
|
1908
|
-
});
|
|
1909
|
-
const runner = new IngestBundleRunner(deps);
|
|
1910
|
-
await mockStageRawFiles(runner, runtime, [['cards/source.json', 'h1']]);
|
|
1911
|
-
await expect(runner.run({
|
|
1912
|
-
jobId: 'job-finalization-target-policy',
|
|
1913
|
-
connectionId: 'warehouse',
|
|
1914
|
-
sourceKey: 'metabase',
|
|
1915
|
-
trigger: 'upload',
|
|
1916
|
-
bundleRef: { kind: 'upload', uploadId: 'upload' },
|
|
1917
|
-
})).rejects.toThrow(/semantic-layer target connection not allowed/);
|
|
1918
|
-
const trace = await readFile(join(runtime.configDir, '.ktx/ingest-traces/job-finalization-target-policy/trace.jsonl'), 'utf-8');
|
|
1919
|
-
expect(trace).toContain('finalization_committed');
|
|
1920
|
-
expect(trace).toContain('semantic_layer_target_policy');
|
|
1921
|
-
expect(trace).toContain('ingest_failed');
|
|
1922
|
-
}
|
|
1923
|
-
finally {
|
|
1924
|
-
await rm(runtime.homeDir, { recursive: true, force: true });
|
|
1925
|
-
}
|
|
1926
|
-
});
|
|
1927
1761
|
});
|