Streams + celld — evidence matrix
Status: living checklist for Lab 5b (docs/examples/streams-celld)
Audience: operators and reviewers who need proof the docs match shipped behavior
Related: clawql-celld.md · clawql-streams.md · Learn Lab 5b
This page is the honest map of what is automated, what is local-only, and what remains draft. It is not a badge wall — every row names a command that produces the evidence.
Architecture under test (shipped)
| Layer | In cell bundle? | How it is proven |
|---|---|---|
clawql-core/streams-slim (audit / cache / hash-chain) |
Yes | Unit tests + webhook smoke assertions |
Significance filter (always/never/threshold/pattern/rate/composite) |
Yes | Unit tests + smoke filtered / rate 3rd-event spawn / composite AND |
Session TTL setAlarm / alarm() |
Yes | Smoke exitReason:timeout after short TTL |
Audit LTX flush (audit:ring, audit:seq:*) |
Yes (DO storage) | Smoke keys — session bookkeeping only, not compliance WORM (see below) |
| CoreToolsDO slim search/execute | Yes (default) | Mock + full-stack smoke celld-isolate; escape CLAWQL_CORE_IN_CELLD=0 → host MCP (Bun) |
Host clawql-audit via CLAWQL_AUDIT_WORM_URL |
No — fetch |
worm-fetch.test.mjs + full-stack SESSION_START + /chain/verify |
Streamable HTTP MCP (CLAWQL_MCP_URL) |
No — fetch |
mcp-fetch.test.mjs + mock smoke + full-stack real MCP |
Lab 5b OpenAPI pack (listPets + streams.session.noop) |
Host file | openapi-pack.test.mjs + smoke-host-mcp-pack.sh + full-stack CLAWQL_SPEC_PATH |
mcp-api-adapter REST (CLAWQL_MCP_ADAPTER_URL) |
No — fetch |
adapter-fetch.test.mjs + mock smoke + full-stack real |
| Inference multi-turn skeleton | No — fetch |
Smoke + full-stack: bind POST /v1/keys/bind + 2× POST /v1/messages (turns:2, virtualKeyBound); TTL expire-on-destroy → virtualKeyExpired |
| Lab VK budget / expire stub (local DeductionService stand-in) | No — stub HTTP | bash docs/examples/streams-celld/scripts/smoke-vk-budget.sh → bind → 402 ceiling → expire → 401 |
| ADR 0015 kill-node stand-in (file-journal SIGKILL) | Host Node | npm run demo:kill-node-standin → docs/benchmarks/program-kill-node-standin/evidence.json — host process only |
| ADR 0015 ProgramCellDO isolate kill-node | Yes (DO journal) | smoke-program-cell-kill.sh — write arm outcome_unknown + read arm resume re-run after SIGKILL celld |
| Helm celld StatefulSet / probes | Chart only | make helm-celld-template-tests |
| Fleet LTX / multi-node diagnose | Manual | docs/examples/idp/streams-celld/README.md |
clawql-streams package / stream_* tools |
Not shipped | Spec-only — see Streams §15 |
| Full DeductionService / model-escalation spend ceilings | Not shipped | Lab stub bind/budget/expire only; real ledger + model escalation on clawql-inference / clawql-payments |
| celld isolate kill-node (fleet / three-arm product gate) | Partial | Lab ProgramCellDO smoke + CI gate on streams-celld.yml; fleet LTX diagnose + three-arm product gate still open — ladder: durability-proof/STATUS |
| Operator mesh denial → host WORM | Package unit | clawql-k8s-operator worm-append + appendMeshDenialToHostWorm (no live Istio) |
| cellrt / TEE / QR stream source | Not shipped | Spec drafts under docs/streams/ |
| AWS Cost Explorer / live cloud cost measurement | Deferred | Local-only closeout; no paid AWS keys in Lab 5b gates |
Why full product is out-of-process (not “missing”)
Embedding Express mcp-api-adapter / vault clawql-memory / full clawql-api / disk-backed clawql-audit inside the Worker is incompatible with celld (no usable node:fs / Express / gRPC / stdio). Lab 5b demos the entire stack by running those hosts as sidecars and proving the cell fetches them — including compliance WORM on the host trail.
Commands (run from repo root)
Path-filtered CI (Streams celld evidence job)
Runs from .github/workflows/streams-celld.yml when Streams/celld paths change — not on every PR in ci.yml.
npm run build -w clawql-merkle -w clawql-core
npx vitest run packages/clawql-core/src/streams-slim.test.ts
node docs/examples/streams-celld/scripts/mcp-fetch.test.mjs
node docs/examples/streams-celld/scripts/adapter-fetch.test.mjs
node docs/examples/streams-celld/scripts/worm-fetch.test.mjs
node docs/examples/streams-celld/scripts/significance-filter.test.mjs
node docs/examples/streams-celld/scripts/core-catalog.test.mjs
node docs/examples/streams-celld/scripts/openapi-pack.test.mjs
node docs/examples/streams-celld/scripts/bundle-check.mjs
make helm-celld-template-tests
Expected: all exit 0; bundle size printed ≈ 0.4 MiB (must be < 64 MiB).
Host MCP + Lab 5b OpenAPI pack (no celld required):
bash docs/examples/streams-celld/scripts/smoke-host-mcp-pack.sh
Expected: search finds streams.session.noop and execute succeeds against the mock upstream.
Lab VK budget + expire (no celld / no provider keys):
bash docs/examples/streams-celld/scripts/smoke-vk-budget.sh
# or: npm run smoke:vk-budget (from docs/examples/streams-celld)
Expected: smoke-vk-budget: PASS with bind → turn1 200 → ceiling 402 → expire 200 → post-expire 401.
ADR 0015 file-journal SIGKILL stand-in (no celld isolate claim):
npm run demo:kill-node-standin
Expected: exit 0; writes docs/benchmarks/program-kill-node-standin/evidence.json with both arms ok: true. Honesty string must say this is not celld isolate kill-node.
ProgramCellDO isolate kill-node (requires celld; SIGKILL binary) — also CI on Streams celld smoke:
STREAMS_CELLD_SMOKE_REQUIRED=1 bash docs/examples/streams-celld/scripts/smoke-program-cell-kill.sh
# File-journal stand-in + kill-mid-write (no celld): npm run demo:kill-node-standin && npm run benchmark:kill-mid-write
Expected: smoke-program-cell-kill: PASS; evidence at docs/benchmarks/program-cell-isolate-kill/evidence.json with write arm outcome_unknown after celld restart. Ladder: docs/benchmarks/durability-proof/STATUS.md.
Local E2E smoke (requires celld v0.4.0 + esbuild)
CELLD_VERSION=v0.4.0 curl -fsSL https://celld.dev/install.sh | sh
npm run build -w clawql-merkle -w clawql-core
STREAMS_CELLD_SMOKE_REQUIRED=1 bash docs/examples/streams-celld/scripts/smoke.sh
# Core-in-celld (no host MCP for search/execute):
STREAMS_CELLD_SMOKE_REQUIRED=1 bash docs/examples/streams-celld/scripts/smoke-core-in-celld.sh
Without STREAMS_CELLD_SMOKE_REQUIRED=1, missing celld exits 0 with a skip message (developer convenience). CI and release gates must set the env var (or install celld and require the smoke).
Smoke covers: bundle-check → unit fetch/filter tests → mock MCP + mock adapter + inference stub → celld dev → significance never/rate/composite → webhook spawn → multi-turn inference (bind + turns:2, virtualKeyBound) → TTL exitReason:timeout + expire-on-destroy (virtualKeyExpired) → streams-slim / MCP / adapter / LTX. Compliance WORM is deferred unless CLAWQL_AUDIT_WORM_URL is set (full-stack smoke sets it). Core-in-celld smoke asserts transport: celld-isolate for search/execute.
Full-stack E2E — real clawql-mcp + adapter + host clawql-audit (CI Streams celld full-stack)
CELLD_VERSION=v0.4.0 curl -fsSL https://celld.dev/install.sh | sh
npm run build
npm run build -w clawql-merkle -w clawql-core -w mcp-api-adapter -w clawql-audit
STREAMS_CELLD_SMOKE_REQUIRED=1 bash docs/examples/streams-celld/scripts/full-stack-smoke.sh
Boots real clawql-mcp-http with CLAWQL_WORM_ENABLED=1 + CLAWQL_WORM_HTTP_PORT (host WORMAuditTrail HTTP), real mcp-api-adapter, points celld at MCP + adapter + CLAWQL_AUDIT_WORM_URL, and asserts:
- search / memory_* / adapter REST / inference multi-turn (
turns:2,virtualKeyBound, stub or gateway) - spawn writes
SESSION_STARTviaaudit.compliance(clawql-audit-http) GET /entries?sessionId=…returns that entry withhash/prevHash/chainIndexGET /chain/verify?sessionId=…returnsvalid: true
Optional containers: docs/examples/streams-celld/docker-compose.full.yml.
Cluster (manual — template-tested only in CI)
Follow docs/examples/idp/streams-celld/README.md. Helm templates are asserted in CI; live webhook→fleet→LTX is not automated yet.
CI wiring
Workflow: .github/workflows/streams-celld.yml (path-filtered + workflow_dispatch). Not part of always-on ci.yml.
| Check | Where |
|---|---|
| Helm celld templates | make lint-k8s-manifests → CI ShellCheck & actionlint |
| streams-slim + fetch/filter/catalog tests + bundle-check | Streams celld evidence (path-filtered) |
Mock smoke.sh + smoke:core-in-celld with celld |
Streams celld smoke (celld) (path-filtered) |
| Real MCP + adapter + host WORM | Streams celld full-stack (path-filtered / dispatch — not every PR) |
Doc sync
After editing docs/streams/clawql-*.md, regenerate site pages:
node apps/docs/scripts/sync-clawql-streams-doc.mjs
node apps/docs/scripts/sync-clawql-celld-doc.mjs
node apps/docs/scripts/sync-clawql-durable-objects-doc.mjs
node apps/docs/scripts/sync-streams-celld-evidence-doc.mjs
What this deliberately does not claim
- Full production
stream_subscribe/ Protocol Fabric event loop package - In-cell Express mcp-api-adapter / in-cell disk
clawql-audit(use sidecars) - Automated multi-node LTX /
celld diagnosefleet proof in GitHub Actions - Comparative “faster than X” marketing claims
- That DO
audit:ring/ celld LTX alone is a compliance audit trail (see below)
Closed (local): host MCP OpenAPI pack · Lab VK bind/budget/expire stub · ADR 0015 file-journal SIGKILL stand-in · AgentSessionDO expire-on-destroy via TTL alarm.
Still open (not local Lab 5b): full DeductionService ledger / model-escalation
spend ceilings · stream_* MCP package · AWS Cost Explorer measurement · fleet LTX /
three-arm product kill-node gate (Lab ProgramCellDO isolate kill smoke is Yes above).
Audit honesty: what Lab 5b actually records
As shipped (after dual-write) — which situation is true?
Lab 5b does not weaken ClawQL’s compliance story when configured correctly: consequential cell events dual-write to host clawql-audit; MCP tool hops land on the same tip-loaded trail when CLAWQL_WORM_ENABLED=1. The cell ring/LTX path is not the sole audit mechanism.
| Event | Where it lands | Continuity |
|---|---|---|
| Cell session bookkeeping (ring flush) | DO audit:ring / audit:seq:* → celld LTX |
Snapshot only — ring resets to genesis on new isolate |
| Consequential session start | Host clawql-audit via POST \{CLAWQL_AUDIT_WORM_URL\}/entries |
Tip-loaded WORMAuditTrail (no fork on host restart) |
MCP tool hops (search / execute / memory_*) when CLAWQL_WORM_ENABLED=1 on host |
Same host process WORM (dual-write in MCP wrap) | Same tip-loaded trail |
Fail-closed: when CLAWQL_AUDIT_WORM_URL is set, a failed / timed-out fetch to host WORM halts spawn (503, gateway spawn_failed) — it does not silently continue with ring-only logging. Unset URL remains deferred (mock smoke without a compliance sidecar).
Continuity proof (full-stack smoke): seeds a prior tip on the host trail, then asserts cell SESSION_START.prevHash === tip.hash and chainIndex === tip.chainIndex + 1, plus full-chain /chain/verify with entriesChecked >= 2 — not merely “an entry exists.”
Operational consequence: an operator who relies on the cell’s audit:ring / LTX alone, without CLAWQL_AUDIT_WORM_URL (and host CLAWQL_WORM_ENABLED for tool hops), has a compliance story that can silently lose hash-chain continuity across a cell restart — exactly the fork-on-restart failure mode WORMAuditTrail.create() / loadTip exists to prevent. Set the host WORM URL for anything you need to prove later.
Ring buffer’s job after dual-write: DO session-resumption bookkeeping only. Do not “upgrade” it into a second compliance system — extend host clawql-audit instead (same rule as execute-batching / spend-governance).
| Property | Lab 5b ring → DO/LTX | Host clawql-audit WORMAuditTrail |
|---|---|---|
| Tip load on restart | No | Yes |
| Dual-ack | No | Yes (not LTX) |
| Merkle batches | No | Yes |
Spec lines that say “LTX bucket = WORM trail” mean operator-owned durable DO SQLite replication for cell state — not “this replaces clawql-audit.”
cellrt: may harden native storage later for bookkeeping performance. Fixing compliance for cell-hosted agents is dual-write to host clawql-audit now, not waiting on a fork.
Hibernation economics (structural only — no dollar figures)
Do not cite vendor $/cell-month numbers in specs or GTM until ClawQL measures idle ratio and resident RAM on a real subscription mix.
Defensible today without a dollar claim: celld’s model is 1:1 durable object + hibernate API for per-subscription affinity (filter config, hibernatable WS). That is a different architecture from a K8s worker pool + queue, whose idle floor is min replicas — not “one Deployment per subscription.” Lead with that structural argument until measured costs exist.