@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.
Files changed (55) hide show
  1. package/assets/python/{kaelio_ktx-0.1.0rc6-py3-none-any.whl → kaelio_ktx-0.1.0-py3-none-any.whl} +0 -0
  2. package/assets/python/manifest.json +4 -4
  3. package/dist/commands/mcp-commands.js +11 -3
  4. package/dist/commands/mcp-commands.test.js +30 -1
  5. package/dist/ingest.test.js +2 -26
  6. package/dist/next-steps.js +1 -1
  7. package/dist/next-steps.test.js +2 -0
  8. package/dist/runtime-requirements.d.ts +1 -2
  9. package/dist/runtime-requirements.js +0 -7
  10. package/dist/runtime-requirements.test.js +2 -2
  11. package/dist/setup-agents.d.ts +11 -3
  12. package/dist/setup-agents.js +397 -134
  13. package/dist/setup-agents.test.js +359 -61
  14. package/dist/setup-runtime.d.ts +0 -1
  15. package/dist/setup-runtime.js +0 -1
  16. package/dist/setup-runtime.test.js +7 -13
  17. package/dist/setup.d.ts +3 -0
  18. package/dist/setup.js +51 -25
  19. package/dist/setup.test.js +112 -16
  20. package/node_modules/@ktx/connector-clickhouse/dist/package-exports.test.js +1 -1
  21. package/node_modules/@ktx/context/dist/core/git.service.d.ts +0 -1
  22. package/node_modules/@ktx/context/dist/core/git.service.js +0 -12
  23. package/node_modules/@ktx/context/dist/ingest/adapters/historic-sql/historic-sql.adapter.d.ts +1 -2
  24. package/node_modules/@ktx/context/dist/ingest/adapters/historic-sql/historic-sql.adapter.js +0 -18
  25. package/node_modules/@ktx/context/dist/ingest/adapters/historic-sql/local-ingest-acceptance.test.js +6 -6
  26. package/node_modules/@ktx/context/dist/ingest/adapters/historic-sql/post-processor.d.ts +4 -0
  27. package/node_modules/@ktx/context/dist/ingest/adapters/historic-sql/post-processor.js +38 -0
  28. package/node_modules/@ktx/context/dist/ingest/adapters/historic-sql/post-processor.test.js +63 -0
  29. package/node_modules/@ktx/context/dist/ingest/adapters/historic-sql/projection.d.ts +0 -5
  30. package/node_modules/@ktx/context/dist/ingest/adapters/historic-sql/projection.js +0 -48
  31. package/node_modules/@ktx/context/dist/ingest/adapters/historic-sql/projection.test.js +0 -83
  32. package/node_modules/@ktx/context/dist/ingest/index.d.ts +2 -1
  33. package/node_modules/@ktx/context/dist/ingest/index.js +1 -0
  34. package/node_modules/@ktx/context/dist/ingest/ingest-bundle.runner.d.ts +0 -2
  35. package/node_modules/@ktx/context/dist/ingest/ingest-bundle.runner.isolated-diff.test.js +0 -166
  36. package/node_modules/@ktx/context/dist/ingest/ingest-bundle.runner.js +45 -235
  37. package/node_modules/@ktx/context/dist/ingest/ingest-bundle.runner.test.js +38 -193
  38. package/node_modules/@ktx/context/dist/ingest/local-bundle-ingest.test.js +3 -22
  39. package/node_modules/@ktx/context/dist/ingest/local-bundle-runtime.js +4 -0
  40. package/node_modules/@ktx/context/dist/ingest/local-ingest.js +7 -0
  41. package/node_modules/@ktx/context/dist/ingest/memory-flow/schema.d.ts +4 -4
  42. package/node_modules/@ktx/context/dist/ingest/memory-flow/schema.js +1 -1
  43. package/node_modules/@ktx/context/dist/ingest/memory-flow/types.d.ts +1 -1
  44. package/node_modules/@ktx/context/dist/ingest/ports.d.ts +20 -1
  45. package/node_modules/@ktx/context/dist/ingest/report-snapshot.d.ts +2 -73
  46. package/node_modules/@ktx/context/dist/ingest/report-snapshot.js +0 -27
  47. package/node_modules/@ktx/context/dist/ingest/reports.d.ts +5 -23
  48. package/node_modules/@ktx/context/dist/ingest/reports.js +24 -7
  49. package/node_modules/@ktx/context/dist/ingest/types.d.ts +0 -33
  50. package/node_modules/@ktx/context/dist/package-exports.test.js +1 -2
  51. package/package.json +4 -4
  52. package/node_modules/@ktx/context/dist/ingest/finalization-scope.d.ts +0 -22
  53. package/node_modules/@ktx/context/dist/ingest/finalization-scope.js +0 -95
  54. package/node_modules/@ktx/context/dist/ingest/finalization-scope.test.js +0 -114
  55. /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, DeterministicFinalizationContext, FinalizationOverrideReplay, FinalizationResult, } from './types.js';
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
  });