@kaelio/ktx 0.11.0 → 0.13.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.13.0-py3-none-any.whl +0 -0
- package/assets/python/manifest.json +4 -4
- package/dist/.tsbuildinfo +1 -1
- package/dist/admin.js +1 -1
- package/dist/clack.d.ts +16 -0
- package/dist/clack.js +37 -6
- package/dist/claude-code-prompt-caching.js +1 -1
- package/dist/cli-program.js +3 -3
- package/dist/cli-runtime.js +2 -2
- package/dist/commands/connection-commands.js +1 -1
- package/dist/commands/ingest-commands.js +4 -4
- package/dist/commands/mcp-commands.js +12 -12
- package/dist/commands/runtime-commands.js +4 -4
- package/dist/commands/setup-commands.js +19 -5
- package/dist/commands/sl-commands.js +1 -1
- package/dist/commands/sql-commands.js +1 -1
- package/dist/commands/status-commands.js +1 -1
- package/dist/connection.js +15 -3
- package/dist/connectors/bigquery/connector.js +1 -14
- package/dist/connectors/clickhouse/connector.js +2 -16
- package/dist/connectors/duckdb/federated-attach.d.ts +7 -0
- package/dist/connectors/duckdb/federated-attach.js +86 -0
- package/dist/connectors/duckdb/federated-executor.d.ts +5 -0
- package/dist/connectors/duckdb/federated-executor.js +59 -0
- package/dist/connectors/mysql/connector.js +2 -16
- package/dist/connectors/postgres/connector.js +1 -14
- package/dist/connectors/shared/string-reference.d.ts +6 -0
- package/dist/connectors/shared/string-reference.js +19 -0
- package/dist/connectors/snowflake/connector.d.ts +1 -1
- package/dist/connectors/snowflake/connector.js +1 -14
- package/dist/connectors/sqlite/connector.js +2 -25
- package/dist/connectors/sqlserver/connector.js +4 -17
- package/dist/context/connections/connection-type.d.ts +1 -1
- package/dist/context/connections/federation.d.ts +33 -0
- package/dist/context/connections/federation.js +51 -0
- package/dist/context/connections/local-warehouse-descriptor.d.ts +2 -0
- package/dist/context/connections/project-sql-executor.d.ts +18 -0
- package/dist/context/connections/project-sql-executor.js +39 -0
- package/dist/context/connections/query-executor.d.ts +2 -2
- package/dist/context/connections/read-only-sql.d.ts +1 -0
- package/dist/context/connections/read-only-sql.js +119 -4
- package/dist/context/connections/resolve-connection.d.ts +12 -0
- package/dist/context/connections/resolve-connection.js +37 -0
- package/dist/context/core/git-env.d.ts +4 -0
- package/dist/context/core/git-env.js +5 -1
- package/dist/context/core/git.service.d.ts +23 -0
- package/dist/context/core/git.service.js +71 -8
- package/dist/context/ingest/adapters/historic-sql/projection.js +2 -1
- package/dist/context/ingest/adapters/live-database/manifest.d.ts +3 -0
- package/dist/context/ingest/adapters/live-database/manifest.js +19 -11
- package/dist/context/ingest/adapters/looker/client.js +7 -2
- package/dist/context/ingest/adapters/looker/factory.d.ts +8 -1
- package/dist/context/ingest/adapters/looker/factory.js +9 -0
- package/dist/context/ingest/adapters/looker/mapping.js +1 -1
- package/dist/context/ingest/adapters/looker/types.d.ts +1 -1
- package/dist/context/ingest/adapters/metabase/client.d.ts +1 -1
- package/dist/context/ingest/adapters/metabase/client.js +1 -1
- package/dist/context/ingest/adapters/metabase/local-metabase.adapter.js +1 -1
- package/dist/context/ingest/adapters/metabase/mapping.js +6 -6
- package/dist/context/ingest/artifact-gates.d.ts +2 -6
- package/dist/context/ingest/artifact-gates.js +5 -47
- package/dist/context/ingest/constrained-repair.d.ts +55 -0
- package/dist/context/ingest/constrained-repair.js +167 -0
- package/dist/context/ingest/final-gate-repair.d.ts +9 -11
- package/dist/context/ingest/final-gate-repair.js +40 -128
- package/dist/context/ingest/finalization-scope.d.ts +1 -1
- package/dist/context/ingest/finalization-scope.js +15 -15
- package/dist/context/ingest/ingest-bundle.runner.d.ts +1 -0
- package/dist/context/ingest/ingest-bundle.runner.js +101 -67
- package/dist/context/ingest/isolated-diff/patch-integrator.d.ts +6 -13
- package/dist/context/ingest/isolated-diff/patch-integrator.js +32 -109
- package/dist/context/ingest/isolated-diff/textual-conflict-resolver.d.ts +8 -9
- package/dist/context/ingest/isolated-diff/textual-conflict-resolver.js +63 -141
- package/dist/context/ingest/local-bundle-runtime.d.ts +2 -0
- package/dist/context/ingest/local-bundle-runtime.js +9 -10
- package/dist/context/ingest/local-ingest.d.ts +2 -0
- package/dist/context/ingest/local-ingest.js +2 -0
- package/dist/context/ingest/memory-flow/view-model.js +1 -1
- package/dist/context/ingest/stages/stage-3-work-units.d.ts +2 -6
- package/dist/context/ingest/stages/stage-3-work-units.js +2 -1
- package/dist/context/ingest/stages/validate-wu-sources.d.ts +7 -1
- package/dist/context/ingest/stages/validate-wu-sources.js +109 -4
- package/dist/context/ingest/tools/warehouse-verification/create-warehouse-verification-tools.d.ts +2 -0
- package/dist/context/ingest/tools/warehouse-verification/create-warehouse-verification-tools.js +1 -1
- package/dist/context/ingest/tools/warehouse-verification/discover-data.tool.js +3 -3
- package/dist/context/ingest/tools/warehouse-verification/sql-execution.tool.d.ts +3 -1
- package/dist/context/ingest/tools/warehouse-verification/sql-execution.tool.js +15 -1
- package/dist/context/llm/ai-sdk-runtime.js +2 -2
- package/dist/context/llm/claude-code-runtime.js +19 -3
- package/dist/context/llm/local-config.js +1 -1
- package/dist/context/llm/runtime-tools.js +2 -2
- package/dist/context/mcp/context-tools.js +33 -8
- package/dist/context/mcp/local-project-ports.js +63 -89
- package/dist/context/mcp/types.d.ts +2 -0
- package/dist/context/memory/local-memory.js +4 -1
- package/dist/context/memory/memory-agent.service.js +1 -1
- package/dist/context/project/config.d.ts +11 -4
- package/dist/context/project/config.js +85 -30
- package/dist/context/project/driver-schemas.js +1 -1
- package/dist/context/project/mappings-yaml-schema.js +2 -2
- package/dist/context/project/project.js +12 -4
- package/dist/context/scan/description-generation.js +4 -4
- package/dist/context/scan/local-enrichment-artifacts.js +33 -4
- package/dist/context/scan/local-scan.js +2 -2
- package/dist/context/scan/local-structural-artifacts.js +5 -5
- package/dist/context/scan/relationship-benchmark-report.js +1 -1
- package/dist/context/scan/relationship-discovery.js +3 -3
- package/dist/context/scan/relationship-llm-proposal.js +3 -3
- package/dist/context/sl/local-query.js +31 -44
- package/dist/context/sl/local-sl.d.ts +0 -8
- package/dist/context/sl/local-sl.js +71 -70
- package/dist/context/sl/semantic-layer.service.d.ts +25 -8
- package/dist/context/sl/semantic-layer.service.js +109 -56
- package/dist/context/sl/source-files.d.ts +48 -0
- package/dist/context/sl/source-files.js +138 -0
- package/dist/context/sl/tools/base-semantic-layer.tool.d.ts +2 -2
- package/dist/context/sl/tools/base-semantic-layer.tool.js +2 -7
- package/dist/context/sl/tools/sl-edit-source.tool.js +10 -8
- package/dist/context/sl/tools/sl-warehouse-validation.js +55 -27
- package/dist/context/sl/tools/sl-write-source.tool.js +12 -9
- package/dist/context/sql-analysis/dialect.d.ts +2 -0
- package/dist/context/sql-analysis/dialect.js +20 -0
- package/dist/context/tools/base-tool.d.ts +6 -19
- package/dist/context/tools/base-tool.js +0 -14
- package/dist/context-build-view.js +5 -5
- package/dist/database-tree-picker.js +18 -3
- package/dist/demo-assets.js +0 -1
- package/dist/doctor.d.ts +1 -1
- package/dist/doctor.js +31 -23
- package/dist/errors.d.ts +31 -0
- package/dist/errors.js +44 -0
- package/dist/ingest-query-executor.d.ts +2 -0
- package/dist/ingest-query-executor.js +8 -22
- package/dist/ingest.d.ts +1 -1
- package/dist/ingest.js +8 -2
- package/dist/io/symbols.d.ts +2 -0
- package/dist/io/symbols.js +2 -0
- package/dist/io/tty.d.ts +8 -0
- package/dist/io/tty.js +16 -0
- package/dist/llm/embedding-health.js +1 -1
- package/dist/llm/embedding-provider.js +3 -3
- package/dist/llm/model-provider.js +1 -1
- package/dist/local-adapters.d.ts +1 -0
- package/dist/local-adapters.js +2 -2
- package/dist/local-scan-connectors.js +1 -1
- package/dist/managed-local-embeddings.js +17 -8
- package/dist/managed-mcp-daemon.js +3 -3
- package/dist/managed-python-command.d.ts +7 -0
- package/dist/managed-python-command.js +34 -8
- package/dist/managed-python-daemon.js +2 -2
- package/dist/managed-python-http.js +3 -3
- package/dist/managed-python-runtime.d.ts +30 -1
- package/dist/managed-python-runtime.js +134 -18
- package/dist/managed-uv-release.d.ts +7 -0
- package/dist/managed-uv-release.js +11 -0
- package/dist/mcp-http-server.js +4 -4
- package/dist/mcp-server-factory.js +3 -3
- package/dist/mcp-stdio-server.js +1 -1
- package/dist/memory-flow-hud.js +2 -2
- package/dist/next-steps.js +2 -2
- package/dist/prompt-navigation.d.ts +17 -0
- package/dist/prompt-navigation.js +49 -3
- package/dist/prompts/memory_agent_bundle_ingest_work_unit.md +2 -2
- package/dist/prompts/memory_agent_external_ingest.md +2 -2
- package/dist/public-ingest-copy.js +1 -1
- package/dist/public-ingest.js +3 -3
- package/dist/release-version.js +1 -1
- package/dist/runtime-requirements.js +1 -1
- package/dist/runtime.js +9 -9
- package/dist/scan.js +1 -1
- package/dist/setup-agents.d.ts +21 -15
- package/dist/setup-agents.js +143 -66
- package/dist/setup-banner.d.ts +20 -0
- package/dist/setup-banner.js +39 -0
- package/dist/setup-context.js +24 -15
- package/dist/setup-databases.d.ts +3 -0
- package/dist/setup-databases.js +47 -59
- package/dist/setup-demo-tour.js +12 -8
- package/dist/setup-embeddings.js +9 -9
- package/dist/setup-interrupt.js +1 -1
- package/dist/setup-models.d.ts +4 -1
- package/dist/setup-models.js +54 -28
- package/dist/setup-project.js +29 -5
- package/dist/setup-prompts.js +16 -1
- package/dist/setup-ready-menu.js +1 -1
- package/dist/setup-sources.js +28 -12
- package/dist/setup.d.ts +1 -0
- package/dist/setup.js +14 -13
- package/dist/skills/analytics/SKILL.md +3 -3
- package/dist/skills/dbt_ingest/SKILL.md +3 -3
- package/dist/skills/looker_ingest/SKILL.md +3 -3
- package/dist/skills/lookml_ingest/SKILL.md +7 -7
- package/dist/skills/metabase_ingest/SKILL.md +4 -4
- package/dist/skills/metricflow_ingest/SKILL.md +15 -15
- package/dist/skills/notion_synthesize/SKILL.md +1 -1
- package/dist/skills/sl/SKILL.md +3 -3
- package/dist/skills/sl_capture/SKILL.md +1 -1
- package/dist/skills/wiki_capture/SKILL.md +1 -1
- package/dist/source-mapping.js +1 -1
- package/dist/sql.d.ts +2 -0
- package/dist/sql.js +35 -53
- package/dist/startup-profile.js +1 -1
- package/dist/status-project.d.ts +0 -2
- package/dist/status-project.js +4 -6
- package/dist/telemetry/events.d.ts +3 -2
- package/dist/telemetry/events.js +11 -1
- package/dist/telemetry/exception.js +14 -0
- package/dist/text-ingest.js +1 -1
- package/dist/tree-picker-tui.d.ts +0 -1
- package/dist/tree-picker-tui.js +2 -3
- package/package.json +2 -1
- package/assets/python/kaelio_ktx-0.11.0-py3-none-any.whl +0 -0
|
@@ -4,6 +4,7 @@ import pLimit from 'p-limit';
|
|
|
4
4
|
import { z } from 'zod';
|
|
5
5
|
import { noopLogger } from '../../context/core/config.js';
|
|
6
6
|
import { createRuntimeToolDescriptorFromAiTool } from '../../context/llm/runtime-tools.js';
|
|
7
|
+
import { isSlYamlPath, slSourceFilePath, slSourceNameForFile, sourceNameFromPath } from '../../context/sl/source-files.js';
|
|
7
8
|
import { createTouchedSlSources } from '../../context/tools/touched-sl-sources.js';
|
|
8
9
|
import { findDanglingWikiRefsForActions } from '../wiki/wiki-ref-validation.js';
|
|
9
10
|
import { actionTargetConnectionId } from './action-identity.js';
|
|
@@ -351,7 +352,7 @@ export class IngestBundleRunner {
|
|
|
351
352
|
const files = await this.deps.semanticLayerService.listFilesForConnection(connectionId);
|
|
352
353
|
const names = files
|
|
353
354
|
.filter((f) => !f.startsWith('_schema/'))
|
|
354
|
-
.map((f) => f
|
|
355
|
+
.map((f) => sourceNameFromPath(f))
|
|
355
356
|
.sort((left, right) => left.localeCompare(right));
|
|
356
357
|
const body = names.length > 0 ? names.join('\n') : '(no sources yet)';
|
|
357
358
|
return `## ${connectionId}\n${body}`;
|
|
@@ -584,14 +585,48 @@ export class IngestBundleRunner {
|
|
|
584
585
|
.map((path) => path.slice('wiki/global/'.length, -'.md'.length))),
|
|
585
586
|
].sort();
|
|
586
587
|
}
|
|
587
|
-
touchedSlSourcesFromPaths(paths) {
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
.
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
588
|
+
async touchedSlSourcesFromPaths(worktree, paths, deletedFileSha) {
|
|
589
|
+
const sources = [];
|
|
590
|
+
for (const path of paths) {
|
|
591
|
+
if (!path.startsWith('semantic-layer/') || !isSlYamlPath(path) || path.includes('/_schema/')) {
|
|
592
|
+
continue;
|
|
593
|
+
}
|
|
594
|
+
const [, connectionId] = path.split('/');
|
|
595
|
+
if (!connectionId) {
|
|
596
|
+
continue;
|
|
597
|
+
}
|
|
598
|
+
// Source identity is the in-file `name:`, never the filename — an uppercase
|
|
599
|
+
// warehouse source like `WIDGET_SALES` lives in a hash-derived
|
|
600
|
+
// `widget_sales-<hash>.yaml`, so parsing the basename yields a phantom name.
|
|
601
|
+
// Read the live file; when it was deleted this run, recover its declared
|
|
602
|
+
// name from the pre-change commit the way `revertSourceToPreHead` resolves a
|
|
603
|
+
// gone file from history. The filename is a last resort only when the content
|
|
604
|
+
// is unrecoverable from both.
|
|
605
|
+
let content;
|
|
606
|
+
try {
|
|
607
|
+
content = await readFile(join(worktree.workdir, path), 'utf-8');
|
|
608
|
+
}
|
|
609
|
+
catch {
|
|
610
|
+
content = await worktree.git.getFileAtCommit(path, deletedFileSha).catch(() => null);
|
|
611
|
+
}
|
|
612
|
+
const sourceName = content === null ? sourceNameFromPath(path) : slSourceNameForFile(path, content);
|
|
613
|
+
if (sourceName.length > 0) {
|
|
614
|
+
sources.push({ connectionId, sourceName });
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
return sources;
|
|
618
|
+
}
|
|
619
|
+
// Inverse direction for commits and repair allowlists: resolve each touched
|
|
620
|
+
// source to its real on-disk path, falling back to the writer's derived
|
|
621
|
+
// filename when the file was deleted in this run.
|
|
622
|
+
async touchedSlSourcePaths(workdir, touched) {
|
|
623
|
+
const service = this.deps.semanticLayerService.forWorktree(workdir);
|
|
624
|
+
const paths = [];
|
|
625
|
+
for (const source of touched) {
|
|
626
|
+
const file = await service.readSourceFile(source.connectionId, source.sourceName);
|
|
627
|
+
paths.push(file?.path ?? slSourceFilePath(source.connectionId, source.sourceName));
|
|
628
|
+
}
|
|
629
|
+
return paths;
|
|
595
630
|
}
|
|
596
631
|
touchedSlSourcesFromActions(actions, fallbackConnectionId) {
|
|
597
632
|
return actions
|
|
@@ -1153,7 +1188,7 @@ export class IngestBundleRunner {
|
|
|
1153
1188
|
projectionTouchedSources = projection.touchedSources;
|
|
1154
1189
|
projectionChangedWikiPageKeys = projection.changedWikiPageKeys;
|
|
1155
1190
|
const projectionPaths = [
|
|
1156
|
-
...
|
|
1191
|
+
...(await this.touchedSlSourcePaths(sessionWorktree.workdir, projection.touchedSources)),
|
|
1157
1192
|
...projection.changedWikiPageKeys.map((pageKey) => `wiki/global/${pageKey}.md`),
|
|
1158
1193
|
];
|
|
1159
1194
|
projectionTouchedPaths = projectionPaths;
|
|
@@ -1297,7 +1332,7 @@ export class IngestBundleRunner {
|
|
|
1297
1332
|
await validateFinalIngestArtifacts({
|
|
1298
1333
|
connectionIds: slConnectionIds,
|
|
1299
1334
|
changedWikiPageKeys: this.wikiPageKeysFromPaths(touchedPaths),
|
|
1300
|
-
touchedSlSources: this.touchedSlSourcesFromPaths(touchedPaths),
|
|
1335
|
+
touchedSlSources: await this.touchedSlSourcesFromPaths(sessionWorktree, touchedPaths, await sessionWorktree.git.revParseHead()),
|
|
1301
1336
|
wikiService: this.deps.wikiService.forWorktree(sessionWorktree.workdir),
|
|
1302
1337
|
semanticLayerService: this.deps.semanticLayerService.forWorktree(sessionWorktree.workdir),
|
|
1303
1338
|
validateTouchedSources: (touched) => validateWuTouchedSources({
|
|
@@ -1322,7 +1357,8 @@ export class IngestBundleRunner {
|
|
|
1322
1357
|
touchedPaths: context.touchedPaths,
|
|
1323
1358
|
trace: runTrace,
|
|
1324
1359
|
reason: context.reason,
|
|
1325
|
-
|
|
1360
|
+
verify: context.verify,
|
|
1361
|
+
maxAttempts: 2,
|
|
1326
1362
|
stepBudget: 12,
|
|
1327
1363
|
abortSignal: ctx?.abortSignal,
|
|
1328
1364
|
});
|
|
@@ -1340,7 +1376,8 @@ export class IngestBundleRunner {
|
|
|
1340
1376
|
allowedPaths: context.touchedPaths,
|
|
1341
1377
|
trace: runTrace,
|
|
1342
1378
|
repairKind: 'patch_semantic_gate',
|
|
1343
|
-
|
|
1379
|
+
verify: context.verify,
|
|
1380
|
+
maxAttempts: 2,
|
|
1344
1381
|
stepBudget: 16,
|
|
1345
1382
|
abortSignal: ctx?.abortSignal,
|
|
1346
1383
|
});
|
|
@@ -1748,17 +1785,24 @@ export class IngestBundleRunner {
|
|
|
1748
1785
|
preFinalizationSha !== postFinalizationSha
|
|
1749
1786
|
? (await sessionWorktree.git.diffNameStatus(preFinalizationSha, postFinalizationSha)).map((entry) => entry.path)
|
|
1750
1787
|
: [];
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1788
|
+
// Validate the write scope before deriving touched sources: attribution
|
|
1789
|
+
// by before/after diff is only defined for connections whose
|
|
1790
|
+
// pre-finalization snapshot was loaded (slConnectionIds), and an
|
|
1791
|
+
// out-of-scope write would otherwise surface downstream as a bogus
|
|
1792
|
+
// unresolved-path or declaration-mismatch failure instead of the real
|
|
1793
|
+
// policy violation.
|
|
1794
|
+
await traceTimed(runTrace, 'finalization', 'semantic_layer_target_policy', {
|
|
1795
|
+
sourceKey: job.sourceKey,
|
|
1796
|
+
allowedTargetConnectionIds: slConnectionIds,
|
|
1797
|
+
touchedPaths: [...new Set(finalizationTouchedPaths)].sort(),
|
|
1798
|
+
}, async () => {
|
|
1799
|
+
assertSemanticLayerTargetPathsAllowed({
|
|
1800
|
+
paths: finalizationTouchedPaths,
|
|
1801
|
+
allowedConnectionIds: new Set(slConnectionIds),
|
|
1802
|
+
});
|
|
1803
|
+
});
|
|
1804
|
+
const postFinalizationSourcesByConnection = await this.loadSourcesByConnection(sessionWorktree.workdir, slConnectionIds);
|
|
1805
|
+
const scope = deriveFinalizationTouchedSources({
|
|
1762
1806
|
changedPaths: finalizationTouchedPaths,
|
|
1763
1807
|
beforeSourcesByConnection: preFinalizationSourcesByConnection,
|
|
1764
1808
|
afterSourcesByConnection: postFinalizationSourcesByConnection,
|
|
@@ -1876,7 +1920,7 @@ export class IngestBundleRunner {
|
|
|
1876
1920
|
...(isolatedDiffEnabled ? projectionTouchedSources : []),
|
|
1877
1921
|
...workUnitOutcomes.flatMap((outcome) => outcome.touchedSlSources),
|
|
1878
1922
|
...this.touchedSlSourcesFromActions(reconcileActions, job.connectionId),
|
|
1879
|
-
...this.touchedSlSourcesFromPaths(postReconciliationPaths),
|
|
1923
|
+
...(await this.touchedSlSourcesFromPaths(sessionWorktree, postReconciliationPaths, preReconciliationSha)),
|
|
1880
1924
|
...finalizationTouchedSources,
|
|
1881
1925
|
]);
|
|
1882
1926
|
const finalWikiGateScope = await this.wikiPageKeysForFinalGates({
|
|
@@ -1926,32 +1970,33 @@ export class IngestBundleRunner {
|
|
|
1926
1970
|
activePhase = 'final_gates';
|
|
1927
1971
|
activeFailureDetails = finalArtifactGateTraceData;
|
|
1928
1972
|
emitStageProgress('final_gates', 89, 'Running final artifact gates');
|
|
1929
|
-
|
|
1930
|
-
await
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1973
|
+
const runFinalArtifactGates = async () => {
|
|
1974
|
+
await validateFinalIngestArtifacts({
|
|
1975
|
+
connectionIds: repairConnectionIds,
|
|
1976
|
+
changedWikiPageKeys: finalChangedWikiPageKeys,
|
|
1977
|
+
touchedSlSources: finalTouchedSlSources,
|
|
1978
|
+
wikiService: this.deps.wikiService.forWorktree(sessionWorktree.workdir),
|
|
1979
|
+
semanticLayerService: this.deps.semanticLayerService.forWorktree(sessionWorktree.workdir),
|
|
1980
|
+
validateTouchedSources: (touched) => validateWuTouchedSources({
|
|
1936
1981
|
semanticLayerService: this.deps.semanticLayerService.forWorktree(sessionWorktree.workdir),
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
}, touched),
|
|
1946
|
-
tableExists: (connectionId, tableRef) => this.tableRefExistsInSemanticLayer(this.deps.semanticLayerService.forWorktree(sessionWorktree.workdir), [connectionId], tableRef),
|
|
1947
|
-
});
|
|
1982
|
+
connections: this.deps.connections,
|
|
1983
|
+
configService: sessionWorktree.config,
|
|
1984
|
+
gitService: sessionWorktree.git,
|
|
1985
|
+
slSourcesRepository: this.deps.slSourcesRepository,
|
|
1986
|
+
probeRowCount: this.deps.settings.probeRowCount,
|
|
1987
|
+
slValidator: this.deps.slValidator,
|
|
1988
|
+
}, touched),
|
|
1989
|
+
tableExists: (connectionId, tableRef) => this.tableRefExistsInSemanticLayer(this.deps.semanticLayerService.forWorktree(sessionWorktree.workdir), [connectionId], tableRef),
|
|
1948
1990
|
});
|
|
1991
|
+
};
|
|
1992
|
+
try {
|
|
1993
|
+
await traceTimed(runTrace, 'final_gates', 'final_artifact_gates', finalArtifactGateTraceData, runFinalArtifactGates);
|
|
1949
1994
|
}
|
|
1950
1995
|
catch (error) {
|
|
1951
1996
|
const gateError = this.errorMessage(error);
|
|
1952
1997
|
const repairPaths = finalGateRepairPaths({
|
|
1953
1998
|
changedWikiPageKeys: finalChangedWikiPageKeys,
|
|
1954
|
-
|
|
1999
|
+
touchedSlSourcePaths: await this.touchedSlSourcePaths(sessionWorktree.workdir, finalTouchedSlSources),
|
|
1955
2000
|
});
|
|
1956
2001
|
emitStageProgress('final_gates', 89, 'Repairing final artifact gates');
|
|
1957
2002
|
const gateRepair = await repairFinalGateFailure({
|
|
@@ -1961,7 +2006,16 @@ export class IngestBundleRunner {
|
|
|
1961
2006
|
allowedPaths: repairPaths,
|
|
1962
2007
|
trace: runTrace,
|
|
1963
2008
|
repairKind: 'final_artifact_gate',
|
|
1964
|
-
|
|
2009
|
+
verify: async () => {
|
|
2010
|
+
try {
|
|
2011
|
+
await runFinalArtifactGates();
|
|
2012
|
+
return { ok: true };
|
|
2013
|
+
}
|
|
2014
|
+
catch (verifyError) {
|
|
2015
|
+
return { ok: false, reason: this.errorMessage(verifyError) };
|
|
2016
|
+
}
|
|
2017
|
+
},
|
|
2018
|
+
maxAttempts: 2,
|
|
1965
2019
|
stepBudget: 16,
|
|
1966
2020
|
abortSignal: ctx?.abortSignal,
|
|
1967
2021
|
});
|
|
@@ -1975,29 +2029,9 @@ export class IngestBundleRunner {
|
|
|
1975
2029
|
};
|
|
1976
2030
|
throw new Error(`${gateError}\ngate repair failed: ${gateRepair.reason}`);
|
|
1977
2031
|
}
|
|
2032
|
+
// The repair loop re-ran the gates via `verify` before reporting
|
|
2033
|
+
// success, so a repaired status here means the tree already passed.
|
|
1978
2034
|
isolatedDiffSummary.gateRepairs += 1;
|
|
1979
|
-
await traceTimed(runTrace, 'final_gates', 'final_artifact_gates_after_gate_repair', {
|
|
1980
|
-
...finalArtifactGateTraceData,
|
|
1981
|
-
repairedPaths: gateRepair.changedPaths,
|
|
1982
|
-
}, async () => {
|
|
1983
|
-
await validateFinalIngestArtifacts({
|
|
1984
|
-
connectionIds: repairConnectionIds,
|
|
1985
|
-
changedWikiPageKeys: finalChangedWikiPageKeys,
|
|
1986
|
-
touchedSlSources: finalTouchedSlSources,
|
|
1987
|
-
wikiService: this.deps.wikiService.forWorktree(sessionWorktree.workdir),
|
|
1988
|
-
semanticLayerService: this.deps.semanticLayerService.forWorktree(sessionWorktree.workdir),
|
|
1989
|
-
validateTouchedSources: (touched) => validateWuTouchedSources({
|
|
1990
|
-
semanticLayerService: this.deps.semanticLayerService.forWorktree(sessionWorktree.workdir),
|
|
1991
|
-
connections: this.deps.connections,
|
|
1992
|
-
configService: sessionWorktree.config,
|
|
1993
|
-
gitService: sessionWorktree.git,
|
|
1994
|
-
slSourcesRepository: this.deps.slSourcesRepository,
|
|
1995
|
-
probeRowCount: this.deps.settings.probeRowCount,
|
|
1996
|
-
slValidator: this.deps.slValidator,
|
|
1997
|
-
}, touched),
|
|
1998
|
-
tableExists: (connectionId, tableRef) => this.tableRefExistsInSemanticLayer(this.deps.semanticLayerService.forWorktree(sessionWorktree.workdir), [connectionId], tableRef),
|
|
1999
|
-
});
|
|
2000
|
-
});
|
|
2001
2035
|
const repairCommit = await sessionWorktree.git.commitFiles(gateRepair.changedPaths, `ingest(${job.sourceKey}): repair final gates syncId=${syncId}`, this.deps.storage.systemGitAuthor.name, this.deps.storage.systemGitAuthor.email);
|
|
2002
2036
|
if (!repairCommit.created) {
|
|
2003
2037
|
isolatedDiffSummary.gateRepairFailures += 1;
|
|
@@ -1,33 +1,25 @@
|
|
|
1
1
|
import type { GitService } from '../../../context/core/git.service.js';
|
|
2
|
+
import type { RepairVerification } from '../constrained-repair.js';
|
|
2
3
|
import type { FinalGateRepairResult } from '../final-gate-repair.js';
|
|
3
4
|
import type { IngestTraceWriter } from '../ingest-trace.js';
|
|
4
5
|
import type { TextualConflictResolutionResult } from './textual-conflict-resolver.js';
|
|
5
|
-
type PatchIntegrationTextualResolution = {
|
|
6
|
-
status: 'repaired';
|
|
7
|
-
attempts: number;
|
|
8
|
-
changedPaths: string[];
|
|
9
|
-
} | {
|
|
10
|
-
status: 'failed';
|
|
11
|
-
attempts: number;
|
|
12
|
-
reason: string;
|
|
13
|
-
};
|
|
14
6
|
export type PatchIntegrationResult = {
|
|
15
7
|
status: 'accepted';
|
|
16
8
|
commitSha: string;
|
|
17
9
|
touchedPaths: string[];
|
|
18
|
-
textualResolution?:
|
|
10
|
+
textualResolution?: TextualConflictResolutionResult;
|
|
19
11
|
gateRepair?: FinalGateRepairResult;
|
|
20
12
|
} | {
|
|
21
13
|
status: 'textual_conflict';
|
|
22
14
|
reason: string;
|
|
23
15
|
touchedPaths: string[];
|
|
24
|
-
textualResolution?:
|
|
16
|
+
textualResolution?: TextualConflictResolutionResult;
|
|
25
17
|
gateRepair?: FinalGateRepairResult;
|
|
26
18
|
} | {
|
|
27
19
|
status: 'semantic_conflict';
|
|
28
20
|
reason: string;
|
|
29
21
|
touchedPaths: string[];
|
|
30
|
-
textualResolution?:
|
|
22
|
+
textualResolution?: TextualConflictResolutionResult;
|
|
31
23
|
gateRepair?: FinalGateRepairResult;
|
|
32
24
|
};
|
|
33
25
|
export interface IntegrateWorkUnitPatchInput {
|
|
@@ -47,13 +39,14 @@ export interface IntegrateWorkUnitPatchInput {
|
|
|
47
39
|
patchPath: string;
|
|
48
40
|
touchedPaths: string[];
|
|
49
41
|
reason: string;
|
|
42
|
+
verify(changedPaths: string[]): Promise<RepairVerification>;
|
|
50
43
|
}): Promise<TextualConflictResolutionResult>;
|
|
51
44
|
repairGateFailure?(input: {
|
|
52
45
|
unitKey: string;
|
|
53
46
|
patchPath: string;
|
|
54
47
|
touchedPaths: string[];
|
|
55
48
|
reason: string;
|
|
49
|
+
verify(changedPaths: string[]): Promise<RepairVerification>;
|
|
56
50
|
}): Promise<FinalGateRepairResult>;
|
|
57
51
|
}
|
|
58
52
|
export declare function integrateWorkUnitPatch(input: IntegrateWorkUnitPatchInput): Promise<PatchIntegrationResult>;
|
|
59
|
-
export {};
|
|
@@ -38,6 +38,19 @@ export async function integrateWorkUnitPatch(input) {
|
|
|
38
38
|
touchedPaths,
|
|
39
39
|
};
|
|
40
40
|
}
|
|
41
|
+
// Repair and resolution success is decided by this check, not by whether
|
|
42
|
+
// the repair agent edited files: the gates re-run over the union of the
|
|
43
|
+
// patch's paths and everything the agent changed.
|
|
44
|
+
const verifyAppliedTree = async (changedPaths) => {
|
|
45
|
+
const paths = [...new Set([...touchedPaths, ...changedPaths])].sort();
|
|
46
|
+
try {
|
|
47
|
+
await input.validateAppliedTree(paths);
|
|
48
|
+
return { ok: true };
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
return { ok: false, reason: errorMessage(error) };
|
|
52
|
+
}
|
|
53
|
+
};
|
|
41
54
|
try {
|
|
42
55
|
await traceTimed(input.trace, 'integration', 'patch_apply', { unitKey: input.unitKey, patchPath: input.patchPath, touchedPaths }, async () => {
|
|
43
56
|
await input.integrationGit.applyPatchFile3WayIndex(input.patchPath);
|
|
@@ -67,6 +80,7 @@ export async function integrateWorkUnitPatch(input) {
|
|
|
67
80
|
patchPath: input.patchPath,
|
|
68
81
|
touchedPaths,
|
|
69
82
|
reason,
|
|
83
|
+
verify: verifyAppliedTree,
|
|
70
84
|
});
|
|
71
85
|
if (textualResolution.status === 'failed') {
|
|
72
86
|
if (preApplyHead) {
|
|
@@ -79,113 +93,37 @@ export async function integrateWorkUnitPatch(input) {
|
|
|
79
93
|
textualResolution,
|
|
80
94
|
};
|
|
81
95
|
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
catch (semanticError) {
|
|
88
|
-
const reason = errorMessage(semanticError);
|
|
89
|
-
await input.trace.event('error', 'integration', 'patch_semantic_conflict_after_textual_resolution', {
|
|
96
|
+
if (textualResolution.changedPaths.length === 0) {
|
|
97
|
+
// The resolver declared the patch redundant and the gates verified the
|
|
98
|
+
// current tree: the integration worktree already represents this work
|
|
99
|
+
// unit's content (e.g. a duplicate page created by another work unit).
|
|
100
|
+
await input.trace.event('debug', 'integration', 'patch_subsumed_after_textual_resolution', {
|
|
90
101
|
unitKey: input.unitKey,
|
|
91
102
|
patchPath: input.patchPath,
|
|
92
|
-
touchedPaths
|
|
93
|
-
|
|
103
|
+
touchedPaths,
|
|
104
|
+
attempts: textualResolution.attempts,
|
|
94
105
|
});
|
|
95
|
-
// A textual conflict and a semantic-gate failure can co-occur: the resolver
|
|
96
|
-
// reconciles the text but can leave wiki sl_refs pointing at measures the
|
|
97
|
-
// merged source no longer defines. Recover via the same gate repair the
|
|
98
|
-
// clean-apply branch uses, instead of hard-failing the whole job.
|
|
99
|
-
if (input.repairGateFailure) {
|
|
100
|
-
const gateRepair = await input.repairGateFailure({
|
|
101
|
-
unitKey: input.unitKey,
|
|
102
|
-
patchPath: input.patchPath,
|
|
103
|
-
touchedPaths: textualResolution.changedPaths,
|
|
104
|
-
reason,
|
|
105
|
-
});
|
|
106
|
-
if (gateRepair.status !== 'failed') {
|
|
107
|
-
// The resolver wrote its merge to the worktree (unstaged); the repair
|
|
108
|
-
// edited a subset on top. Commit the union so neither is dropped.
|
|
109
|
-
const resolvedAndRepairedPaths = [
|
|
110
|
-
...new Set([...textualResolution.changedPaths, ...gateRepair.changedPaths]),
|
|
111
|
-
].sort();
|
|
112
|
-
try {
|
|
113
|
-
await traceTimed(input.trace, 'integration', 'semantic_gate_after_gate_repair', { unitKey: input.unitKey, touchedPaths: gateRepair.changedPaths }, async () => {
|
|
114
|
-
await input.validateAppliedTree(gateRepair.changedPaths);
|
|
115
|
-
});
|
|
116
|
-
const commit = await input.integrationGit.commitFiles(resolvedAndRepairedPaths, `ingest: resolve WorkUnit ${input.unitKey} conflict`, input.author.name, input.author.email);
|
|
117
|
-
if (commit.created) {
|
|
118
|
-
await input.trace.event('debug', 'integration', 'patch_accepted_after_textual_resolution', {
|
|
119
|
-
unitKey: input.unitKey,
|
|
120
|
-
commitSha: commit.commitHash,
|
|
121
|
-
touchedPaths: resolvedAndRepairedPaths,
|
|
122
|
-
attempts: textualResolution.attempts,
|
|
123
|
-
gateRepairAttempts: gateRepair.attempts,
|
|
124
|
-
});
|
|
125
|
-
return {
|
|
126
|
-
status: 'accepted',
|
|
127
|
-
commitSha: commit.commitHash,
|
|
128
|
-
touchedPaths: resolvedAndRepairedPaths,
|
|
129
|
-
textualResolution,
|
|
130
|
-
gateRepair,
|
|
131
|
-
};
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
catch (repairValidationError) {
|
|
135
|
-
if (preApplyHead) {
|
|
136
|
-
await input.integrationGit.resetHardTo(preApplyHead);
|
|
137
|
-
}
|
|
138
|
-
await input.trace.event('error', 'integration', 'patch_semantic_conflict_after_textual_resolution', {
|
|
139
|
-
unitKey: input.unitKey,
|
|
140
|
-
patchPath: input.patchPath,
|
|
141
|
-
touchedPaths: gateRepair.changedPaths,
|
|
142
|
-
reason: errorMessage(repairValidationError),
|
|
143
|
-
});
|
|
144
|
-
return {
|
|
145
|
-
status: 'semantic_conflict',
|
|
146
|
-
reason: errorMessage(repairValidationError),
|
|
147
|
-
touchedPaths: gateRepair.changedPaths,
|
|
148
|
-
textualResolution,
|
|
149
|
-
gateRepair,
|
|
150
|
-
};
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
if (preApplyHead) {
|
|
154
|
-
await input.integrationGit.resetHardTo(preApplyHead);
|
|
155
|
-
}
|
|
156
|
-
return {
|
|
157
|
-
status: 'semantic_conflict',
|
|
158
|
-
reason: gateRepair.status === 'failed' ? gateRepair.reason : reason,
|
|
159
|
-
touchedPaths: textualResolution.changedPaths,
|
|
160
|
-
textualResolution,
|
|
161
|
-
gateRepair,
|
|
162
|
-
};
|
|
163
|
-
}
|
|
164
|
-
if (preApplyHead) {
|
|
165
|
-
await input.integrationGit.resetHardTo(preApplyHead);
|
|
166
|
-
}
|
|
167
106
|
return {
|
|
168
|
-
status: '
|
|
169
|
-
|
|
170
|
-
touchedPaths:
|
|
107
|
+
status: 'accepted',
|
|
108
|
+
commitSha: preApplyHead ?? '',
|
|
109
|
+
touchedPaths: [],
|
|
171
110
|
textualResolution,
|
|
172
111
|
};
|
|
173
112
|
}
|
|
174
113
|
const commit = await input.integrationGit.commitFiles(textualResolution.changedPaths, `ingest: resolve WorkUnit ${input.unitKey} conflict`, input.author.name, input.author.email);
|
|
175
114
|
if (!commit.created) {
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
const noChangeReason = 'textual resolver produced no committable changes';
|
|
180
|
-
await input.trace.event('error', 'integration', 'textual_conflict_resolver_noop', {
|
|
115
|
+
// The resolver's writes left the tree byte-identical to the accepted
|
|
116
|
+
// state, and the gates verified it — the patch is represented already.
|
|
117
|
+
await input.trace.event('debug', 'integration', 'patch_subsumed_after_textual_resolution', {
|
|
181
118
|
unitKey: input.unitKey,
|
|
182
119
|
patchPath: input.patchPath,
|
|
183
120
|
touchedPaths: textualResolution.changedPaths,
|
|
121
|
+
attempts: textualResolution.attempts,
|
|
184
122
|
});
|
|
185
123
|
return {
|
|
186
|
-
status: '
|
|
187
|
-
|
|
188
|
-
touchedPaths:
|
|
124
|
+
status: 'accepted',
|
|
125
|
+
commitSha: preApplyHead ?? '',
|
|
126
|
+
touchedPaths: [],
|
|
189
127
|
textualResolution,
|
|
190
128
|
};
|
|
191
129
|
}
|
|
@@ -221,6 +159,7 @@ export async function integrateWorkUnitPatch(input) {
|
|
|
221
159
|
patchPath: input.patchPath,
|
|
222
160
|
touchedPaths,
|
|
223
161
|
reason,
|
|
162
|
+
verify: verifyAppliedTree,
|
|
224
163
|
});
|
|
225
164
|
if (gateRepair.status === 'failed') {
|
|
226
165
|
if (preApplyHead) {
|
|
@@ -233,22 +172,6 @@ export async function integrateWorkUnitPatch(input) {
|
|
|
233
172
|
gateRepair,
|
|
234
173
|
};
|
|
235
174
|
}
|
|
236
|
-
try {
|
|
237
|
-
await traceTimed(input.trace, 'integration', 'semantic_gate_after_gate_repair', { unitKey: input.unitKey, touchedPaths: gateRepair.changedPaths }, async () => {
|
|
238
|
-
await input.validateAppliedTree(gateRepair.changedPaths);
|
|
239
|
-
});
|
|
240
|
-
}
|
|
241
|
-
catch (repairValidationError) {
|
|
242
|
-
if (preApplyHead) {
|
|
243
|
-
await input.integrationGit.resetHardTo(preApplyHead);
|
|
244
|
-
}
|
|
245
|
-
return {
|
|
246
|
-
status: 'semantic_conflict',
|
|
247
|
-
reason: errorMessage(repairValidationError),
|
|
248
|
-
touchedPaths: gateRepair.changedPaths,
|
|
249
|
-
gateRepair,
|
|
250
|
-
};
|
|
251
|
-
}
|
|
252
175
|
const commit = await input.integrationGit.commitFiles(gateRepair.changedPaths, `ingest: repair WorkUnit ${input.unitKey} gates`, input.author.name, input.author.email);
|
|
253
176
|
if (!commit.created) {
|
|
254
177
|
if (preApplyHead) {
|
|
@@ -1,14 +1,7 @@
|
|
|
1
1
|
import type { AgentRunnerPort } from '../../../context/llm/runtime-port.js';
|
|
2
|
+
import type { ConstrainedRepairResult, RepairVerification } from '../constrained-repair.js';
|
|
2
3
|
import type { IngestTraceWriter } from '../ingest-trace.js';
|
|
3
|
-
export type TextualConflictResolutionResult =
|
|
4
|
-
status: 'repaired';
|
|
5
|
-
attempts: number;
|
|
6
|
-
changedPaths: string[];
|
|
7
|
-
} | {
|
|
8
|
-
status: 'failed';
|
|
9
|
-
attempts: number;
|
|
10
|
-
reason: string;
|
|
11
|
-
};
|
|
4
|
+
export type TextualConflictResolutionResult = ConstrainedRepairResult;
|
|
12
5
|
export interface ResolveTextualConflictInput {
|
|
13
6
|
agentRunner: AgentRunnerPort;
|
|
14
7
|
workdir: string;
|
|
@@ -17,6 +10,12 @@ export interface ResolveTextualConflictInput {
|
|
|
17
10
|
touchedPaths: string[];
|
|
18
11
|
trace: IngestTraceWriter;
|
|
19
12
|
reason: string;
|
|
13
|
+
/**
|
|
14
|
+
* Re-runs the artifact gates against the current worktree. A resolution —
|
|
15
|
+
* including an explicit no-change declaration for a redundant patch —
|
|
16
|
+
* counts as successful only when this passes.
|
|
17
|
+
*/
|
|
18
|
+
verify(changedPaths: string[]): Promise<RepairVerification>;
|
|
20
19
|
maxAttempts?: number;
|
|
21
20
|
stepBudget?: number;
|
|
22
21
|
abortSignal?: AbortSignal;
|