disclosure-bureau/investigator-runtime/Dockerfile

31 lines
1.2 KiB
Text
Raw Normal View History

W3.1-W3.4: Investigation Bureau foundation — migrations, runtime, Locard Migrations: - 0004_investigation_bureau.sql: 7 new tables (investigation_jobs + evidence, hypotheses, contradictions, witnesses, gaps, residual_uncertainties), id sequences, pg_notify trigger on investigation_jobs, RLS read-only public, investigator role with least-privilege grants (no service_role). - 0005_investigator_write_policies.sql: fixup adding RLS INSERT/UPDATE policies bound to investigator + service_role + postgres (RLS with only a SELECT policy was silently blocking the worker's claim UPDATE). investigator-runtime/ (new Bun + TS container): - src/main.ts: LISTEN/NOTIFY poller, claim-with-SKIP-LOCKED, drain pool, healthcheck file, graceful SIGTERM shutdown. - src/orchestrator.ts: chief-detective dispatch (evidence_chain → Locard). Marks job failed when all per-item outputs error; surfaces first errors. - src/lib/{env,pg,audit,ids,claude}.ts: typed config (gate #8), pool + dedicated LISTEN client, NDJSON audit, sequence allocator (E-NNNN etc), claude -p subprocess with quota detection (api_error_status=429). - src/tools/write_evidence.ts: schema-validate (grade A/B/C custody steps), resolve chunk_pk via FK, verify verbatim_excerpt actually appears in chunk content, INSERT + render case/evidence/E-NNNN.md + audit. - src/detectives/locard.ts: load chunk → call Claude with locard.md system prompt → parse strict JSON → call writeEvidence locally. - Dockerfile installs `claude` CLI (OAuth) at build time. Compose: - new `investigator` service builds from investigator-runtime/, connects with low-privilege role, mounts case/ RW and wiki/+raw/ RO, 512m mem cap. Web: - /api/admin/investigate/test (POST+GET) gated by middleware (W0-F1). POST creates a job, GET polls status. For W3.6 it becomes the chat tool. End-to-end smoke: INSERT job → pg_notify → claim → Locard dispatch → claude subprocess invoked. Auth works (CLI v2.1.150). Currently quota exhausted (weekly limit · resets 3pm UTC) — pipeline catches the typed isQuota error, marks job failed with surfaced reason. Architecture proven; quota reset enables real evidence creation. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 22:49:33 +00:00
# Investigator runtime — Bun + TS worker that spawns `claude -p` subprocesses
# (Sonnet 4.6 via OAuth) and writes Investigation Bureau outputs to disk + DB.
FROM oven/bun:1.1-slim AS base
# Tools we shell out to: `claude` CLI (OAuth) + git for sha256 over PDFs.
# The claude install script downloads the binary; no API key needed at build.
RUN apt-get update && apt-get install -y --no-install-recommends \
curl ca-certificates git \
&& curl -fsSL https://claude.ai/install.sh | bash \
&& cp /root/.local/bin/claude /usr/local/bin/claude \
&& claude --version \
&& apt-get purge -y curl && apt-get autoremove -y && rm -rf /var/lib/apt/lists/*
WORKDIR /app
# Install pg deps first so they cache.
COPY package.json bun.lockb* ./
RUN bun install --production || bun install
COPY tsconfig.json ./
COPY src ./src
COPY prompts ./prompts
# Default healthcheck: the worker writes /tmp/healthy when its LISTEN
# connection is up. Container is unhealthy if that file is older than 90s.
HEALTHCHECK --interval=30s --timeout=10s --start-period=20s --retries=3 \
CMD test -f /tmp/healthy && find /tmp/healthy -mmin -1.5 | grep -q healthy
CMD ["bun", "run", "src/main.ts"]