feat: mock atomizer and work-performer services with contract tests (phase 11)
- services/atomizer: standalone Go module implementing §5.1 — Anthropic
OpenAI-compatible chat completions by default, native /v1/messages when
LLM_API_STYLE=anthropic, strict-JSON prompting, defensive fence-stripping
parse with one retry, deterministic equal-split fallback without an API
key, exact coefficient-sum normalization, bearer auth
- services/work-performer: Node 20 http server implementing §5.2 — single
concurrency, /work/{jobId}/TASK.md preparation, attachment downloads,
optional shallow git clone, claude CLI execution with JSON output,
simulated success when the CLI is unavailable (offline demo), artifact
endpoint, idempotent HMAC-signed callbacks with retry, best-effort cancel
- compose profile 'mocks': separate builds/ports/tokens, healthchecks,
${HOME}/.claude(.json) mounted read-only into the performer
- contract tests (go test -tags=contract) for both services; Makefile
test-contract target; verified live incl. a real Claude Code job run
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -39,5 +39,52 @@ services:
|
||||
retries: 3
|
||||
start_period: 10s
|
||||
|
||||
# --- placeholder external services (docker compose --profile mocks up) ---
|
||||
# Two fully independent services: separate builds, ports, tokens (§5).
|
||||
atomizer-mock:
|
||||
build: ./services/atomizer
|
||||
profiles: ["mocks"]
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
PORT: "8090"
|
||||
ATOMIZER_TOKEN: ${ATOMIZER_TOKEN}
|
||||
ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY:-}
|
||||
ANTHROPIC_OPENAI_BASE_URL: ${ANTHROPIC_OPENAI_BASE_URL:-https://api.anthropic.com/v1}
|
||||
ANTHROPIC_MODEL: ${ANTHROPIC_MODEL:-claude-sonnet-4-6}
|
||||
LLM_API_STYLE: ${LLM_API_STYLE:-openai}
|
||||
ports:
|
||||
- "127.0.0.1:8090:8090"
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "-qO-", "http://127.0.0.1:8090/healthz"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 5s
|
||||
|
||||
work-performer:
|
||||
build: ./services/work-performer
|
||||
profiles: ["mocks"]
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
PORT: "8091"
|
||||
WORK_PERFORMER_TOKEN: ${WORK_PERFORMER_TOKEN}
|
||||
PUBLIC_BASE_URL: http://work-performer:8091
|
||||
# host Claude Code config/secrets, read-only (§9.2)
|
||||
volumes:
|
||||
- ${HOME}/.claude:/root/.claude
|
||||
- ${HOME}/.claude.json:/root/.claude.json
|
||||
- work-data:/work
|
||||
ports:
|
||||
- "127.0.0.1:8091:8091"
|
||||
extra_hosts:
|
||||
- "host.docker.internal:host-gateway"
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "node -e \"fetch('http://127.0.0.1:8091/healthz').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))\""]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 5s
|
||||
|
||||
volumes:
|
||||
mongo-data:
|
||||
work-data:
|
||||
|
||||
Reference in New Issue
Block a user