feat(node): three-node HF demo topology — implementation (F2)#151
Merged
Conversation
Three-node demo topology (ADR 0012). New src/serving/node/ resolves and validates AGENTFLOW_NODE_* once at boot: unset/empty role == standalone (byte-identical to today's demo, N1); center/edge fully validated with fail-fast on a missing center URL, missing token, or unknown branch. Lifespan stores node_config/role/branch on app.state; the ingest endpoint and edge emitter (later steps) hang off this single seam. N1/N2 config + standalone-unchanged tests (unit + integration). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Center-only node federation ingest (ADR 0012 §3). An edge pushes a batch of the same canonical events; the center applies each via local_pipeline._process_event — no new serving logic — and tags the originating branch on the pipeline_events journal (new branch column, NULL for in-process events). Auth ladder: role gate (404 off-center, even with a valid token) → bearer constant-time compare vs AGENTFLOW_NODE_TOKEN (401 missing / 403 wrong) → body shape (422, unknown origin_branch rejected by Literal). Demo-guard allow-list + auth-middleware exempt let the token call through while the public demo-key still fails; endpoint hidden from public OpenAPI. Idempotent by event_id (re-POST does not double-count). N3/N4/N5/N12 tests. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Edge-role background task (ADR 0012 §6). A slow generator produces the same canonical events the in-process pipeline makes; each is stamped with the edge's branch, applied to the edge's own read surface, and forwarded unchanged to the center's POST /v1/node/events with the node token (N7). Cold-center tolerance (N9): bounded retries with backoff, drop + log on give-up, never raised into the loop — the edge stays up when the hub is asleep, which is what makes the push-on-activity sleep choreography self-healing. Started in lifespan only for edge role (off in center/ standalone; AGENTFLOW_NODE_EMITTER_ENABLED=false disables for tests). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Boot baseline for the cross-branch view (ADR 0012 §7). The demo entity tables are a shared catalog with no branch column, so branch attribution lives on the pipeline_events journal: a deterministic per-branch baseline under a distinct topic (node.baseline). Center seeds all three branches, an edge seeds only its own (N6), standalone seeds none — byte-identical to today's demo (N1). Pure function of the branch, cleared-then-relaid, so a restart yields the same baseline (N11). The distinct topic keeps the rows inert to every existing journal scan and separable from the live delta. N6/N11 unit + integration tests. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
GET /v1/node/branches (center-only, 404 off-center). Composes a per-branch summary purely from the pipeline_events journal — no new store: seeded baseline, live delta this lifecycle, and last-seen timestamp. A silent branch (asleep / just booted) shows baseline + null last-seen + a waking status, never an error (N8) — the sleep behaviour is visible by design. Includes the UI hint directing visitors to open a branch Space. N8 unit + integration tests (incl. the N4 "metric moved" end: an ingested spb event lifts the spb live delta and sets last-seen). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…cts) Per-role Hugging Face Space artifacts for the three-node deploy (ADR 0012 §11): center/edge-spb/edge-ekb READMEs (Space frontmatter + role env matrix + the honesty boundary stated plainly) and a DEPLOY.md runbook (same image x3, env in Space Settings, center-first bring-up, verify-live §12). The shared image is the existing deploy/hf-space/Dockerfile. The actual HF publish + live-verify remain the OWNER GATE — these are the committed artifacts only. Frontmatter guard test included. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
DORA Metrics
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements the three-node demo topology per ADR 0012 and the build contract
docs/three-node-demo-topology.md(F2 ofplan_endgame_02_07_26.md). One image, three roles differentiated purely by environment; the standalone demo Space stays byte-identical.The actual Hugging Face publish + live-verify remain the owner gate — this PR is the implementation + committed deploy artifacts only.
What's here (6 commits, one per build-contract step)
src/serving/node/config.py) — resolves/validatesAGENTFLOW_NODE_*once at boot; unset role = standalone (strict superset); fail-fast on an edge with no center URL/token or an unknown branch.POST /v1/node/events— token-auth (constant-time, distinct fromdemo-key), applies each event via the existinglocal_pipeline._process_event(no new serving logic), tags the originating branch on thepipeline_eventsjournal (newbranchcolumn), idempotent byevent_id. 404 off-center, hidden from public OpenAPI.node.baselinetopic (center = all branches, edge = its own, standalone = none).GET /v1/node/branches— per-branch baseline / live-delta / last-seen from the journal; silent branches degrade towaking, never error.DEPLOY.mdrunbook underdeploy/hf-space/three-node/(same image ×3; env in Space Settings).Honesty boundary (stated in every node README)
Demonstrates branch distribution / event federation, not horizontal scaling. Three substitutions are stated plainly so the artifact never over-claims: HTTPS
POSTstands in for Kafka→Flink (transport only); single-replica embedded control plane, not the multi-replica PostgreSQL profile; the federated live layer is ephemeral (resets on hub restart).Tests — machine-checkable invariants N1–N12
tests/unit/test_node_{config,emitter,seed,view,deploy_artifacts}.py+tests/integration/test_node_topology.py.Verification (local, no-Docker)
ruff+ruff format --check+mypy(strict,src/, 124 files) +export_openapi.py --check— all green (no OpenAPI drift; the node routes areinclude_in_schema=False)🤖 Generated with Claude Code