feat(cli)!: remove fast mode; ktx ingest always builds enriched context (KLO-721) (#237)

Fast mode (the ktx ingest --fast/--deep database-ingest depth toggle) is removed.
ktx ingest now always builds the full enriched ("deep") context. There is no
structural fallback: a database connection without a configured model and
embeddings fails the enrichment-readiness preflight before any work runs, with
a 'Run ktx setup to configure a model and embeddings' hint.

- Remove --fast/--deep flags, the per-connection context.depth field, and the
  ktx setup depth prompt (delete setup-database-context-depth.ts).
- Rename ingest-depth.ts -> connection-drivers.ts; ingest always requests scan
  mode 'enriched'; readiness gate (enrichmentReadinessGaps) runs for every
  database target.
- Drop the database-context-depth telemetry step (Node + Python schema mirrors
  regenerated).
- Update CLI, setup, context-build view, docs, the public ktx skill, and the
  release-smoke / artifacts scripts (now assert the no-LLM guard failure).

ktx status --fast (a separate network-probe flag) is unchanged.

Follow-ups: KLO-726 (live progress for ktx ingest --all), KLO-727 (restore
credentialed successful-ingest release smoke coverage).
This commit is contained in:
Andrey Avtomonov 2026-05-29 17:41:04 +02:00 committed by GitHub
parent 637891f030
commit 3f0d11e07d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
34 changed files with 222 additions and 884 deletions

View file

@ -257,7 +257,7 @@ describe('standalone example docs', () => {
assert.match(primarySources, /context:\n queryHistory:/);
assert.match(rootReadme, /`ktx ingest` \| Build context for every configured connection/);
assert.doesNotMatch(rootReadme, /`ktx ingest <id>`/);
assert.match(quickstart, /Databases:\n warehouse: deep context complete/);
assert.match(quickstart, /Databases:\n warehouse: database context complete/);
assert.match(quickstart, /Databases configured: yes \(warehouse\)/);
assert.match(setupReference, /Databases configured: yes \(postgres-warehouse\)/);
assert.doesNotMatch(rootReadme, new RegExp(['Primary sources', 'configured'].join(' ')));

View file

@ -106,7 +106,6 @@ export function buildLiveDatabaseIngestArgs(projectDir, _databaseIntrospectionUr
connectionId,
'--project-dir',
projectDir,
'--fast',
'--no-input',
];
}
@ -152,20 +151,20 @@ function requireSuccess(label, result) {
}
}
function requireFailure(label, result) {
if (result.code === 0) {
throw new Error(
`${label} unexpectedly succeeded\nstdout:\n${result.stdout}\nstderr:\n${result.stderr}`,
);
}
}
function requireOutput(label, result, pattern) {
if (!pattern.test(result.stdout)) {
throw new Error(`${label} output did not match ${pattern}\nstdout:\n${result.stdout}`);
}
}
function getRunId(stdout) {
const match = stdout.match(/^Run: (.+)$/m);
if (!match) {
throw new Error(`ingest output did not include a run id\nstdout:\n${stdout}`);
}
return match[1];
}
async function requireDocker() {
const result = await run('docker', ['info'], { timeout: 20_000 });
if (result.code !== 0) {
@ -310,13 +309,17 @@ async function main() {
env: managedRuntimeEnv(cleanInstallDir),
timeout: 120_000,
});
requireSuccess('ktx ingest warehouse --fast', ingestRun);
requireOutput('ktx ingest warehouse --fast', ingestRun, /Ingest finished/);
requireOutput('ktx ingest warehouse --fast', ingestRun, /Database schema/);
// ktx ingest now always builds enriched context and requires a configured
// model and embeddings. This smoke project has neither, so the database
// target fails the enrichment-readiness preflight before any work runs.
// This still exercises the packaged binary, daemon startup, and the live
// database connection end to end.
requireFailure('ktx ingest warehouse', ingestRun);
requireOutput('ktx ingest warehouse', ingestRun, /Ingest finished with partial failures/);
requireOutput('ktx ingest warehouse', ingestRun, /enrichment is not configured/);
const runId = getRunId(ingestRun.stdout);
await assertPathExists(join(projectDir, '.ktx', 'db.sqlite'), 'SQLite local ingest state');
process.stdout.write(`Installed live-database artifact smoke passed: ${runId}\n`);
process.stdout.write('Installed live-database artifact smoke passed: enrichment-readiness guard verified\n');
} finally {
if (daemonStarted && cleanInstallDir) {
await stopDaemon(cleanInstallDir);

View file

@ -100,7 +100,6 @@ describe('installed live-database artifact smoke helpers', () => {
'warehouse',
'--project-dir',
'/tmp/project',
'--fast',
'--no-input',
]);

View file

@ -512,15 +512,6 @@ function requireSuccess(label, result) {
assert.equal(result.stderr, '', label + ' wrote unexpected stderr');
}
function requireSuccessWithProjectStderr(label, result, projectDir) {
assert.equal(
result.code,
0,
label + ' failed with code ' + result.code + '\\nstdout:\\n' + result.stdout + '\\nstderr:\\n' + result.stderr,
);
assert.equal(result.stderr, 'Project: ' + projectDir + '\\n', label + ' wrote unexpected stderr');
}
function requireExitCodeWithProjectStderr(label, result, projectDir, expectedCode) {
assert.equal(
result.code,
@ -860,27 +851,15 @@ try {
requireOutput('ktx admin runtime stop', runtimeStop, /Stopped KTX daemon/);
process.stdout.write('ktx admin runtime daemon lifecycle verified\\n');
const structuralScan = await run(
const databaseIngest = await run(
...Object.values(
pnpmCommand(['exec', 'ktx', 'ingest', 'warehouse', '--project-dir', projectDir, '--fast', '--no-input']),
pnpmCommand(['exec', 'ktx', 'ingest', 'warehouse', '--project-dir', projectDir, '--no-input']),
),
);
requireSuccessWithProjectStderr('ktx ingest fast', structuralScan, projectDir);
requireOutput('ktx ingest fast', structuralScan, /Ingest finished/);
requireOutput('ktx ingest fast', structuralScan, /Database schema/);
requireOutput('ktx ingest fast', structuralScan, /warehouse\\s+done/);
await access(join(projectDir, 'semantic-layer', 'warehouse', '_schema', 'public.yaml'));
process.stdout.write('ktx ingest fast verified\\n');
const enrichedScan = await run(
...Object.values(
pnpmCommand(['exec', 'ktx', 'ingest', 'warehouse', '--project-dir', projectDir, '--deep', '--no-input']),
),
);
requireExitCodeWithProjectStderr('ktx ingest deep readiness guard', enrichedScan, projectDir, 1);
requireOutput('ktx ingest deep readiness guard', enrichedScan, /Ingest finished with partial failures/);
requireOutput('ktx ingest deep readiness guard', enrichedScan, /requires deep ingest readiness/);
process.stdout.write('ktx ingest deep readiness guard verified\\n');
requireExitCodeWithProjectStderr('ktx ingest enrichment guard', databaseIngest, projectDir, 1);
requireOutput('ktx ingest enrichment guard', databaseIngest, /Ingest finished with partial failures/);
requireOutput('ktx ingest enrichment guard', databaseIngest, /enrichment is not configured/);
process.stdout.write('ktx ingest enrichment guard verified\\n');
await access(join(projectDir, '.ktx', 'db.sqlite'));
process.stdout.write('ktx ingest state verified\\n');

View file

@ -530,10 +530,11 @@ describe('verification snippets', () => {
assert.doesNotMatch(source, /ktx admin runtime prune/);
assert.doesNotMatch(source, /staleRuntimeDir/);
assert.match(source, /pnpmCommand\(\['exec', 'ktx', 'ingest', 'warehouse'/);
assert.match(source, /'--deep'/);
assert.doesNotMatch(source, /'--fast'/);
assert.doesNotMatch(source, /'--deep'/);
assert.doesNotMatch(source, /'--enrich'/);
assert.match(source, /ktx ingest fast verified/);
assert.match(source, /ktx ingest deep readiness guard verified/);
assert.match(source, /ktx ingest enrichment guard verified/);
assert.match(source, /enrichment is not configured/);
assert.match(source, /enrichment:/);
assert.match(source, /mode: deterministic/);
assert.doesNotMatch(source, /run\('pnpm', \['exec', 'ktx', 'ingest', 'run'/);