From e34b756052297613f95b75bdebe5c39bfa94600e Mon Sep 17 00:00:00 2001 From: mptyl Date: Tue, 11 Aug 2026 19:12:37 +0200 Subject: [PATCH] fix: serve a deterministic internal embedding fixture for P2 acceptance --- backend/scripts/p2-acceptance.mjs | 44 ++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 7 deletions(-) diff --git a/backend/scripts/p2-acceptance.mjs b/backend/scripts/p2-acceptance.mjs index 7ac78478..fd9762b6 100644 --- a/backend/scripts/p2-acceptance.mjs +++ b/backend/scripts/p2-acceptance.mjs @@ -766,26 +766,32 @@ async function writeInstallationFiles(ctx) { ].join("\n") + "\n"; await atomicWrite(operatorEnvPath, operatorEnv); await atomicWrite(join(ctx.run.root, "installation", "pi-auth.json"), JSON.stringify({ fixture: true })); + const embeddingStubPath = join(installationDir, "embedding-stub.py"); + await atomicWrite(embeddingStubPath, EMBEDDING_STUB_SOURCE); const override = { services: { core: { image: ctx.coreImageTag, - environment: { - THT_INTERNAL_EMBEDDING_URL: `http://host.docker.internal:${ctx.fixturePorts.embedding}`, - }, extra_hosts: ["host.docker.internal:host-gateway"], }, "workspace-maintenance": { image: ctx.coreImageTag, - environment: { - THT_INTERNAL_EMBEDDING_URL: `http://host.docker.internal:${ctx.fixturePorts.embedding}`, - }, extra_hosts: ["host.docker.internal:host-gateway"], }, qdrant: { ports: [`127.0.0.1:${qdrantPort}:6333`], restart: "no", }, + // Deterministic Ollama-compatible embedding fixture on the internal allowlisted host + // name `embedding` (http://embedding:11434). Replaces the real Ollama service entirely. + embedding: { + image: ctx.coreImageTag, + entrypoint: ["python3", "/stub.py"], + volumes: [ + { type: "bind", source: embeddingStubPath, target: "/stub.py", read_only: true }, + ], + healthcheck: { disable: true }, + }, }, }; await atomicWrite(fixtureOverridePath, yamlStringify(override, { lineWidth: 0, sortMapEntries: false })); @@ -888,7 +894,7 @@ async function dockerCompose(ctx, commandArgs, { allowFailure = false, maxOutput } async function startQdrant(ctx) { - await dockerCompose(ctx, ["up", "-d", "qdrant"]); + await dockerCompose(ctx, ["up", "-d", "qdrant", "embedding"]); for (let attempt = 0; attempt < 60; attempt += 1) { try { const response = await fetch(`http://127.0.0.1:${ctx.fixturePorts.qdrant}/collections`); @@ -972,6 +978,30 @@ function sameSet(left, right) { return JSON.stringify([...left].sort()) === JSON.stringify([...right].sort()); } +const EMBEDDING_STUB_SOURCE = String.raw`import json +from http.server import BaseHTTPRequestHandler, HTTPServer + +class _Handler(BaseHTTPRequestHandler): + def do_POST(self): + length = int(self.headers.get("Content-Length", "0")) + payload = json.loads(self.rfile.read(length)) + inputs = payload.get("input", []) + if isinstance(inputs, str): + inputs = [inputs] + embeddings = [[0.01] * 1024 for _ in inputs] + body = json.dumps({"model": payload.get("model", "qwen3-embedding:0.6b"), "embeddings": embeddings}).encode("utf-8") + self.send_response(200) + self.send_header("Content-Type", "application/json") + self.send_header("Content-Length", str(len(body))) + self.end_headers() + self.wfile.write(body) + + def log_message(self, *args): + pass + +HTTPServer(("0.0.0.0", 11434), _Handler).serve_forever() +`; + function realUserHome() { try { const output = execFileSync("bash", ["-lc", 'printf "%s" ~'], { encoding: "utf8" }).trim();