mirror of
https://github.com/Kaelio/ktx.git
synced 2026-06-07 07:55:13 +02:00
Remove stale app service references
This commit is contained in:
parent
e18e6ac8c4
commit
9530d33c00
10 changed files with 30 additions and 59 deletions
|
|
@ -13,8 +13,8 @@ generates query workload under separate users, runs `ktx setup` with
|
|||
|
||||
- Docker with Compose v2
|
||||
- Node and pnpm matching the KTX workspace
|
||||
- `python-service/.venv` already created, or `KTX_SQL_ANALYSIS_URL` pointing at
|
||||
a running service that exposes `/api/sql/analyze-for-fingerprint`
|
||||
- `KTX_SQL_ANALYSIS_URL` or `KTX_DAEMON_URL` pointing at a running SQL-analysis
|
||||
service that exposes `/api/sql/analyze-for-fingerprint`
|
||||
|
||||
## Run
|
||||
|
||||
|
|
@ -111,5 +111,5 @@ The manifest should have `dialect: "postgres"`, `degraded: true`,
|
|||
- Missing grants: confirm `GRANT pg_read_all_stats TO ktx_reader;`.
|
||||
- Empty templates: rerun `scripts/generate-workload.sh base` and keep
|
||||
`--historic-sql-min-calls 2` for the smoke.
|
||||
- SQL-analysis failures: set `KTX_SQL_ANALYSIS_URL` to the running service URL
|
||||
or create `python-service/.venv` before running `scripts/smoke.sh`.
|
||||
- SQL-analysis failures: set `KTX_SQL_ANALYSIS_URL` or `KTX_DAEMON_URL` to a
|
||||
running service URL before running `scripts/smoke.sh`.
|
||||
|
|
|
|||
|
|
@ -4,46 +4,23 @@ set -euo pipefail
|
|||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
EXAMPLE_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
KTX_ROOT="$(cd "$EXAMPLE_DIR/../.." && pwd)"
|
||||
REPO_ROOT="$(cd "$KTX_ROOT/.." && pwd)"
|
||||
COMPOSE_FILE="$EXAMPLE_DIR/docker-compose.yml"
|
||||
PROJECT_PARENT="${KTX_POSTGRES_HISTORIC_PROJECT_PARENT:-$(mktemp -d)}"
|
||||
PROJECT_DIR="$PROJECT_PARENT/postgres-historic-ktx"
|
||||
KTX_BIN="$KTX_ROOT/packages/cli/dist/bin.js"
|
||||
PYTHON_SERVICE_LOG="$PROJECT_PARENT/python-service.log"
|
||||
PYTHON_SERVICE_PID=""
|
||||
|
||||
cleanup() {
|
||||
if [[ -n "$PYTHON_SERVICE_PID" ]]; then
|
||||
kill "$PYTHON_SERVICE_PID" >/dev/null 2>&1 || true
|
||||
fi
|
||||
if [[ "${KTX_POSTGRES_HISTORIC_KEEP_DOCKER:-0}" != "1" ]]; then
|
||||
docker compose -f "$COMPOSE_FILE" down -v >/dev/null 2>&1 || true
|
||||
fi
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
start_sql_analysis_if_needed() {
|
||||
if [[ -n "${KTX_SQL_ANALYSIS_URL:-}" ]]; then
|
||||
require_sql_analysis_url() {
|
||||
if [[ -n "${KTX_SQL_ANALYSIS_URL:-}" || -n "${KTX_DAEMON_URL:-}" ]]; then
|
||||
return
|
||||
fi
|
||||
if [[ ! -d "$REPO_ROOT/python-service/.venv" ]]; then
|
||||
echo "Set KTX_SQL_ANALYSIS_URL or create python-service/.venv before running this smoke." >&2
|
||||
exit 1
|
||||
fi
|
||||
(
|
||||
cd "$REPO_ROOT/python-service"
|
||||
source .venv/bin/activate
|
||||
uvicorn app.main:app --host 127.0.0.1 --port 18081 >"$PYTHON_SERVICE_LOG" 2>&1
|
||||
) &
|
||||
PYTHON_SERVICE_PID="$!"
|
||||
export KTX_SQL_ANALYSIS_URL="http://127.0.0.1:18081"
|
||||
for _ in $(seq 1 60); do
|
||||
if curl -fsS "$KTX_SQL_ANALYSIS_URL/health" >/dev/null 2>&1; then
|
||||
return
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
echo "SQL analysis service did not become healthy. Log: $PYTHON_SERVICE_LOG" >&2
|
||||
echo "Set KTX_SQL_ANALYSIS_URL or KTX_DAEMON_URL before running this smoke." >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
|
|
@ -111,7 +88,7 @@ NODE
|
|||
cd "$KTX_ROOT"
|
||||
pnpm --filter @ktx/context run build
|
||||
pnpm --filter @ktx/cli run build
|
||||
start_sql_analysis_if_needed
|
||||
require_sql_analysis_url
|
||||
|
||||
docker compose -f "$COMPOSE_FILE" up -d --wait
|
||||
"$EXAMPLE_DIR/scripts/generate-workload.sh" base
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { z } from 'zod';
|
||||
|
||||
// Literal vocabularies — kept in lockstep with the Python Pydantic model at
|
||||
// python-service/ktx-sl/semantic_layer/models.py (SourceColumn / ColumnRole /
|
||||
// python/ktx-sl/semantic_layer/models.py (SourceColumn / ColumnRole /
|
||||
// ColumnVisibility / JoinDeclaration). If these diverge, YAMLs can pass
|
||||
// TypeScript validation at ingest time but fail Python loading at query time.
|
||||
const columnTypeValues = ['string', 'number', 'time', 'boolean'] as const;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { describe, expect, it, vi } from 'vitest';
|
|||
import { createHttpSqlAnalysisPort } from './http-sql-analysis-port.js';
|
||||
|
||||
describe('createHttpSqlAnalysisPort', () => {
|
||||
it('calls the python-service fingerprint endpoint and maps snake_case response fields', async () => {
|
||||
it('calls the SQL-analysis fingerprint endpoint and maps snake_case response fields', async () => {
|
||||
const requestJson = vi.fn(async () => ({
|
||||
fingerprint: 'fingerprint-template',
|
||||
normalized_sql: 'SELECT * FROM analytics.orders WHERE status = ?',
|
||||
|
|
@ -26,7 +26,7 @@ describe('createHttpSqlAnalysisPort', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it('preserves python-service parse errors in the mapped result', async () => {
|
||||
it('preserves SQL-analysis parse errors in the mapped result', async () => {
|
||||
const requestJson = vi.fn(async () => ({
|
||||
fingerprint: '',
|
||||
normalized_sql: '',
|
||||
|
|
|
|||
|
|
@ -151,7 +151,7 @@ export abstract class BaseTool<TInput extends ZodType = ZodType> {
|
|||
}
|
||||
}
|
||||
},
|
||||
// Send only markdown to LLM - frontend still receives full { markdown, structured } via stream
|
||||
// Send only markdown to the LLM; tool callers still receive the structured output.
|
||||
toModelOutput: ({ output }) => {
|
||||
if (output && typeof output === 'object' && 'markdown' in output) {
|
||||
return { type: 'content', value: [{ type: 'text', text: output.markdown as string }] };
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ function lowerProductName() {
|
|||
describe('scanFileContent', () => {
|
||||
it('rejects source imports from application directories', () => {
|
||||
const serverAlias = '@' + 'server/contracts';
|
||||
const pythonAppPath = 'python-service/' + 'app/api/endpoints/semantic_layer.py';
|
||||
const pythonAppPath = `${['python', 'service'].join('-')}/app/api/endpoints/semantic_layer.py`;
|
||||
|
||||
const violations = [
|
||||
...scanFileContent('packages/context/src/index.ts', `import { orpc } from '${serverAlias}';`),
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { dirname, resolve } from 'node:path';
|
|||
import { fileURLToPath } from 'node:url';
|
||||
import { describe, it } from 'node:test';
|
||||
|
||||
const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..', '..');
|
||||
const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
||||
const ciWorkflowPath = resolve(repoRoot, '.github', 'workflows', 'ci.yml');
|
||||
|
||||
async function readCiWorkflowOrSkip(testContext) {
|
||||
|
|
@ -21,7 +21,7 @@ async function readCiWorkflowOrSkip(testContext) {
|
|||
}
|
||||
|
||||
describe('KTX CI artifact upload contract', () => {
|
||||
it('uploads verified KTX package artifacts from check-ktx-subtree', async (testContext) => {
|
||||
it('uploads verified KTX package artifacts from the standalone check job', async (testContext) => {
|
||||
const workflow = await readCiWorkflowOrSkip(testContext);
|
||||
if (workflow === null) {
|
||||
return;
|
||||
|
|
@ -29,42 +29,35 @@ describe('KTX CI artifact upload contract', () => {
|
|||
|
||||
assert.match(
|
||||
workflow,
|
||||
/name: Build ktx package artifacts and verify public smoke\s+run: cd ktx && pnpm run artifacts:build && pnpm run artifacts:verify-manifest && pnpm run artifacts:verify-demo\s+- name: Upload ktx package artifacts/s,
|
||||
/name: Build and verify package artifacts\s+run: pnpm run artifacts:check\s+- name: Upload package artifacts/s,
|
||||
);
|
||||
assert.match(workflow, /uses: actions\/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f/);
|
||||
assert.match(workflow, /name: ktx-package-artifacts-\$\{\{ github\.sha \}\}/);
|
||||
assert.match(workflow, /ktx\/dist\/artifacts\/manifest\.json/);
|
||||
assert.match(workflow, /ktx\/dist\/artifacts\/npm\/\*\.tgz/);
|
||||
assert.match(workflow, /ktx\/dist\/artifacts\/python\/\*\.whl/);
|
||||
assert.match(workflow, /ktx\/dist\/artifacts\/python\/\*\.tar\.gz/);
|
||||
assert.match(workflow, /dist\/artifacts\/manifest\.json/);
|
||||
assert.match(workflow, /dist\/artifacts\/npm\/\*\.tgz/);
|
||||
assert.match(workflow, /dist\/artifacts\/python\/\*\.whl/);
|
||||
assert.match(workflow, /dist\/artifacts\/python\/\*\.tar\.gz/);
|
||||
assert.match(workflow, /if-no-files-found: error/);
|
||||
assert.match(workflow, /retention-days: 7/);
|
||||
});
|
||||
|
||||
it('runs packed demo artifact smoke on Linux and macOS', async (testContext) => {
|
||||
it('runs TypeScript and Python checks in the standalone workflow', async (testContext) => {
|
||||
const workflow = await readCiWorkflowOrSkip(testContext);
|
||||
if (workflow === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
assert.match(workflow, /check-ktx-packed-demo:/);
|
||||
assert.match(workflow, /matrix:\s+os: \[ubuntu-latest, macos-latest\]/s);
|
||||
assert.match(workflow, /name: Download ktx package artifacts/);
|
||||
assert.match(workflow, /path: ktx\/dist\/artifacts/);
|
||||
assert.match(workflow, /run: cd ktx && pnpm run artifacts:verify-demo/);
|
||||
assert.match(workflow, /run: pnpm run check/);
|
||||
assert.match(workflow, /run: uv sync --all-packages/);
|
||||
assert.match(workflow, /run: uv run pytest/);
|
||||
});
|
||||
|
||||
it('includes packed demo artifact smoke in ci-success', async (testContext) => {
|
||||
it('does not depend on host application CI jobs', async (testContext) => {
|
||||
const workflow = await readCiWorkflowOrSkip(testContext);
|
||||
if (workflow === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
assert.match(
|
||||
workflow,
|
||||
/needs: \[check-ktx-subtree, check-ktx-packed-demo, build-python-service, test-server, build-frontend, run-pre-commit, build-docker-images\]/,
|
||||
);
|
||||
assert.match(workflow, /needs\.check-ktx-packed-demo\.result.*== "failure"/);
|
||||
assert.match(workflow, /needs\.check-ktx-packed-demo\.result.*== "cancelled"/);
|
||||
assert.doesNotMatch(workflow, /build-python-service|test-server|build-frontend|build-docker-images/);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -31,11 +31,10 @@ describe('Conductor workspace scripts', () => {
|
|||
|
||||
it('runs the KTX daemon on the documented fixed local port', async () => {
|
||||
const runScript = await readText('scripts/conductor-run.sh');
|
||||
const legacyServerPackagePattern = new RegExp(`@${['kae', 'lio'].join('')}/server|python-service|npx`);
|
||||
|
||||
assert.match(runScript, /pnpm run build/);
|
||||
assert.match(runScript, /source \.venv\/bin\/activate/);
|
||||
assert.match(runScript, /uv run ktx-daemon serve-http --host 127\.0\.0\.1 --port 8765/);
|
||||
assert.doesNotMatch(runScript, legacyServerPackagePattern);
|
||||
assert.doesNotMatch(runScript, /\bnpx\b/);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -66,6 +66,8 @@ describe('standalone example docs', () => {
|
|||
assert.match(smoke, /assert_manifest "\$FIRST_MANIFEST" true/);
|
||||
assert.match(smoke, /assert_manifest "\$SECOND_MANIFEST" false/);
|
||||
assert.match(smoke, /assert_manifest "\$RESET_MANIFEST" true/);
|
||||
assert.doesNotMatch(readme, /python-service/);
|
||||
assert.doesNotMatch(smoke, /python-service|PYTHON_SERVICE|REPO_ROOT/);
|
||||
});
|
||||
|
||||
it('lists every published TypeScript package in the package root README', async () => {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ function commandKeys(files) {
|
|||
|
||||
describe('precommit-check', () => {
|
||||
it('skips files outside ktx', () => {
|
||||
assert.deepEqual(commandKeys(['server/src/app.ts']), []);
|
||||
assert.deepEqual(commandKeys(['outside-workspace/src/app.ts']), []);
|
||||
});
|
||||
|
||||
it('runs only the touched package checks for package code', () => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue