Skip to main content
Supabase Storage, per-client Render hosting, and Upstash are configuration paths, not proven capabilities. None have been exercised against a live account in this environment. FREE profile — local/shared, in-process inference — is what actually runs. See Config-only paths below before describing any of these as “wired up” to a client.

The wm@2 artifact

A trained workspace model (app/services/model_lifecycle.py) is a versioned manifest plus a set of files, written through the model store. Behind WM2_ARTIFACTS=false (default), a train produces the older wm@1 manifest — 13 fixed keys, no separate files. Behind WM2_ARTIFACTS=true, the manifest additionally carries:
FileEncryptedContents
manifest.jsonNo (the manifest itself)Every block below, plus content_hash and determinism_hash
svd.npzYesSign-pinned SVD basis, re-fit on the exact training corpus — audit/parity only; assignment stays in raw embedding space
bm25.json.zstYesBM25 term-frequency model + min/max score normalization
loop_stats.jsonNoPer-loop member count, radius p90, local tau
centroids.jsonNoPer-loop centroid vectors in raw embedding space
ledger_snapshot.jsonl.zstNoThis run’s loop-ledger rows + a derived prior_map (member_id → canonical loop_id)
config_lock.jsonNoEvery config kind’s frozen body + content_hash, plus the resolved theta chain, as literals
ann/index.meta.jsonNopgvector-HNSW index metadata
Encryption is envelope encryption (app/crypto/envelope.py) keyed by CAUSELOOP_MASTER_KEY. If the master key or DATABASE_URL is unavailable, encryption falls back to plaintext with a loud log warning — never silent — matching the established pattern elsewhere in this codebase (availability over confidentiality, but never a silent downgrade). content_hash (unique per train, registry/lineage identity) and determinism_hash (twin-train-comparable computation identity, excludes run-identity residue) are two deliberately different hashes over deliberately different bases — see Evaluation Gates → E-DET for exactly why.

In-process vs. hosted inference

Two independent axes control where inference runs: LOOP_INFERENCE_ENABLED (default false) — when true, forge_issue (the single ingest choke point) calls loop_inference.assign_and_stamp immediately after embedding, additionally gated on QUEUE_INGEST == "off" (see below). This is the in-process, synchronous path. INFERENCE_PROFILE ("free" default, or "prod") — controls what a hosted inference service (portal stage 06, POST /provisioning/client-profiles/{id}/services) actually provisions:
  • free: registers routing to SHARED_INFERENCE_URL (a shared, multi-tenant cluster-inference service) if configured — no Render API call at all. If SHARED_INFERENCE_URL is empty or unreachable, attach still succeeds; the service is marked degraded and in-process inference keeps serving regardless (the circuit-breaker design: attach means “register routing + a row,” not “guarantee a healthy remote service”).
  • prod: runs the real Render create → deploy → poll → healthcheck flow (app/services/render_client.py), per-client, using RENDER_API_KEY/RENDER_OWNER_ID.

FREE vs. PROD — what’s real and what’s config-only

FREE (INFERENCE_PROFILE=free, default)PROD (INFERENCE_PROFILE=prod)
Render API callsNoneReal create/deploy/poll flow — but see the warning below
Cost guardplan=starter/standard onlyplan=pro additionally requires staff:admin
Attach on missing shared serviceSucceeds, marked degraded, in-process keeps servingN/A
Test coverageExercised in this codebase’s test suiterespx-faked HTTP layer only
The PROD profile’s Render integration is dormant in this environment. The code comment in app/services/render_client.py says this directly: every code path is “exercised only against a faked HTTP layer, never a real Render API call” — no live Render account exists here. Do not describe per-client Render hosting as working; describe it as implemented and tested against a fake, never run against production infrastructure.

Redis Streams topology

Four streams, one real consumer group today:
StreamPurposeReal consumer group
cl:issues:ingest:v1New issue envelopes awaiting inference assignmentinference
cl:issues:assigned:v1Assignment resultsnone yet — documented future subscriber
cl:issues:outliers:v1Buffered/abstained assignmentsnone yet — documented future subscriber
cl:models:lifecycle:v1Model promotion/activation eventsnone yet — documented future subscriber
(app/services/streaming_topology.py) Only the ingest stream’s inference consumer group is implemented; the other three streams and their platform/minibatch/drift/notify subscribers are documented as future work, not yet built.

QUEUE_INGEST — the two ingestion modes

QUEUE_INGEST=off     # default — inline synchronous inference, first-class and tested
QUEUE_INGEST=redis   # outbox row -> relay -> stream -> consumer
off (default): the ingest API writes the issue directly; forge_issue’s inline hook does inference synchronously in the same request, when LOOP_INFERENCE_ENABLED=true. Documented as “a first-class, tested fallback, not an afterthought.” redis: the ingest API writes an outbox row instead of doing inference inline. A relay job (app/services/outbox_relay.py, driven by app/scheduler.py::register_outbox_relay_job every OUTBOX_RELAY_INTERVAL_SECONDS — default 3.0) publishes unsent outbox rows to cl:issues:ingest:v1. app/services/inference_consumer.py reads from there and does the assignment.

Effectively-once semantics — the consumer_ledger

The outbox relay is at-least-once: if relay_once publishes successfully but then fails to mark the row sent, the same row republishes on the next tick. This is explicitly safe by design, because the consumer dedups before doing any work:
claim = repo.try_claim_consumer_ledger(stream, cgroup, content_hash)
if claim is None:
    return "duplicate"   # no-op ack
The dedup key is (stream, consumer_group, content_hash)not the outbox row id or stream message id — so a re-publish of the same logical message is silently absorbed. “At-least-once publish + idempotent consumer = effectively-once,” proven in tests/test_outbox_relay.py::test_crash_window_duplicate_publish_is_absorbed_downstream.
One documented, un-closed gap: claiming the ledger row and performing the actual side effects (embed + assign) are not one atomic unit. A crash between them permanently strands the ledger row — redelivery of that exact content_hash is then silently swallowed with zero side effects, an at-most-once window rather than effectively-once. Backstopped by two things: the issue row itself is already written before this ever runs, and auto_infer.py’s debounced pipeline re-run independently picks up anything streaming inference dropped.

DLQ and replay

Messages dead-letter (published to <stream>:dlq) on: an unsupported/missing schema version, a tokenizer-version mismatch between the artifact and the running code, or exceeding QUEUE_MAX_ATTEMPTS (default 5) via reclaim of stuck deliveries (QUEUE_RECLAIM_IDLE_MS, default 60000). Replay is a staff CLI, not an automated background process:
.venv/bin/python -m scripts.queue_replay --inspect
.venv/bin/python -m scripts.queue_replay --replay --id <entry-id> --yes
.venv/bin/python -m scripts.queue_replay --quarantine --id <entry-id> --yes
Dry-run by default (--replay/--quarantine without --yes print what would happen and change nothing). A replay republishes to the original stream with a fresh trace_id but an unchanged content_hash — the same dedup mechanism above makes “replaying an already-processed message” a safe no-op. Every replay and quarantine writes an audit log row.

Honest degradation — GET /v1/provisioning/queues/health

"""HONEST DEGRADATION ... 'a green dashboard on a dead queue is that bug in
its most dangerous form.' Returns {"enabled": false, "reason": ...} whenever
the queue plane is not actually live — QUEUE_INGEST != "redis", no
REDIS_URL configured, or a genuine Redis connection failure — and NEVER
zeros for streams/consumers in any of those cases."""
(app/services/queue_health.py) Reachability is proven with a real Redis PING (short timeout), never assumed from settings alone. This endpoint is staff-gated (router-level require_staff() only — a read, not a mutation) and returns per-stream {name, length, lag, pending, dlq_depth} plus consumer liveness when the queue plane genuinely is up.

Config-only paths, never exercised against a live account

Say this explicitly whenever describing storage/hosting options — do not imply any of the following have been proven against a real account.
PathStatus
Supabase Storage (UPLOAD_STORE_URI=s3://...SupabaseUploadStore)Stub. Every method (save/open/delete) raises NotImplementedError("SupabaseUploadStore is config-only in this wave (untested-live)..."). The default, tested upload backend is local disk (file://./var/causeloop/uploads).
Per-client Render hosting (INFERENCE_PROFILE=prod)Real code, respx-faked in tests only — never run against a live Render account in this environment (see above).
UpstashNo Upstash-specific code exists anywhere in this repo. It is the presumptive hosted-Redis provider a real deployment would put behind REDIS_URL (a generic redis:// connection string) — exercised only against local Redis in dev/test here.
S3-compatible model store (MODEL_STORE_URI=s3://...S3ModelStore)This one is genuinely real code — boto3 + endpoint_url, moto-tested — and could point at a live Supabase Storage or Cloudflare R2 S3-compatible endpoint. It has simply never been pointed at one in this environment. Don’t conflate this with the upload-store stub above; they’re different backends behind a shared file:///s3:// convention.