Skip to content

Commit 6146f16

Browse files
brownjuly2003-codeJuliaEdomclaude
authored
fix(g2-s7): pin SERVING_BACKEND=duckdb for single-container demo deploys (#165)
* fix(g2-s7): pin SERVING_BACKEND=duckdb for single-container demo deploys config/serving.yaml has defaulted to ClickHouse since the ADR 0006 Phase 1 cutover, so any demo image built from current main crashes on boot (BackendExecutionError: connection refused) — no ClickHouse runs beside the single-container demo. Caught live on the first three-node HF Space bring-up (liovina/agentflow-center, RUNTIME_ERROR), fix verified on the same Space: setting the env flips the engine back to embedded DuckDB and the node boots healthy. Pin the backend where the demo conventions already live: ENV in deploy/hf-space/Dockerfile, [env] in deploy/fly/fly.toml, and the local docker-run example in deploy/fly/README.md (Dockerfile.api bakes no demo env, so the example must pass it explicitly). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs(g2-s7): changelog entry for the demo serving-backend pin Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs(g2-s7): correct node-ingest auth codes to the implemented ladder The build spec, ADR 0012, DEPLOY.md and the center Space README all claimed the public demo-key POST to /v1/node/events gets 403. The implemented and N2/N3-tested ladder is: role != center -> 404, no/malformed bearer -> 401 (the demo-key caller sends none, so it lands here), wrong bearer -> 403. Caught by the first live §12 verify against the deployed center. Docs follow the code: the tests assert 401 deliberately and the guard property (public key can never push) is unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: JuliaEdom <uedomskikh@gmail.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
1 parent fa4ba22 commit 6146f16

8 files changed

Lines changed: 35 additions & 11 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,17 @@ All notable changes to AgentFlow are documented in this file.
44

55
## [Unreleased]
66

7+
### Fixed — single-container demo deploys pin the DuckDB serving backend (G2 S7, 2026-07-06)
8+
9+
- **`SERVING_BACKEND=duckdb` is now pinned** in `deploy/hf-space/Dockerfile`
10+
(`ENV`), `deploy/fly/fly.toml` (`[env]`), and the `deploy/fly/README.md`
11+
local docker-run example. `config/serving.yaml` has defaulted to ClickHouse
12+
since the ADR 0006 Phase 1 cutover and ships inside the demo image, so any
13+
demo built from post-cutover main crashed on boot (`BackendExecutionError:
14+
connection refused` — no ClickHouse runs beside a single-container demo).
15+
Caught live on the first three-node HF Space bring-up; the standalone demo
16+
Space never showed it only because it still ran a pre-cutover image.
17+
718
### Changed — spec/seed number consistency: daily rate, GTIN check digits, band centering, FX honesty (G2 S3, 2026-07-06)
819

920
- **Seed daily rate now matches §1 (audit m5).** `satellite_seed*.sql` order

‎deploy/fly/README.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ curl -i -X POST \
7070
python -c "import tomllib, pathlib; tomllib.loads(pathlib.Path('deploy/fly/fly.toml').read_text(encoding='utf-8'))"
7171
docker build -t agentflow-demo -f Dockerfile.api .
7272
docker run --rm -p 8000:8000 \
73+
-e SERVING_BACKEND=duckdb \
7374
-e DUCKDB_PATH=/data/agentflow-demo.duckdb \
7475
-e AGENTFLOW_USAGE_DB_PATH=/data/agentflow-demo-api.duckdb \
7576
-e AGENTFLOW_DEMO_MODE=true \

‎deploy/fly/fly.toml‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ primary_region = "fra"
55
dockerfile = "../../Dockerfile.api"
66

77
[env]
8+
# config/serving.yaml defaults to ClickHouse; the demo VM runs none.
9+
SERVING_BACKEND = "duckdb"
810
DUCKDB_PATH = "/data/agentflow-demo.duckdb"
911
AGENTFLOW_USAGE_DB_PATH = "/data/agentflow-demo-api.duckdb"
1012
AGENTFLOW_DEMO_MODE = "true"

‎deploy/hf-space/Dockerfile‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ ENV AGENTFLOW_ENTITY_CONTRACTS_DIR=/app/contracts/entities
3838
# Demo mode (mirrors deploy/fly/README.md): injected public key, admin routes
3939
# return 404, mutating routes blocked except POST /v1/query[/explain], DuckDB
4040
# seeded on first boot. Data lives under the demo user's writable home.
41+
# config/serving.yaml defaults to ClickHouse (ADR 0006 Phase 1); the
42+
# single-container demo runs none, so pin the embedded DuckDB backend.
43+
ENV SERVING_BACKEND=duckdb
4144
ENV AGENTFLOW_DEMO_MODE=true
4245
ENV AGENTFLOW_SEED_ON_BOOT=true
4346
ENV DEMO_API_KEY=demo-key

‎deploy/hf-space/three-node/DEPLOY.md‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,8 @@ TOKEN=... # the shared node token, from your secret store — never commit it
6868
# 1. All three healthy
6969
curl -fsS $CENTER/v1/health && curl -fsS $SPB/v1/health && curl -fsS $EKB/v1/health
7070

71-
# 2. Public demo-key cannot push (403 — demo-guard holds)
71+
# 2. Public demo-key cannot push (401 — the ingest wants its own bearer,
72+
# not the public key; a wrong bearer gets 403)
7273
curl -i -X POST -H "X-API-Key: demo-key" -H "Content-Type: application/json" \
7374
-d '{"origin_branch":"spb","events":[]}' $CENTER/v1/node/events
7475

‎deploy/hf-space/three-node/center/README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ curl -fsS $SPACE/v1/health
7070
# Cross-branch view (public demo key)
7171
curl -fsS -H "X-API-Key: demo-key" $SPACE/v1/node/branches
7272

73-
# Public callers cannot push events — the node token is required (403)
73+
# Public callers cannot push events — the node token is required (401)
7474
curl -i -X POST -H "X-API-Key: demo-key" -H "Content-Type: application/json" \
7575
-d '{"origin_branch":"spb","events":[]}' $SPACE/v1/node/events
7676
```

‎docs/decisions/0012-three-node-demo-topology.md‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,8 +150,10 @@ choreography below. No second account, no paid tier, no organization required.
150150
exists (ADR 0006 Phase 1).
151151
- The endpoint is **allow-listed in the demo-mode guard** exactly like
152152
`/v1/query` (`src/serving/api/main.py:286-299`), so public callers with the
153-
`demo-key` still get `403` on it; only the node token authorizes it. It is
154-
mounted **only** in center role; in edge/standalone role it does not exist.
153+
`demo-key` are still rejected on it by the endpoint's own bearer ladder
154+
(`401` with no bearer, `403` with a wrong one); only the node token
155+
authorizes it. It is mounted **only** in center role; in edge/standalone
156+
role it does not exist.
155157
- **Push, not pull:** edges emit on their own activity (the existing background
156158
generator tick, reused). This is what makes sleep choreography work.
157159

‎docs/three-node-demo-topology.md‎

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -69,17 +69,19 @@ Content-Type: application/json
6969
}
7070
7171
200 OK -> { "accepted": N, "applied": N, "dead_lettered": M }
72-
401 -> missing/malformed bearer
73-
403 -> wrong token, OR demo-key/public caller (demo-guard), OR role != center
72+
401 -> missing/malformed bearer (a public demo-key caller sends none, so it lands here)
73+
403 -> bearer present but wrong (including the demo-key offered as a bearer)
74+
404 -> role != center (N2 - the role gate runs before the auth ladder)
7475
422 -> body shape invalid (not the per-event schema - that dead-letters, see below)
7576
```
7677

7778
- Auth: constant-time compare of the bearer against `AGENTFLOW_NODE_TOKEN`
7879
(reuse the pattern in `src/serving/api/auth/`); **not** the `demo-key` path.
7980
- The demo-guard (`main.py:286-299`) blocks `POST` for the public key on every
8081
path except the allow-list; adding `/v1/node/events` to that set lets the
81-
**token-authenticated** node call through while the public `demo-key` still
82-
gets `403` (N3).
82+
**token-authenticated** node call through, and the endpoint's own bearer
83+
ladder still rejects the public `demo-key` caller — `401` without a bearer,
84+
`403` with a wrong one (N3).
8385
- Apply each event via `local_pipeline._process_event(conn, event, clickhouse_sink=...)`
8486
on the center's serving connection - **no new serving logic**. A per-event schema
8587
failure dead-letters exactly as in-process events do (that path already writes
@@ -199,7 +201,8 @@ Bring-up order: **center first** (edges need its URL live), then the two edges.
199201
## 12. Verify-live checklist (F2 done-gate)
200202

201203
- `curl {center}/v1/health`, `{edge-spb}/v1/health`, `{edge-ekb}/v1/health` -> all 200.
202-
- Public demo-key `POST {center}/v1/node/events` -> `403` (demo-guard holds, N3).
204+
- Public demo-key `POST {center}/v1/node/events` -> `401` (it carries no bearer;
205+
a wrong bearer gets `403` — the ingest never honors the public key, N3).
203206
- `POST {center}/v1/node/events` with the node token, one seeded `spb` order ->
204207
`200 applied:1`; then a center cross-branch read shows `spb` last-seen set and the
205208
metric moved (N4).
@@ -215,8 +218,9 @@ Machine-checkable; each is a unit/integration test F2 must add (mirrors
215218
- **N1** Standalone role (no `AGENTFLOW_NODE_ROLE`): `/v1/node/events` is not mounted
216219
(`404`), no emitter task; behavior byte-identical to today's demo.
217220
- **N2** `/v1/node/events` mounted iff role=`center`; edge/standalone => `404`.
218-
- **N3** Ingest rejects the public `demo-key` (`403`, demo-guard) and missing/wrong
219-
bearer (`401`/`403`); accepts the correct `AGENTFLOW_NODE_TOKEN`.
221+
- **N3** Ingest rejects the public `demo-key` (`401` — it sends no bearer; `403` if
222+
offered as one) and missing/wrong bearer (`401`/`403`); accepts the correct
223+
`AGENTFLOW_NODE_TOKEN`.
220224
- **N4** A valid POSTed event is applied via `_process_event`, lands in
221225
`pipeline_events` tagged `branch=<origin>`, and moves the matching center metric.
222226
- **N5** Idempotency: the same `event_id` POSTed twice does not double-count.

0 commit comments

Comments
 (0)