refactor: enforce ktx naming and AGENTS.md compliance sweep (#289)

Align the tree with AGENTS.md/CLAUDE.md conventions:

- Rewrite user-facing strings, docs, and tests to lowercase `ktx`
  (no bare uppercase `KTX` tokens remain outside literal identifiers).
- Drop the legacy `historicSql` migration path and its now-unused
  helpers, per the no-backward-compat rule.
- Remove `as unknown as` / `any` casts: narrow `BaseTool` generics to
  `z.ZodObject`, add a typed `createLookerClient`, and delete the dead
  `getParametersSchema`/`toAnthropicFormat` pre-AI-SDK helpers.
- Use `InvalidArgumentError` for Commander parse failures.
- Finish the adapter→connector prose conversion in the `ktx.yaml` docs
  while keeping the literal `adapters` config key.
This commit is contained in:
Andrey Avtomonov 2026-06-11 13:49:45 +02:00 committed by GitHub
parent 005c5fc860
commit 00cdf2de90
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
237 changed files with 844 additions and 974 deletions

View file

@ -4,7 +4,7 @@ import { join } from 'node:path';
import { describe, expect, it } from 'vitest';
import { resolveKtxConfigReference, resolveKtxHomePath } from '../../../src/context/core/config-reference.js';
describe('KTX config references', () => {
describe('ktx config references', () => {
it('resolves env references without returning empty values', () => {
expect(resolveKtxConfigReference('env:AI_GATEWAY_API_KEY', { AI_GATEWAY_API_KEY: ' gateway-key ' })).toBe(
'gateway-key',

View file

@ -165,7 +165,7 @@ async function writeHistoricSqlProject(project: KtxLocalProject): Promise<KtxLoc
' state: sqlite',
' search: sqlite-fts5',
' git:',
' author: KTX Test <system@ktx.local>',
' author: ktx Test <system@ktx.local>',
'',
].join('\n'),
'utf-8',
@ -193,7 +193,7 @@ async function writeHistoricSqlProject(project: KtxLocalProject): Promise<KtxLoc
},
},
}),
'KTX Test',
'ktx Test',
'system@ktx.local',
'Seed schema shard',
);

View file

@ -29,7 +29,7 @@ function sdk(): LookerSdkPort {
}
describe('DefaultLookerConnectionClientFactory', () => {
it('resolves credentials by Looker connection id and creates a KTX Looker client', async () => {
it('resolves credentials by Looker connection id and creates a ktx Looker client', async () => {
const fakeSdk = sdk();
const resolver: LookerCredentialResolver = {
resolve: vi.fn().mockResolvedValue({

View file

@ -69,7 +69,7 @@ describe('discoverLookerConnections', () => {
});
describe('looker dialect and target validation helpers', () => {
it('maps Looker dialect names to KTX connection types', () => {
it('maps Looker dialect names to ktx connection types', () => {
expect(lookerDialectToConnectionType('bigquery_standard_sql')).toBe('BIGQUERY');
expect(lookerDialectToConnectionType('postgres')).toBe('POSTGRESQL');
expect(lookerDialectToConnectionType('mssql')).toBeNull();
@ -224,7 +224,7 @@ describe('computeLookerMappingDrift and validateLookerMappings', () => {
).toEqual({
ok: false,
errors: [
{ key: 'b2b_sandbox_bq', reason: 'KTX connection missing does not exist' },
{ key: 'b2b_sandbox_bq', reason: 'ktx connection missing does not exist' },
{
key: 'pg_runtime',
reason: 'Connection type LOOKER cannot be used as a Looker warehouse mapping target',
@ -259,7 +259,7 @@ describe('collectExploreParseItems and projectParsedIdentifier', () => {
});
});
it('projects successful and failed parser rows into KTX parsed target tables', () => {
it('projects successful and failed parser rows into ktx parsed target tables', () => {
expect(
projectParsedIdentifier({
ok: true,

View file

@ -255,7 +255,7 @@ describe('Looker staged runtime schemas', () => {
});
});
it('accepts slug-shaped connection ids inside KTX Looker runtime schemas', () => {
it('accepts slug-shaped connection ids inside ktx Looker runtime schemas', () => {
const parsedTargetTable = {
ok: true as const,
catalog: 'proj',
@ -313,7 +313,7 @@ describe('Looker staged runtime schemas', () => {
});
});
it('rejects unsafe KTX Looker connection ids', () => {
it('rejects unsafe ktx Looker connection ids', () => {
expect(() =>
parseLookerPullConfig({
lookerConnectionId: '../prod-looker',

View file

@ -9,8 +9,8 @@ async function readMetabaseFile(name: string): Promise<string> {
return readFile(join(metabaseDir, name), 'utf-8');
}
describe('KTX Metabase client boundary', () => {
it('keeps NestJS, server data-source base classes, and server-relative imports out of the KTX client', async () => {
describe('ktx Metabase client boundary', () => {
it('keeps NestJS, server data-source base classes, and server-relative imports out of the ktx client', async () => {
const client = await readMetabaseFile('client.ts');
expect(client).not.toContain(`@${'nestjs'}`);
expect(client).not.toContain(`DataSource${'Client'}`);
@ -19,7 +19,7 @@ describe('KTX Metabase client boundary', () => {
expect(client).not.toContain('../../types/brand');
});
it('keeps proxy implementation code out of the KTX v1 client', async () => {
it('keeps proxy implementation code out of the ktx v1 client', async () => {
const client = await readMetabaseFile('client.ts');
expect(client).not.toContain(`network-${'proxy'}`);
expect(client).not.toContain(`ssh${'2'}`);

View file

@ -232,7 +232,7 @@ describe('MetabaseClient admin auth helpers', () => {
);
await expect(client.getPermissionGroups()).resolves.toEqual([{ id: 2, name: 'Administrators' }]);
await expect(client.createApiKey({ name: 'KTX CLI test', groupId: 2 })).resolves.toBe(mintedMetabaseCredential);
await expect(client.createApiKey({ name: 'ktx CLI test', groupId: 2 })).resolves.toBe(mintedMetabaseCredential);
expect(fetchMock).toHaveBeenNthCalledWith(
1,
@ -247,7 +247,7 @@ describe('MetabaseClient admin auth helpers', () => {
'https://metabase.example.test/api/api-key',
expect.objectContaining({
method: 'POST',
body: JSON.stringify({ name: 'KTX CLI test', group_id: 2 }),
body: JSON.stringify({ name: 'ktx CLI test', group_id: 2 }),
}),
);
});

View file

@ -57,7 +57,7 @@ describe('metabaseRuntimeConfigFromLocalConnection', () => {
};
expect(() => metabaseRuntimeConfigFromLocalConnection('prod-metabase', connection)).toThrow(
'Standalone KTX does not support proxy-bearing Metabase connections yet',
'Standalone ktx does not support proxy-bearing Metabase connections yet',
);
});

View file

@ -87,7 +87,7 @@ describe('validateMetabaseMappings', () => {
}),
).toEqual({
ok: false,
errors: [{ key: '2', reason: 'KTX connection missing-target does not exist' }],
errors: [{ key: '2', reason: 'ktx connection missing-target does not exist' }],
});
});
});
@ -149,7 +149,7 @@ describe('validateMappingPhysicalMatch', () => {
).toBeNull();
});
it('returns null for unknown engines because KTX cannot validate them', () => {
it('returns null for unknown engines because ktx cannot validate them', () => {
expect(
validateMappingPhysicalMatch(
{ metabaseEngine: 'unknown-engine', metabaseDbName: 'X', metabaseHost: 'host' },
@ -177,7 +177,7 @@ describe('computeMetabaseMappingPhysicalMismatches', () => {
).toEqual([
{
mappingId: 'mapping-bad',
reason: "Metabase database 'app' does not match KTX connection database 'other_app'",
reason: "Metabase database 'app' does not match ktx connection database 'other_app'",
},
]);
});
@ -216,7 +216,7 @@ describe('refreshMetabaseMapping', () => {
physicalMismatches: [
{
mappingId: '2',
reason: "Metabase database 'analytics' does not match KTX connection database 'wrong_database'",
reason: "Metabase database 'analytics' does not match ktx connection database 'wrong_database'",
},
],
});
@ -282,7 +282,7 @@ describe('findBestMatch', () => {
});
describe('METABASE_ENGINE_TO_CONNECTION_TYPE', () => {
it('keeps the server-supported Metabase engine table in KTX', () => {
it('keeps the server-supported Metabase engine table in ktx', () => {
expect(METABASE_ENGINE_TO_CONNECTION_TYPE).toMatchObject({
postgres: 'POSTGRESQL',
bigquery: 'BIGQUERY',

View file

@ -213,7 +213,7 @@ function makeDeps(
lockingService: { withLock: vi.fn(async (_key, fn) => fn()) },
storage: {
homeDir: join(runtime.configDir, '.ktx'),
systemGitAuthor: { name: 'KTX Test', email: 'system@ktx.local' },
systemGitAuthor: { name: 'ktx Test', email: 'system@ktx.local' },
resolveUploadDir: (id) => join(runtime.homeDir, 'upload', id),
resolvePullDir: (id) => join(runtime.homeDir, 'pull', id),
resolveTranscriptDir: (id) => join(runtime.configDir, '.ktx/ingest-transcripts', id),
@ -308,7 +308,7 @@ describe('IngestBundleRunner isolated diff path', () => {
await currentSession.gitService.commitFiles(
['wiki/global/custom-isolated.md'],
'custom wiki',
'KTX Test',
'ktx Test',
'system@ktx.local',
);
return { stopReason: 'natural' };
@ -395,7 +395,7 @@ describe('IngestBundleRunner isolated diff path', () => {
await currentSession.gitService.commitFiles(
['wiki/global/legacy-isolated.md'],
'legacy isolated wiki',
'KTX Test',
'ktx Test',
'system@ktx.local',
);
return { stopReason: 'natural' };
@ -486,7 +486,7 @@ describe('IngestBundleRunner isolated diff path', () => {
await currentSession.gitService.commitFiles(
['semantic-layer/warehouse/good.yaml'],
'test: add good source',
'KTX Test',
'ktx Test',
'system@ktx.local',
);
}
@ -504,7 +504,7 @@ describe('IngestBundleRunner isolated diff path', () => {
await currentSession.gitService.commitFiles(
['semantic-layer/warehouse/bad.yaml'],
'test: add bad source',
'KTX Test',
'ktx Test',
'system@ktx.local',
);
}
@ -606,7 +606,7 @@ describe('IngestBundleRunner isolated diff path', () => {
await currentSession.gitService.commitFiles(
[`wiki/global/${sourceKey}-isolated.md`],
`${sourceKey} wiki`,
'KTX Test',
'ktx Test',
'system@ktx.local',
);
return { stopReason: 'natural' };
@ -682,7 +682,7 @@ describe('IngestBundleRunner isolated diff path', () => {
'---\nsummary: Account segments\nusage_mode: auto\nsl_refs:\n - mart_account_segments\n---\n\nARR is `mart_account_segments.total_contract_arr_cents`.\n',
);
currentSession.actions.push({ target: 'wiki', type: 'created', key: 'account-segments', detail: 'Account segments' });
await currentSession.gitService.commitFiles(['wiki/global/account-segments.md'], 'wu wiki', 'KTX Test', 'system@ktx.local');
await currentSession.gitService.commitFiles(['wiki/global/account-segments.md'], 'wu wiki', 'ktx Test', 'system@ktx.local');
}
if (params.telemetryTags.unitKey === 'card-source') {
await writeFile(
@ -697,7 +697,7 @@ describe('IngestBundleRunner isolated diff path', () => {
detail: 'Dollar measure',
targetConnectionId: 'warehouse',
});
await currentSession.gitService.commitFiles(['semantic-layer/warehouse/mart_account_segments.yaml'], 'wu source', 'KTX Test', 'system@ktx.local');
await currentSession.gitService.commitFiles(['semantic-layer/warehouse/mart_account_segments.yaml'], 'wu source', 'ktx Test', 'system@ktx.local');
}
return { stopReason: 'natural' };
}) as never;
@ -740,7 +740,7 @@ describe('IngestBundleRunner isolated diff path', () => {
await runtime.git.commitFiles(
['semantic-layer/warehouse/mart_account_segments.yaml', 'wiki/global/account-segments.md'],
'seed existing wiki body ref',
'KTX Test',
'ktx Test',
'system@ktx.local',
);
const preRunHead = await runtime.git.revParseHead();
@ -773,7 +773,7 @@ describe('IngestBundleRunner isolated diff path', () => {
await currentSession.gitService.commitFiles(
['semantic-layer/warehouse/mart_account_segments.yaml'],
'wu source rename',
'KTX Test',
'ktx Test',
'system@ktx.local',
);
return { stopReason: 'natural' };
@ -903,7 +903,7 @@ describe('IngestBundleRunner isolated diff path', () => {
await mkdir(join(root, 'wiki/global'), { recursive: true });
await writeFile(join(root, `wiki/global/${unitKey}.md`), `---\nsummary: ${unitKey}\nusage_mode: auto\n---\n\n${unitKey}\n`);
currentSession.actions.push({ target: 'wiki', type: 'created', key: unitKey, detail: unitKey });
await currentSession.gitService.commitFiles([`wiki/global/${unitKey}.md`], `wu ${unitKey}`, 'KTX Test', 'system@ktx.local');
await currentSession.gitService.commitFiles([`wiki/global/${unitKey}.md`], `wu ${unitKey}`, 'ktx Test', 'system@ktx.local');
return { stopReason: 'natural' };
}) as never;
const runner = new IngestBundleRunner(deps);
@ -950,7 +950,7 @@ describe('IngestBundleRunner isolated diff path', () => {
);
addTouchedSlSource(currentSession.touchedSlSources, 'warehouse', 'orders');
currentSession.actions.push({ target: 'sl', type: 'updated', key: 'orders', detail: suffix, targetConnectionId: 'warehouse' });
await currentSession.gitService.commitFiles(['semantic-layer/warehouse/orders.yaml'], `wu ${suffix}`, 'KTX Test', 'system@ktx.local');
await currentSession.gitService.commitFiles(['semantic-layer/warehouse/orders.yaml'], `wu ${suffix}`, 'ktx Test', 'system@ktx.local');
return { stopReason: 'natural' };
}) as never;
const runner = new IngestBundleRunner(deps);
@ -1006,7 +1006,7 @@ describe('IngestBundleRunner isolated diff path', () => {
'---\nsummary: Projected orders\nusage_mode: auto\nsl_refs:\n - mart_account_segments\n---\n\nARR `mart_account_segments.total_contract_arr`.\n',
);
currentSession.actions.push({ target: 'wiki', type: 'created', key: 'projected-orders', detail: 'Projected orders' });
await currentSession.gitService.commitFiles(['wiki/global/projected-orders.md'], 'wu projected wiki', 'KTX Test', 'system@ktx.local');
await currentSession.gitService.commitFiles(['wiki/global/projected-orders.md'], 'wu projected wiki', 'ktx Test', 'system@ktx.local');
return { stopReason: 'natural' };
}) as never;
const runner = new IngestBundleRunner(deps);
@ -1042,7 +1042,7 @@ describe('IngestBundleRunner isolated diff path', () => {
await mkdir(join(root, 'wiki/global'), { recursive: true });
await writeFile(join(root, 'wiki/global/notion-page.md'), '---\nsummary: Notion page\nusage_mode: auto\nsl_refs:\n - missing_source\n---\n\nBody\n');
currentSession.actions.push({ target: 'wiki', type: 'created', key: 'notion-page', detail: 'Notion page' });
await currentSession.gitService.commitFiles(['wiki/global/notion-page.md'], 'wu notion', 'KTX Test', 'system@ktx.local');
await currentSession.gitService.commitFiles(['wiki/global/notion-page.md'], 'wu notion', 'ktx Test', 'system@ktx.local');
return { stopReason: 'natural' };
}) as never;
const runner = new IngestBundleRunner(deps);
@ -1088,7 +1088,7 @@ describe('IngestBundleRunner isolated diff path', () => {
await currentSession.gitService.commitFiles(
['semantic-layer/warehouse/mart_account_segments.yaml'],
'wu source',
'KTX Test',
'ktx Test',
'system@ktx.local',
);
} else {
@ -1104,7 +1104,7 @@ describe('IngestBundleRunner isolated diff path', () => {
detail: 'Stale reconcile wiki page',
rawPaths: ['cards/source.json'],
});
await currentSession.gitService.commitFiles(['wiki/global/account-segments.md'], 'reconcile wiki', 'KTX Test', 'system@ktx.local');
await currentSession.gitService.commitFiles(['wiki/global/account-segments.md'], 'reconcile wiki', 'ktx Test', 'system@ktx.local');
}
return { stopReason: 'natural' };
}) as never;
@ -1167,7 +1167,7 @@ describe('IngestBundleRunner isolated diff path', () => {
detail: 'Account segments',
rawPaths: ['cards/wiki.json'],
});
await currentSession.gitService.commitFiles(['wiki/global/account-segments.md'], 'wu wiki', 'KTX Test', 'system@ktx.local');
await currentSession.gitService.commitFiles(['wiki/global/account-segments.md'], 'wu wiki', 'ktx Test', 'system@ktx.local');
}
if (params.telemetryTags.unitKey === 'card-source') {
await mkdir(join(root, 'semantic-layer/warehouse'), { recursive: true });
@ -1187,7 +1187,7 @@ describe('IngestBundleRunner isolated diff path', () => {
await currentSession.gitService.commitFiles(
['semantic-layer/warehouse/mart_account_segments.yaml'],
'wu source',
'KTX Test',
'ktx Test',
'system@ktx.local',
);
}
@ -1302,7 +1302,7 @@ describe('IngestBundleRunner isolated diff path', () => {
await currentSession.gitService.commitFiles(
['semantic-layer/warehouse/mart_account_segments.yaml', 'wiki/global/account-segments.md'],
'valid artifacts with invalid provenance',
'KTX Test',
'ktx Test',
'system@ktx.local',
);
return { stopReason: 'natural' };
@ -1444,7 +1444,7 @@ describe('IngestBundleRunner isolated diff path', () => {
'name: orders\ngrain: [id]\ncolumns: [{name: id, type: string}]\njoins: []\nmeasures: []\n',
);
currentSession.actions.push({ target: 'sl', type: 'created', key: 'orders', detail: 'forbidden', targetConnectionId: 'warehouse' });
await currentSession.gitService.commitFiles(['semantic-layer/warehouse/orders.yaml'], 'forbidden sl', 'KTX Test', 'system@ktx.local');
await currentSession.gitService.commitFiles(['semantic-layer/warehouse/orders.yaml'], 'forbidden sl', 'ktx Test', 'system@ktx.local');
return { stopReason: 'natural' };
}) as never;
const runner = new IngestBundleRunner(deps);
@ -1469,7 +1469,7 @@ describe('IngestBundleRunner isolated diff path', () => {
join(runtime.configDir, 'wiki/global/source-page.md'),
'---\nsummary: Source page\nusage_mode: auto\n---\n\nSource page\n',
);
await runtime.git.commitFiles(['wiki/global/source-page.md'], 'seed source page', 'KTX Test', 'system@ktx.local');
await runtime.git.commitFiles(['wiki/global/source-page.md'], 'seed source page', 'ktx Test', 'system@ktx.local');
const preRunHead = await runtime.git.revParseHead();
const { deps, adapter } = makeDeps(runtime);
adapter.chunk.mockResolvedValue({
@ -1501,7 +1501,7 @@ describe('IngestBundleRunner isolated diff path', () => {
await currentSession.gitService.commitFiles(
['wiki/global/account-segments.md'],
'wu page ref',
'KTX Test',
'ktx Test',
'system@ktx.local',
);
}
@ -1517,7 +1517,7 @@ describe('IngestBundleRunner isolated diff path', () => {
await currentSession.gitService.commitFiles(
['wiki/global/source-page.md'],
'wu delete source page',
'KTX Test',
'ktx Test',
'system@ktx.local',
);
}
@ -1582,7 +1582,7 @@ describe('IngestBundleRunner isolated diff path', () => {
await runtime.git.commitFiles(
['wiki/global/source-page.md', 'wiki/global/account-segments.md'],
'seed inbound wiki refs',
'KTX Test',
'ktx Test',
'system@ktx.local',
);
const preRunHead = await runtime.git.revParseHead();
@ -1613,7 +1613,7 @@ describe('IngestBundleRunner isolated diff path', () => {
await currentSession.gitService.commitFiles(
['wiki/global/source-page.md'],
'wu delete target page',
'KTX Test',
'ktx Test',
'system@ktx.local',
);
return { stopReason: 'natural' };
@ -1751,7 +1751,7 @@ describe('IngestBundleRunner isolated diff path', () => {
await currentSession.gitService.commitFiles(
['semantic-layer/finance/orders.yaml'],
'wu unauthorized target',
'KTX Test',
'ktx Test',
'system@ktx.local',
);
return { stopReason: 'natural' };
@ -1822,7 +1822,7 @@ describe('IngestBundleRunner isolated diff path', () => {
detail: 'Valid page',
rawPaths: ['pages/source.json'],
});
await currentSession.gitService.commitFiles(['wiki/global/valid-page.md'], 'wu valid page', 'KTX Test', 'system@ktx.local');
await currentSession.gitService.commitFiles(['wiki/global/valid-page.md'], 'wu valid page', 'ktx Test', 'system@ktx.local');
} else {
await mkdir(join(root, 'semantic-layer/finance'), { recursive: true });
await writeFile(
@ -1841,7 +1841,7 @@ describe('IngestBundleRunner isolated diff path', () => {
await currentSession.gitService.commitFiles(
['semantic-layer/finance/reconcile_orders.yaml'],
'reconcile unauthorized target',
'KTX Test',
'ktx Test',
'system@ktx.local',
);
}
@ -1959,7 +1959,7 @@ describe('IngestBundleRunner isolated diff path', () => {
await currentSession.gitService.commitFiles(
['semantic-layer/warehouse/mart_account_segments.yaml'],
`wu ${params.telemetryTags.unitKey}`,
'KTX Test',
'ktx Test',
'system@ktx.local',
);
return { stopReason: 'natural' };
@ -2025,7 +2025,7 @@ describe('IngestBundleRunner isolated diff path', () => {
await runtime.git.commitFiles(
['semantic-layer/warehouse/mart_account_segments.yaml', 'wiki/global/account-segments.md'],
'seed stale wiki body ref',
'KTX Test',
'ktx Test',
'system@ktx.local',
);
@ -2073,7 +2073,7 @@ describe('IngestBundleRunner isolated diff path', () => {
await currentSession.gitService.commitFiles(
['semantic-layer/warehouse/mart_account_segments.yaml'],
'wu source rename',
'KTX Test',
'ktx Test',
'system@ktx.local',
);
return { stopReason: 'natural' as const };
@ -2128,7 +2128,7 @@ describe('IngestBundleRunner isolated diff path', () => {
await runtime.git.commitFiles(
['semantic-layer/warehouse/mart_account_segments.yaml', 'wiki/global/account-segments.md'],
'seed stale wiki body ref',
'KTX Test',
'ktx Test',
'system@ktx.local',
);
const preRunHead = await runtime.git.revParseHead();
@ -2168,7 +2168,7 @@ describe('IngestBundleRunner isolated diff path', () => {
await currentSession.gitService.commitFiles(
['semantic-layer/warehouse/mart_account_segments.yaml'],
'wu source rename',
'KTX Test',
'ktx Test',
'system@ktx.local',
);
return { stopReason: 'natural' as const };
@ -2302,7 +2302,7 @@ describe('IngestBundleRunner isolated diff path', () => {
await currentSession.gitService.commitFiles(
['wiki/global/orders.md'],
'wu orders',
'KTX Test',
'ktx Test',
'system@ktx.local',
);
return { stopReason: 'natural' as const };

View file

@ -261,7 +261,7 @@ const buildRunner = (deps: ReturnType<typeof makeDeps> = makeDeps(), overrides:
lockingService: deps.lockingService as any,
storage: {
homeDir: '/tmp/ktx-test',
systemGitAuthor: { name: 'KTX Test', email: 'system@ktx.local' },
systemGitAuthor: { name: 'ktx Test', email: 'system@ktx.local' },
resolveUploadDir: (uploadId) => `/tmp/ktx-test/ingest-uploads/${uploadId}`,
resolvePullDir: (jobId) => `/tmp/ktx-test/ingest-pulls/${jobId}`,
resolveTranscriptDir: (jobId) => `/tmp/ktx-test/run/wu-transcripts/${jobId}`,
@ -1518,7 +1518,7 @@ describe('IngestBundleRunner — Stages 1 → 7', () => {
...(buildRunner(deps) as any).deps,
storage: {
homeDir: tempRoot,
systemGitAuthor: { name: 'KTX Test', email: 'system@ktx.local' },
systemGitAuthor: { name: 'ktx Test', email: 'system@ktx.local' },
resolveUploadDir: (uploadId: string) => join(tempRoot, 'ingest-uploads', uploadId),
resolvePullDir: (jobId: string) => join(tempRoot, 'ingest-pulls', jobId),
resolveTranscriptDir: (jobId: string) => join(tempRoot, 'run', 'wu-transcripts', jobId),

View file

@ -18,14 +18,14 @@ describe('ingest prompt assets', () => {
expect(prompt).toContain('Do not create a duplicate contested artifact');
});
it('uses product-neutral KTX runtime wording', async () => {
it('uses product-neutral ktx runtime wording', async () => {
const prompt = await readFile(
new URL('../../../src/prompts/memory_agent_bundle_ingest_work_unit.md', import.meta.url),
'utf-8',
);
expect(prompt).toContain('KTX semantic-layer sources and/or knowledge wiki pages');
expect(prompt).toContain('maps cleanly to KTX');
expect(prompt).toContain('ktx semantic-layer sources and/or knowledge wiki pages');
expect(prompt).toContain('maps cleanly to ktx');
expect(prompt).not.toMatch(forbiddenProductPattern());
});

View file

@ -34,7 +34,7 @@ function forbiddenProductPattern() {
}
describe('ingest runtime assets', () => {
it('resolves every reusable ingest skill from packaged KTX assets without server fallback', async () => {
it('resolves every reusable ingest skill from packaged ktx assets without server fallback', async () => {
const registry = new SkillsRegistryService({ skillsDir });
const expected = [...new Set([...adapterSkillNames, ...adapterReconcileSkillNames])].sort();
@ -48,7 +48,7 @@ describe('ingest runtime assets', () => {
}
});
it('loads page-triage and light-extraction prompts from packaged KTX prompt assets', async () => {
it('loads page-triage and light-extraction prompts from packaged ktx prompt assets', async () => {
const prompts = new PromptService({ promptsDir, partials: [] });
for (const promptName of pageTriagePromptNames) {
@ -61,7 +61,7 @@ describe('ingest runtime assets', () => {
await expect(prompts.loadPrompt('skills/light_extraction')).resolves.toContain('# Light Context Extraction');
});
it('packages historic-SQL table digest guidance from KTX assets', async () => {
it('packages historic-SQL table digest guidance from ktx assets', async () => {
const registry = new SkillsRegistryService({ skillsDir });
const skills = await registry.listSkills(['historic_sql_table_digest'], 'memory_agent');
@ -77,7 +77,7 @@ describe('ingest runtime assets', () => {
expect(body).not.toMatch(forbiddenProductPattern());
});
it('packages historic-SQL patterns guidance from KTX assets', async () => {
it('packages historic-SQL patterns guidance from ktx assets', async () => {
const registry = new SkillsRegistryService({ skillsDir });
const skills = await registry.listSkills(['historic_sql_patterns'], 'memory_agent');

View file

@ -49,7 +49,7 @@ describe('integrateWorkUnitPatch', () => {
patchPath,
integrationGit: git,
trace,
author: { name: 'KTX Test', email: 'system@ktx.local' },
author: { name: 'ktx Test', email: 'system@ktx.local' },
validateAppliedTree: vi.fn().mockResolvedValue(undefined),
slDisallowed: false,
allowedTargetConnectionIds: new Set(['c1']),
@ -82,7 +82,7 @@ describe('integrateWorkUnitPatch', () => {
patchPath,
integrationGit: git,
trace,
author: { name: 'KTX Test', email: 'system@ktx.local' },
author: { name: 'ktx Test', email: 'system@ktx.local' },
validateAppliedTree: vi.fn().mockRejectedValue(new Error('final artifact gates failed')),
slDisallowed: false,
allowedTargetConnectionIds: new Set(['c1']),
@ -117,7 +117,7 @@ describe('integrateWorkUnitPatch', () => {
patchPath,
integrationGit: git,
trace,
author: { name: 'KTX Test', email: 'system@ktx.local' },
author: { name: 'ktx Test', email: 'system@ktx.local' },
validateAppliedTree: vi.fn().mockResolvedValue(undefined),
slDisallowed: true,
allowedTargetConnectionIds: new Set(['c1']),
@ -158,7 +158,7 @@ describe('integrateWorkUnitPatch', () => {
patchPath,
integrationGit: git,
trace,
author: { name: 'KTX Test', email: 'system@ktx.local' },
author: { name: 'ktx Test', email: 'system@ktx.local' },
validateAppliedTree: vi.fn().mockResolvedValue(undefined),
slDisallowed: false,
allowedTargetConnectionIds: new Set(['warehouse']),
@ -325,7 +325,7 @@ describe('integrateWorkUnitPatch', () => {
patchPath,
integrationGit: git,
trace,
author: { name: 'KTX Test', email: 'system@ktx.local' },
author: { name: 'ktx Test', email: 'system@ktx.local' },
validateAppliedTree,
slDisallowed: false,
allowedTargetConnectionIds: new Set(['c1']),
@ -380,7 +380,7 @@ describe('integrateWorkUnitPatch', () => {
patchPath,
integrationGit: git,
trace,
author: { name: 'KTX Test', email: 'system@ktx.local' },
author: { name: 'ktx Test', email: 'system@ktx.local' },
validateAppliedTree: vi.fn().mockRejectedValue(new Error('final artifact gates failed')),
slDisallowed: false,
allowedTargetConnectionIds: new Set(['c1']),

View file

@ -65,7 +65,7 @@ describe('runIsolatedWorkUnit', () => {
run: async (child) => {
await mkdir(join(child.workdir, 'wiki/global'), { recursive: true });
await writeFile(join(child.workdir, 'wiki/global/a.md'), '---\nsummary: A\nusage_mode: auto\n---\n\nBody\n');
await child.git.commitFiles(['wiki/global/a.md'], 'test: write wiki', 'KTX Test', 'system@ktx.local');
await child.git.commitFiles(['wiki/global/a.md'], 'test: write wiki', 'ktx Test', 'system@ktx.local');
return {
unitKey: 'wu-1',
status: 'success',

View file

@ -521,7 +521,7 @@ describe('canonical local ingest', () => {
' state: sqlite',
' search: sqlite-fts5',
' git:',
' author: KTX Test <system@ktx.local>',
' author: ktx Test <system@ktx.local>',
'',
].join('\n'),
'utf-8',
@ -530,7 +530,7 @@ describe('canonical local ingest', () => {
await historicProject.fileStore.writeFile(
'semantic-layer/warehouse/_schema/public.yaml',
YAML.stringify({ tables: { orders: { table: 'public.orders', columns: [{ name: 'id', type: 'string' }] } } }),
'KTX Test',
'ktx Test',
'system@ktx.local',
'Seed schema shard',
);
@ -682,7 +682,7 @@ describe('canonical local ingest', () => {
' state: sqlite',
' search: sqlite-fts5',
' git:',
' author: KTX Test <system@ktx.local>',
' author: ktx Test <system@ktx.local>',
'',
].join('\n'),
'utf-8',
@ -765,7 +765,7 @@ describe('canonical local ingest', () => {
' state: sqlite',
' search: sqlite-fts5',
' git:',
' author: KTX Test <system@ktx.local>',
' author: ktx Test <system@ktx.local>',
'',
].join('\n'),
'utf-8',
@ -808,7 +808,7 @@ describe('canonical local ingest', () => {
' state: sqlite',
' search: sqlite-fts5',
' git:',
' author: KTX Test <system@ktx.local>',
' author: ktx Test <system@ktx.local>',
'',
].join('\n'),
'utf-8',

View file

@ -596,7 +596,7 @@ describe('local ingest', () => {
});
});
it('includes upload-capable KTX adapters in default local ingest adapters', () => {
it('includes upload-capable ktx adapters in default local ingest adapters', () => {
expect(createDefaultLocalIngestAdapters(project).map((adapter) => adapter.source)).toEqual(
expect.arrayContaining(['dbt', 'metricflow', 'notion']),
);

View file

@ -17,7 +17,7 @@ describe('memory-flow acceptance scenarios', () => {
it('renders a completed replay with a clear saved-memory completion line', () => {
const output = renderScenario(successfulReplayScenario());
expect(output).toContain('KTX memory flow warehouse/metricflow done');
expect(output).toContain('ktx memory flow warehouse/metricflow done');
expect(output).toContain('Saved 3 memories from 4 raw files: 2 wiki pages, 1 SL updates.');
expect(output).toContain('Commit: abc12345 Run: run-success Report: ingest-report.json');
});
@ -48,7 +48,7 @@ describe('memory-flow acceptance scenarios', () => {
it('renders no ANSI color codes in the text fallback for terminals without color support', () => {
const output = renderScenario(successfulReplayScenario(), 80);
expect(output).toContain('KTX memory flow warehouse/metricflow done');
expect(output).toContain('ktx memory flow warehouse/metricflow done');
expect(output).not.toMatch(/\u001b\[[0-9;]*m/);
});

View file

@ -13,7 +13,7 @@ import type { MemoryFlowInteractionState, MemoryFlowViewModel } from '../../../.
function view(): MemoryFlowViewModel {
return {
title: 'KTX memory flow warehouse/metricflow running',
title: 'ktx memory flow warehouse/metricflow running',
subtitle: 'Run run-1 Sync sync-1',
status: 'running',
activeLine: 'active: WorkUnit orders step 2/4',

View file

@ -5,7 +5,7 @@ import type { MemoryFlowViewModel } from '../../../../src/context/ingest/memory-
function view(): MemoryFlowViewModel {
return {
title: 'KTX memory flow warehouse/metricflow done',
title: 'ktx memory flow warehouse/metricflow done',
subtitle: 'Run run-1 Sync sync-1',
status: 'done',
activeLine: 'active: complete',
@ -128,7 +128,7 @@ describe('renderMemoryFlowInteractive', () => {
const output = renderMemoryFlowInteractive(view(), state, { terminalWidth: 140 });
expect(output).toContain('KTX memory flow warehouse/metricflow done');
expect(output).toContain('ktx memory flow warehouse/metricflow done');
expect(output).toContain('OK SOURCE -> OK CHUNKS -> !! WORKUNITS -> OK ACTIONS -> !! GATES -> OK SAVED');
expect(output).toContain('[WORKUNITS]');
expect(output).toContain('> orders');

View file

@ -4,7 +4,7 @@ import { renderMemoryFlowReplay } from '../../../../src/context/ingest/memory-fl
function view(): MemoryFlowViewModel {
return {
title: 'KTX memory flow warehouse/metricflow done',
title: 'ktx memory flow warehouse/metricflow done',
subtitle: 'Run run-1 Sync sync-1',
status: 'done',
activeLine: 'active: complete',
@ -79,7 +79,7 @@ describe('renderMemoryFlowReplay', () => {
'OK SOURCE -> OK CHUNKS -> !! WORKUNITS -> OK ACTIONS -> !! GATES -> OK SAVED',
);
expect(renderMemoryFlowReplay(view(), { terminalWidth: 140 })).toMatchInlineSnapshot(`
"KTX memory flow warehouse/metricflow done
"ktx memory flow warehouse/metricflow done
active: complete
Run run-1 Sync sync-1
OK SOURCE -> OK CHUNKS -> !! WORKUNITS -> OK ACTIONS -> !! GATES -> OK SAVED

View file

@ -93,7 +93,7 @@ describe('buildMemoryFlowViewModel', () => {
it('builds six readable columns from replay events', () => {
const view = buildMemoryFlowViewModel(replayInput());
expect(view.title).toBe('KTX memory flow warehouse/metricflow done');
expect(view.title).toBe('ktx memory flow warehouse/metricflow done');
expect(view.activeLine).toBe('active: complete');
expect(view.columns.map((column) => column.id)).toEqual([
'source',
@ -179,7 +179,7 @@ describe('buildMemoryFlowViewModel', () => {
details: { actions: [], provenance: [], transcripts: [] },
});
expect(view.title).toBe('KTX memory flow Warehouse + dbt + BI + Docs done');
expect(view.title).toBe('ktx memory flow Warehouse + dbt + BI + Docs done');
expect(view.columns.find((column) => column.id === 'source')?.counters[0]).toBe('Warehouse, dbt, BI, Docs');
expect(view.completionLine).toContain('Saved 16 memories from 29 raw files');
});

View file

@ -11,7 +11,7 @@ function viewWithStatuses(statuses: Array<'waiting' | 'active' | 'complete' | 'w
const ids = ['source', 'chunks', 'workUnits', 'actions', 'gates', 'saved'] as const;
return {
title: 'KTX memory flow warehouse/metricflow running',
title: 'ktx memory flow warehouse/metricflow running',
subtitle: 'Run run-1 Sync sync-1',
status: 'running',
activeLine: 'active: WorkUnit orders',

View file

@ -198,7 +198,7 @@ describe('PageTriageService', () => {
'Reusable outbound sequence:',
'',
'- Ask about current customer success expansion workflow.',
'- Position KTX as AI search visibility for CS teams.',
'- Position ktx as AI search visibility for CS teams.',
'- Close with a discovery call request.',
].join('\n'),
'utf-8',
@ -233,7 +233,7 @@ describe('PageTriageService', () => {
{
candidateKey: 'cold-call-script',
topic: 'Cold Call Script',
assertion: 'Cold call outreach should position KTX around AI search visibility for CS teams.',
assertion: 'Cold call outreach should position ktx around AI search visibility for CS teams.',
rationale: 'The script gives a reusable outbound call sequence and positioning language.',
evidenceChunkIds: ['00000000-0000-0000-0000-000000000101'],
suggestedPageKey: 'cold-call-script',

View file

@ -106,7 +106,7 @@ describe('repo-fetch', () => {
const cacheGit = createSimpleGit(cacheDir);
await cacheGit.addConfig('user.email', 'test@ktx.local');
await cacheGit.addConfig('user.name', 'KTX Test');
await cacheGit.addConfig('user.name', 'ktx Test');
await writeFile(join(cacheDir, 'local-only.txt'), 'local commit\n', 'utf-8');
await cacheGit.add('.');
await cacheGit.commit('local-only divergent commit');

View file

@ -362,7 +362,7 @@ describe('ClaudeCodeKtxLlmRuntime', () => {
});
});
it('registers only exact KTX MCP tool ids and denies non-KTX tools', async () => {
it('registers only exact ktx MCP tool ids and denies non-ktx tools', async () => {
const query = vi.fn((_input: any) =>
stream([
initMessage({ tools: ['mcp__ktx__load_skill'], mcp_servers: [{ name: 'ktx', status: 'connected' }] }),
@ -487,7 +487,7 @@ describe('ClaudeCodeKtxLlmRuntime', () => {
);
});
it('allows host-discovered context during agent loops while requiring exact KTX MCP tools and servers', async () => {
it('allows host-discovered context during agent loops while requiring exact ktx MCP tools and servers', async () => {
const query = vi.fn((_input: any) =>
stream([
initMessage({
@ -553,7 +553,7 @@ describe('ClaudeCodeKtxLlmRuntime', () => {
});
});
it('still rejects unexpected tools, missing KTX tools, plugins, and non-KTX MCP servers from init messages', async () => {
it('still rejects unexpected tools, missing ktx tools, plugins, and non-ktx MCP servers from init messages', async () => {
const query = vi.fn((_input: any) =>
stream([
initMessage({

View file

@ -1,7 +1,7 @@
import { describe, expect, it, vi } from 'vitest';
import { KtxIngestEmbeddingPortAdapter, KtxScanEmbeddingPortAdapter } from '../../../src/context/llm/embedding-port.js';
describe('KTX embedding port adapters', () => {
describe('ktx embedding port adapters', () => {
it('adapts LLM modules embeddings to ingest embedding port shape', async () => {
const provider = {
dimensions: 3,

View file

@ -12,7 +12,7 @@ import {
resolveLocalKtxLlmConfig,
} from '../../../src/context/llm/local-config.js';
describe('local KTX LLM config', () => {
describe('local ktx LLM config', () => {
it('resolves env and file references into a KtxLlmConfig', () => {
const config: KtxProjectLlmConfig = {
provider: {
@ -190,7 +190,7 @@ describe('local KTX LLM config', () => {
});
});
describe('local KTX embedding config', () => {
describe('local ktx embedding config', () => {
it('resolves sentence-transformers config', () => {
const config: KtxProjectEmbeddingConfig = {
backend: 'sentence-transformers',

View file

@ -1,7 +1,7 @@
import { describe, expect, it, vi } from 'vitest';
import { createLocalKtxLlmProviderFromConfig, createLocalKtxLlmRuntimeFromConfig } from '../../../src/context/llm/local-config.js';
describe('local KTX LLM runtime config', () => {
describe('local ktx LLM runtime config', () => {
it('creates a Claude Code runtime for claude-code backend without creating an AI SDK provider', () => {
const runtime = createLocalKtxLlmRuntimeFromConfig(
{

View file

@ -2,7 +2,7 @@
{
"name": "connection_list",
"title": "Connection List",
"description": "List configured read-only data connections available to this KTX project. Use this before connection-scoped tools when the project may have multiple warehouses.",
"description": "List configured read-only data connections available to this ktx project. Use this before connection-scoped tools when the project may have multiple warehouses.",
"inputSchema": {
"type": "object",
"properties": {},
@ -54,7 +54,7 @@
{
"name": "wiki_search",
"title": "Wiki Search",
"description": "Search KTX wiki pages for reusable business context. Example: wiki_search({ query: \"revenue recognition\", limit: 5 }).",
"description": "Search ktx wiki pages for reusable business context. Example: wiki_search({ query: \"revenue recognition\", limit: 5 }).",
"inputSchema": {
"type": "object",
"properties": {
@ -181,7 +181,7 @@
{
"name": "wiki_read",
"title": "Wiki Read",
"description": "Read a KTX wiki page by key returned from wiki_search. Example: wiki_read({ key: \"global/revenue\" }).",
"description": "Read a ktx wiki page by key returned from wiki_search. Example: wiki_read({ key: \"global/revenue\" }).",
"inputSchema": {
"type": "object",
"properties": {
@ -1227,7 +1227,7 @@
{
"name": "discover_data",
"title": "Discover Data",
"description": "Search across KTX wiki pages, semantic-layer sources, measures, dimensions, raw tables, and columns. Example: discover_data({ query: \"monthly orders by customer\", connectionId: \"warehouse\", kinds: [\"sl_source\", \"table\"] }).",
"description": "Search across ktx wiki pages, semantic-layer sources, measures, dimensions, raw tables, and columns. Example: discover_data({ query: \"monthly orders by customer\", connectionId: \"warehouse\", kinds: [\"sl_source\", \"table\"] }).",
"inputSchema": {
"type": "object",
"properties": {
@ -1398,7 +1398,7 @@
{
"name": "sql_execution",
"title": "SQL Execution",
"description": "Execute one parser-validated read-only SQL query against a configured KTX connection. Example: sql_execution({ connectionId: \"warehouse\", sql: \"select count(*) from public.orders\", maxRows: 100 }).",
"description": "Execute one parser-validated read-only SQL query against a configured ktx connection. Example: sql_execution({ connectionId: \"warehouse\", sql: \"select count(*) from public.orders\", maxRows: 100 }).",
"inputSchema": {
"type": "object",
"properties": {
@ -1472,7 +1472,7 @@
{
"name": "memory_ingest",
"title": "Memory Ingest",
"description": "Ingest free-form markdown knowledge into durable KTX memory. Use this for business rules, metric definitions, schema gotchas, recurring findings, or explicit user requests to remember something. Example: memory_ingest({ connectionId: \"warehouse\", content: \"ARR is reported in cents in this warehouse.\" }).",
"description": "Ingest free-form markdown knowledge into durable ktx memory. Use this for business rules, metric definitions, schema gotchas, recurring findings, or explicit user requests to remember something. Example: memory_ingest({ connectionId: \"warehouse\", content: \"ARR is reported in cents in this warehouse.\" }).",
"inputSchema": {
"type": "object",
"properties": {

View file

@ -987,7 +987,7 @@ describe('createKtxMcpServer', () => {
expect(ingest.ingest).toHaveBeenCalledWith({
userId: 'mcp-user',
chatId: expect.stringMatching(/^mcp-/),
userMessage: 'Ingest external knowledge into KTX memory.',
userMessage: 'Ingest external knowledge into ktx memory.',
assistantMessage: content,
connectionId: '00000000-0000-4000-8000-000000000001',
sourceType: 'external_ingest',
@ -996,7 +996,7 @@ describe('createKtxMcpServer', () => {
const cliEquivalentInput: MemoryAgentInput = {
userId: 'mcp-user',
chatId: 'cli-text-ingest-test-1',
userMessage: 'Ingest external text artifact "orders lookml" into KTX memory.',
userMessage: 'Ingest external text artifact "orders lookml" into ktx memory.',
assistantMessage: content,
connectionId: '00000000-0000-4000-8000-000000000001',
sourceType: 'external_ingest',
@ -1101,7 +1101,7 @@ describe('createKtxMcpServer', () => {
expect(ingestSpy).toHaveBeenCalledWith({
userId: 'local',
chatId: expect.stringMatching(/^mcp-/),
userMessage: 'Ingest external knowledge into KTX memory.',
userMessage: 'Ingest external knowledge into ktx memory.',
assistantMessage: 'Revenue means paid order value.',
connectionId: 'warehouse',
sourceType: 'external_ingest',
@ -1127,7 +1127,7 @@ describe('createKtxMcpServer', () => {
}
});
it('registers KTX context MCP tools when context ports are supplied', async () => {
it('registers ktx context MCP tools when context ports are supplied', async () => {
const fake = makeFakeServer();
const contextTools: KtxMcpContextPorts = {
connections: {
@ -1298,7 +1298,7 @@ describe('createKtxMcpServer', () => {
expect(jsonToolResult({ ok: true }).structuredContent).toEqual({ ok: true });
if (false) {
// @ts-expect-error bare arrays are not valid MCP structuredContent objects in KTX
// @ts-expect-error bare arrays are not valid MCP structuredContent objects in ktx
jsonToolResult([]);
}
});

View file

@ -20,9 +20,9 @@ const expectedAdapterSkillHeadings: Record<string, string> = {
historic_sql_table_digest: '# Historic SQL Table Digest',
live_database_ingest: '# Live Database Ingest',
looker_ingest: '# Looker Runtime Ingest',
lookml_ingest: '# LookML to KTX Semantic Layer',
metabase_ingest: '# Metabase to KTX Semantic Layer',
metricflow_ingest: '# MetricFlow to KTX Semantic Layer',
lookml_ingest: '# LookML to ktx Semantic Layer',
metabase_ingest: '# Metabase to ktx Semantic Layer',
metricflow_ingest: '# MetricFlow to ktx Semantic Layer',
};
const verificationWriterSkills = [
'notion_synthesize',
@ -125,7 +125,7 @@ describe('memory runtime assets', () => {
it('ships Metabase guidance that avoids invalid joins for SQL-only card outputs', async () => {
const body = await readFile(join(skillsDir, 'metabase_ingest', 'SKILL.md'), 'utf-8');
expect(body).toContain('Do not declare a KTX join just because the card SQL joins that table internally');
expect(body).toContain('Do not declare a ktx join just because the card SQL joins that table internally');
expect(body).toContain('only when the card output exposes a local key that matches the target source grain');
expect(body).toContain('If `sl_discover` resolves the table, it is not outside the manifest');
expect(body).toContain('reason: "parse_error"');
@ -167,7 +167,7 @@ describe('memory runtime assets', () => {
}
});
it('ships only the KTX connectionId sql_execution call shape in writer guidance', async () => {
it('ships only the ktx connectionId sql_execution call shape in writer guidance', async () => {
const shared = await readFile(join(skillsDir, '_shared', 'identifier-verification.md'), 'utf-8');
const bodies = [{ name: '_shared/identifier-verification.md', body: shared }];

View file

@ -9,7 +9,7 @@ import {
const removedAutoCommitKey = ['auto', 'commit'].join('_');
describe('KTX project config', () => {
describe('ktx project config', () => {
it.each(['status', 'replay', 'run', 'watch'])('accepts former ingest subcommand name "%s" as a connection id', (connectionId) => {
expect(
parseKtxProjectConfig(`

View file

@ -5,7 +5,7 @@ import { join } from 'node:path';
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
import { initKtxProject, loadKtxProject } from '../../../src/context/project/project.js';
describe('KTX local project runtime', () => {
describe('ktx local project runtime', () => {
let tempDir: string;
beforeEach(async () => {

View file

@ -10,7 +10,7 @@ import {
setKtxSetupDatabaseConnectionIds,
} from '../../../src/context/project/setup-config.js';
describe('KTX setup config helpers', () => {
describe('ktx setup config helpers', () => {
let tempDir: string;
beforeEach(async () => {

View file

@ -9,7 +9,7 @@ import {
} from '../../../src/context/scan/credentials.js';
import type { KtxCredentialEnvelope, KtxScanReport, KtxScanWarning } from '../../../src/context/scan/types.js';
describe('KTX scan credential redaction', () => {
describe('ktx scan credential redaction', () => {
it('keeps credential references inspectable', () => {
const envReference: KtxCredentialEnvelope = { kind: 'env', name: 'DATABASE_URL' };
const fileReference: KtxCredentialEnvelope = { kind: 'file', path: '~/.config/ktx/warehouse' };

View file

@ -7,7 +7,7 @@ import {
const defaultPatterns = defaultKtxDataDictionarySettings.excludePatterns;
describe('KTX scan data dictionary policy', () => {
describe('ktx scan data dictionary policy', () => {
it('includes text-like and boolean categorical types', () => {
expect(isKtxDataDictionaryCandidate('varchar(50)', 'status', defaultPatterns)).toBe(true);
expect(isKtxDataDictionaryCandidate('VARCHAR', 'category', defaultPatterns)).toBe(true);

View file

@ -90,7 +90,7 @@ function createConnector(): KtxScanConnector {
};
}
describe('KTX description prompt builders', () => {
describe('ktx description prompt builders', () => {
it('builds column prompts with sample values, source descriptions, and nested BigQuery guidance', () => {
const { system, user } = buildKtxColumnDescriptionPrompt({
columnName: 'payload',

View file

@ -1,7 +1,7 @@
import { describe, expect, it } from 'vitest';
import { buildKtxColumnEmbeddingText } from '../../../src/context/scan/embedding-text.js';
describe('KTX scan embedding text', () => {
describe('ktx scan embedding text', () => {
it('builds column embedding text with table, description, FK, and sample-value context', () => {
expect(
buildKtxColumnEmbeddingText({

View file

@ -5,7 +5,7 @@ import {
skippedKtxScanEnrichmentSummary,
} from '../../../src/context/scan/enrichment-summary.js';
describe('KTX scan enrichment summaries', () => {
describe('ktx scan enrichment summaries', () => {
it('keeps structural scans skipped when no enrichment was requested', () => {
expect(failedKtxScanEnrichmentSummary('structural', false)).toEqual(skippedKtxScanEnrichmentSummary);
});

View file

@ -11,7 +11,7 @@ import type {
KtxStructuralSyncPlan,
} from '../../../src/context/scan/enrichment-types.js';
describe('KTX scan enrichment contracts', () => {
describe('ktx scan enrichment contracts', () => {
it('models an enriched schema with reusable table, column, and relationship metadata', () => {
const schema: KtxEnrichedSchema = {
connectionId: 'warehouse',

View file

@ -373,7 +373,7 @@ describe('local scan enrichment', () => {
expect(result.summary.statisticalValidation).toBe('skipped');
expect(result.warnings).toContainEqual({
code: 'relationship_validation_failed',
message: 'KTX scan connector advertises readOnlySql but does not expose executeReadOnly',
message: 'ktx scan connector advertises readOnlySql but does not expose executeReadOnly',
recoverable: true,
metadata: { capability: 'readOnlySql' },
});

View file

@ -1644,7 +1644,7 @@ describe('local scan', () => {
expect(result.report.warnings).toEqual([
{
code: 'enrichment_failed',
message: 'KTX scan enrichment failed after structural scan completed: embedding service timed out',
message: 'ktx scan enrichment failed after structural scan completed: embedding service timed out',
recoverable: true,
metadata: {
mode: 'enriched',

View file

@ -258,7 +258,7 @@ describe('relationship benchmark report', () => {
}),
);
expect(markdown).toContain('# KTX Relationship Discovery Benchmark Evidence');
expect(markdown).toContain('# ktx Relationship Discovery Benchmark Evidence');
expect(markdown).toContain(
'| demo_b2b_no_declared_constraints | smoke | declared_pks_and_declared_fks_removed | run | no | 0.500 | 0.000 | 0.000 | 0 |',
);

View file

@ -279,7 +279,7 @@ describe('relationship diagnostics artifacts', () => {
warnings: [
{
code: 'connector_capability_missing',
message: 'KTX scan connector cannot run standalone statistical relationship validation',
message: 'ktx scan connector cannot run standalone statistical relationship validation',
recoverable: true,
metadata: { capability: 'readOnlySql' },
},

View file

@ -449,7 +449,7 @@ describe('production relationship discovery', () => {
});
expect(result.warnings).toContainEqual({
code: 'connector_capability_missing',
message: 'KTX scan connector cannot run read-only SQL relationship validation',
message: 'ktx scan connector cannot run read-only SQL relationship validation',
recoverable: true,
metadata: { capability: 'readOnlySql' },
});

View file

@ -146,12 +146,12 @@ describe('relationship LLM proposals', () => {
expect(runtime.generateObject).toHaveBeenCalledWith(
expect.objectContaining({
role: 'candidateExtraction',
system: expect.stringContaining('You are helping KTX review possible SQL relationships'),
system: expect.stringContaining('You are helping ktx review possible SQL relationships'),
prompt: expect.stringContaining('"tables"'),
}),
);
const call = vi.mocked(runtime.generateObject).mock.calls[0]?.[0];
expect(call?.prompt).not.toContain('You are helping KTX review possible SQL relationships');
expect(call?.prompt).not.toContain('You are helping ktx review possible SQL relationships');
});
it('skips when no runtime is configured', async () => {
@ -207,7 +207,7 @@ describe('relationship LLM proposals', () => {
expect(failed).toMatchObject({ candidates: [], llmCalls: 1, summary: 'failed' });
expect(failed.warnings[0]).toMatchObject({
code: 'relationship_llm_proposal_failed',
message: 'KTX relationship LLM proposal failed: model unavailable',
message: 'ktx relationship LLM proposal failed: model unavailable',
recoverable: true,
});
});

View file

@ -1,7 +1,7 @@
import { describe, expect, it } from 'vitest';
import { inferKtxDimensionType, ktxColumnTypeMappingFromNative, normalizeKtxNativeType } from '../../../src/context/scan/type-normalization.js';
describe('KTX scan type normalization', () => {
describe('ktx scan type normalization', () => {
it('normalizes native database type strings', () => {
expect(normalizeKtxNativeType(' NUMERIC(12, 2) ')).toBe('numeric');
expect(normalizeKtxNativeType('TIMESTAMP WITH TIME ZONE')).toBe('timestamp with time zone');

View file

@ -17,7 +17,7 @@ import {
type KtxSchemaSnapshot,
} from '../../../src/context/scan/types.js';
describe('KTX scan contract types', () => {
describe('ktx scan contract types', () => {
it('defaults to structural-only connector capabilities', () => {
expect(createKtxConnectorCapabilities()).toEqual({
structuralIntrospection: true,

View file

@ -47,7 +47,7 @@ const baseTable: SemanticLayerSource = {
};
describe('listConnectionIdsWithNames', () => {
it('discovers local KTX connection ids from semantic-layer directories', async () => {
it('discovers local ktx connection ids from semantic-layer directories', async () => {
const configService = {
listFiles: vi.fn().mockResolvedValue({
files: [

View file

@ -20,7 +20,7 @@ export async function makeLocalGitRepo(fixtureDir: string, destRoot: string): Pr
await git.init();
await git.raw(['checkout', '-B', 'main']);
await git.addConfig('user.email', 'test@ktx.local');
await git.addConfig('user.name', 'KTX Test');
await git.addConfig('user.name', 'ktx Test');
await git.add('.');
await git.commit('initial');
const commit = async (message: string): Promise<string> => {