Architecture Assessment — Compute Posture (on-prem vs Vercel) and the 127.20 ingress ruling
Re-filed S504 (ruling R9), from reference/: a ratified decision-support paper (output landed as DR-042..DR-046) — a point-in-time report, not durable facts.
Architecture Assessment — Compute Posture and the 127.20 Ingress Ruling
Section titled “Architecture Assessment — Compute Posture and the 127.20 Ingress Ruling”Status: DECISION-SUPPORT, authored S456 (2026-07-09) for owner ratification. Gates the
{127.20} private-ingress ruling and the id-71 Vercel-spec rework. Builds on — does not
re-derive — the salvaged ingress assessment
(canonical:.user-scratch/s454-recovery/id-127.20-private-ingress-assessment.md, cited IA
§N), the Vercel async-worker research
(specs/id-71-ai-tooling/research-inputs/vercel-async-worker-architecture.md, cited VR
§N), reference/deployment-architecture.md (DA §N), reference/decision-register.md
(DR-NNN), and the owner’s verbatim feedback
(canonical:.user-scratch/id-128-127-vercel-feedback.md, cited OF). Vercel/Cloudflare
product facts were re-checked live on 2026-07-09 against official docs (URLs inline); the VR
research doc’s facts (07/07/2026) held, with one material update flagged in §F.
Executive summary — the decisions Liam must make
Section titled “Executive summary — the decisions Liam must make”This paper reframes a cluster of questions the owner raised (OF) into six ratifiable decisions. Each has a recommendation; the reasoning is in the lettered section.
-
Compute posture (§A) — keep the split; do not move the app on-prem by default. The pipeline correctly lives on-prem (data-adjacent, compute-heavy, single-tenant). The Next.js app correctly stays on Vercel: it is a stateless, public-by-design layer that holds no client data at rest (the tenant boundary is the Supabase project, not the app server — PD “one project per client”), so moving it to the VPS buys no data-isolation at high ops cost. Recommendation: ratify the split. App-on-VPS becomes a per-client contractual option, not the default.
-
Define “zero-egress” precisely (§B) — it never meant literally zero. Client document content already leaves the box today: the pipeline calls Anthropic for extraction/embedding (DA §5.5), and client data sits at rest in Supabase cloud (single-tenant project per client). “Zero-egress” operationally means no client data at rest in shared multi-tenant third-party infra, and no non-essential egress — terms-protected model/transit egress (Anthropic no-train/ZDR; Supabase single-tenant) is the accepted, bounded exception. Recommendation: ratify this definition as the honest reading of the DR-017 promise; it is the load-bearing premise for decisions 3–6.
-
Per-client tooling-posture choice (§A/§D/§E) — offer cloud OR local, per client. Local equivalents for the Vercel stack are mostly close (§D): Queues → already have it (Supabase pgmq), Gateway → LiteLLM, Connect → Nango, agent runtime → goose (already the pilot). The one real gap is durable workflow execution (Temporal/Inngest — real ops on a 4 GB box). Recommendation: ratify a per-client choice — cloud AI-tooling in the client’s own Vercel project (ZDR) for cloud-native clients, or the local stack on the client VPS for strict-on-prem clients — kept behind our own thin interface so it is swappable. This choice forces the “thin-and-swappable, not all-in” answer to VR §4 Q1 (lock-in).
-
Agent topology (§E) — data-plane per-client, control-plane central. Every client runs all agent types inside its own isolation boundary (client VPS or client’s own Vercel project) with a per-client service-actor, read-only DB replica, and per-client OKF repo access (OF decision-surface pt 5). The Platform control/observability plane is central and trades in telemetry only (run status, tokens, timings, health) — never client corpus content. This is the “central view” the owner was missing (OF), and it keeps DR-017 intact. Recommendation: ratify; generalise DR-017 from goose to all data-plane agents.
-
Cloudflare “on-prem” framing (§C) — it stays on-prem; the nuance is transit, not residence. Putting Cloudflare in front does not move compute or storage off the box, so the on-prem property (single-tenant, client-owned compute + storage) remains true. The only new consideration is ingress transit: a TLS-terminating proxy (Cloudflare Tunnel) sees cleartext of whatever crosses the ingress. For the primary ingest flow this is only control metadata (
/walkcarries a pointer + bearer; files are pull-synced from the client’s own bucket, DA §5). Content bytes cross only on the/extractcleaner path. Recommendation: accept — on-prem is about where data lives and is processed, which is unchanged; manage the/extracttransit exposure explicitly (§F). -
The {127.20} ingress ruling (§F) — Cloudflare Tunnel default, origin-terminated escape hatch. Recommendation: ratify Cloudflare Tunnel + Access service token as the default private ingress (only option that makes the origin genuinely unreachable — no open port — with a free Zero Trust tier and DNS-only rollback), routed through the existing Traefik to preserve the
/walk|/health|/extractpath-scope, bearer retained as a second factor. New since the salvaged assessment: Vercel Static IPs are now self-serve on Pro ($100/mo/project) — this reopens IP-allowlist at Traefik as a fourth option and is the preferred origin-terminated alternative (strictly better than mTLS: no cert-expiry outage class) for any client that contractually requires no third party seeing content cleartext on the ingress. The/healthexternal monitor is retired (owner already agreed, OF). The prerequisite is moving the pipeline subdomain to Cloudflare nameservers.
One-line synthesis: the platform is already a hybrid — on-prem where data lives and is processed (pipeline, per-client Supabase), cloud where it is served and where terms-protected inference happens (Vercel app, Anthropic). The right posture is not “move everything on-prem” but “hold the at-rest bright line, make every cloud dependency per-client and contractually no-retention, and make cloud-vs-local a per-client choice behind our own interface.”
A. Compute posture — on-prem (IONOS/Coolify) vs Vercel
Section titled “A. Compute posture — on-prem (IONOS/Coolify) vs Vercel”The owner’s question (OF): “When we pivoted to on-prem, the cocoindex pipeline was hosted there, but should we also not have moved the app-side there too, rather than remaining in Vercel?”
The two workloads are not the same shape
Section titled “The two workloads are not the same shape”| Property | Pipeline (cocoindex) | Web app (Next.js) |
|---|---|---|
| State | Stateful — LMDB memoisation store, pull-synced corpus working copy on disk (DA §3 L-raw) | Stateless — renders/routes; holds nothing at rest |
| Data at rest | Working copy of client files on the box | None — reads/writes the client Supabase project over the network |
| Compute | Heavy Python (Docling, extraction, embeddings), long walks (VR §2) | Light request/response; serverless |
| Reachability | Private by intent (only the Vercel→VPS hop forces public reach — DR-015) | Public by design — it is the login-gated website |
| Tenant boundary | The client VPS + the client Supabase project | The Supabase project (PD “the DB is the tenant”) — not the app server |
The pipeline moved on-prem for a real reason: it is the data-adjacent, single-tenant, compute-heavy worker, and DR-017/DR-023/DR-025 put the client’s evidence and processing on the client’s own box. None of those reasons apply to the app. The app stores no client data at rest, is public by design, and Vercel is the first-party platform for Next.js (edge network, preview deploys, zero-ops TLS/CDN). Moving it to Coolify means self-operating the Next.js runtime, scaling, TLS, and preview environments — high ops cost for zero data-isolation gain, because the thing you would be “bringing on-prem” holds none of the client’s data.
Where “app on Vercel” does create surface — and why it is already handled
Section titled “Where “app on Vercel” does create surface — and why it is already handled”The app is the component that reaches into the private pipeline (the Vercel→VPS hop) and into Supabase. That is precisely the {127.20} ingress question (§F) and Supabase RLS — both already tracked. Vercel being in front of those hops is an ingress-hardening problem, not a data-residence problem.
Supabase (the owner’s adjacent note)
Section titled “Supabase (the owner’s adjacent note)”The owner noted Supabase stays cloud “for now” and that Coolify offers a one-click self-hosted Supabase. Self-hosting Supabase per client is possible but is a major ops step: you become the DBA for backups, Postgres upgrades, and the whole extension stack (pgvector, pgmq, pg_cron) — per client. Supabase cloud today is a single-tenant project per client (PD), already an accepted at-rest processor (§B). Recommendation: keep Supabase cloud as default; self-hosted-Supabase-on-Coolify is the same per-client contractual option as app-on-VPS — offered to a client who forbids a cloud DB, not the standard build.
Recommendation (A)
Section titled “Recommendation (A)”Ratify the split as correct, not accidental: pipeline on-prem, app on Vercel (as a per-client Vercel project — already the intention, OF decision-surface pt 2). Offer app-on-VPS and self-hosted-Supabase as per-client contractual options for strict-on-prem clients, not defaults. This is strictly a superset of today and costs nothing until a client asks.
Where on-prem is strictly worse (stated plainly): self-hosting the app or DB trades Vercel/Supabase’s managed TLS, CDN, preview deploys, backups, and Postgres lifecycle for your own pager. For a client with no contractual on-prem requirement it is pure ops cost with no security benefit — the data is not more contained (the app holds none; the DB is already single-tenant).
B. DR-017 per-client zero-egress boundaries — what egress each option creates
Section titled “B. DR-017 per-client zero-egress boundaries — what egress each option creates”The owner’s incisive question (OF): “If we use Anthropic or any other non-local AI model, are we not already in theory allowing client data to leave their environment already, or does ZDR + Secure compute from Vercel and Anthropic cover this?”
Yes — and this is the crux of the whole assessment. Client document content already leaves the client’s box today, in the current on-prem design: the extraction/embedding step calls Anthropic (DA §5.5: “AI extraction (Anthropic) → embeddings”). And client data sits at rest in Supabase cloud. So “zero-egress” was never literally zero. It has always meant, operationally:
No client data at rest in shared multi-tenant third-party infrastructure, and no non-essential egress. Terms-protected transit for essential functions — model inference under no-train/ZDR terms; a single-tenant managed DB — is the accepted, bounded exception. The bright line is at-rest-in-multi-tenant, not “a byte never crosses the boundary.”
Anthropic and single-tenant Supabase are today’s two contracted data processors. The right question for Vercel is therefore not “does any client data leave the box” (it already does, essentially) but “does adopting Vercel add a new third party, and at rest or only in transit?”
Egress created by each option
Section titled “Egress created by each option”| Option | New third party in path? | Client content at rest in it? | Client content in transit through it? | Preserves the commitment? |
|---|---|---|---|---|
| Status quo (pipeline on-prem, Anthropic direct) | Anthropic (existing) | No (VPS + client Supabase only) | Yes — prompts to Anthropic (no-train terms) | Baseline — this is the zero-egress posture as practised |
| Supabase cloud (current) | Supabase (existing) | Yes — but single-tenant project per client | n/a | Preserved — accepted at-rest processor, the DB is the tenant boundary |
| Local tooling stack (LiteLLM/Nango/pgmq/goose on client VPS) | None | No | Only to Anthropic (as today) | Fully preserved |
| Cloudflare Tunnel (ingress) | Cloudflare | No (tunnel is transit-only) | On /extract only (TLS-terminated at CF edge — sees cleartext); /walk is metadata | Preserved with a DPA + content-light ingress (§C, §F) |
| Vercel AI Gateway | Vercel | No with ZDR | Yes — prompts transit Vercel then Anthropic | Preserved with ZDR ($0.10/1k, pricing); marginal add over calling Anthropic direct |
| Vercel Workflows / Queues | Vercel | Yes, unless orchestrate-only — steps persist inputs/outputs in Vercel-managed storage (VR §1.2, §4 Q2) | Yes | Only if disciplined to orchestrate-only (pointers/IDs, never records — VR §4 Q5) |
| Vercel Sandbox | Vercel | Ephemeral | Yes, if code touches content | Only for code-execution agents (not a current need — VR §1.4) |
What “ZDR + Secure Compute” does and does not cover (answering the owner directly)
Section titled “What “ZDR + Secure Compute” does and does not cover (answering the owner directly)”- Anthropic ZDR / no-train: covers provider retention/training of prompts. It does not make the data “not leave” — it makes the leaving contractually bounded. This is the mitigation the current design already relies on.
- Vercel AI Gateway ZDR: routes only to providers with ZDR agreements and adds Vercel’s own no-retention; team-wide ZDR now costs $0.10/1k requests (moved behind a fee Apr 2026 — changelog). Caveat: BYOK keys are skipped by default under ZDR unless individually marked ZDR-compliant (ZDR docs) — relevant because the platform BYO-keys Anthropic today.
- Vercel Secure Compute: is about reaching a private backend, not model data — and it is AWS-shaped (VPC peering to your AWS VPC) and Enterprise-only (docs). Canonical’s boxes are IONOS, not AWS, so Secure Compute’s private-networking does not apply (its static-IP allowlisting does — see §F). It is not a client-data-egress control.
Recommendation (B)
Section titled “Recommendation (B)”Ratify the operational definition above. It makes the honest case: the platform already accepts terms-bounded transit (Anthropic); the defensible line to hold is no client data at rest in shared multi-tenant infra. Under that line: the local stack fully preserves the commitment; AI Gateway + ZDR and Cloudflare Tunnel + DPA preserve it as accepted-exception transit; Workflows/Queues preserve it only under orchestrate-only discipline (the concrete guard-rail — VR §4 Q5 — that makes a “yes” on Workflows compatible with a “no” on egress).
C. Does Cloudflare in front of the pipeline still count as “on-prem”?
Section titled “C. Does Cloudflare in front of the pipeline still count as “on-prem”?”The owner’s framing (OF): “based on our current Ionos/Coolify setup, will introducing Cloudflare (or possibly Control D), actually mean ‘on prem’ is true, or would the data that cocoindex ingests or processes need to be on the same box for this statement to actually be true?”
Answer: on-prem is about residence + processing, which Cloudflare does not move
Section titled “Answer: on-prem is about residence + processing, which Cloudflare does not move”“On-prem” in this codebase has never meant “on the client’s physical premises” — the VPS is a rented IONOS box. It means single-tenant, client-owned/client-controlled compute and storage, with data processed on a box dedicated to that client (DA §1, §9). By that definition:
- The data cocoindex ingests and processes is already on the box — the pull-synced corpus working copy on the VPS, writing the client’s own Supabase project (DA §3, §5). Cloudflare in front does not move any of that off the box. So the owner’s implied test — “would the data need to be on the same box for on-prem to be true” — is already satisfied, with or without Cloudflare.
- Cloudflare mediates only the ingress hop. It changes how a request reaches the origin, not where the data lives or is processed. On-prem stays true.
The real nuance: TLS termination model (what transits, in cleartext, and to whom)
Section titled “The real nuance: TLS termination model (what transits, in cleartext, and to whom)”This is the technically precise version of the owner’s worry:
| Ingress model | TLS terminates at | Third party sees content cleartext? | What actually transits |
|---|---|---|---|
| Cloudflare Tunnel (TLS-terminating proxy) | Cloudflare edge | Yes — CF decrypts, re-encrypts to origin | /walk: bearer + pointer (metadata). /extract: document bytes (content) |
| mTLS at Traefik (origin-terminated) | The origin (Traefik) | No | Same paths, but end-to-end encrypted to the box |
| Static-IP allowlist (origin-terminated) | The origin (Traefik) | No (but the allowlisted source IP is a shared Vercel pool — §F) | Same, end-to-end to the box |
So: Cloudflare Tunnel keeps the data on-prem but inserts Cloudflare as a transit
processor that can see cleartext of whatever crosses the ingress. For the primary ingest
flow this is only control metadata — /walk carries a bearer + a pointer, and the files
themselves are pull-synced from the client’s own Supabase bucket to the VPS (DA §5, DR-023/
DR-025), never through Cloudflare. Content bytes cross the ingress only on the /extract
cleaner path (lib/extraction/clean-via-worker.ts, IA §1). That is a bounded, addressable
exposure (§F), not a wholesale “your data now goes through Cloudflare.”
Control D (the owner’s alternative): Control D is a DNS resolver / filtering service — it governs name resolution policy, not ingress. It does not give the pipeline origin privacy the way a Tunnel does and is not a substitute for the {127.20} ingress decision. It solves a different problem (egress DNS policy / content filtering) and can be considered separately if that need arises.
Recommendation (C)
Section titled “Recommendation (C)”Accept that Cloudflare-in-front keeps the pipeline on-prem (residence + processing
unchanged). Treat the only real question as ingress transit exposure under TLS termination,
and manage it on the content-bearing path (/extract) per §F — either keep that path
content-light (route extraction through pull-from-bucket like /walk) or cover it under
Cloudflare’s DPA. For a client who will not accept any third party seeing content
cleartext on the ingress, choose an origin-terminated option (Static-IP allowlist or
mTLS, §F).
D. Local-equivalent feasibility for the Vercel agent stack
Section titled “D. Local-equivalent feasibility for the Vercel agent stack”The owner’s question (OF): “If we didn’t use Vercel’s functionality, how far are we currently from what we would need … (Gateway, Connect, Sandbox, Queues, workflows & agent framework) so that we had an entirely local equivalent?”
Assessed per primitive, on the existing Coolify boxes, with an honest ops cost. (Vercel-side facts: VR §1.)
| Vercel primitive | What it does | Self-hosted equivalent on Coolify | Gap / ops cost |
|---|---|---|---|
| Queues (VR §1.3) | Durable pub/sub | Supabase pgmq (in the client’s own DB) — already available; or Redis+BullMQ on the VPS | ~Zero gap. pgmq lives inside the client Supabase project — the most isolation-aligned option (DR-023/DR-025). Low ops. |
| AI Gateway (VR §1.5) | Model router, spend obs, fallback | LiteLLM (OSS proxy: routing, BYOK, spend tracking, fallbacks) | Small gap. One container + config per box. Or skip entirely and call Anthropic direct (status quo). |
| Connect (VR §1.6) | Outbound SaaS OAuth/API-key brokering | Nango (OSS unified OAuth for SaaS) + a secrets manager (Infisical/Vault) | Small–moderate gap. Only needed when SaaS connectors land (WS-1/WS-6 — deferred, PD). |
| Agent runtime (eve, VR §1.1) | Headless agent framework | goose — already the id-71 pilot, already the per-client target (DR-017) | Have it for the runtime. The delta vs eve is the durable-session/hooks layer (= the Workflows gap below). |
| Sandbox (VR §1.4) | Ephemeral untrusted-code microVMs | gVisor/Firecracker microVMs, or resource-capped ephemeral containers | Far, but likely unneeded. Safe isolation of AI-generated code is genuinely hard; no current requirement (VR §1.4). Defer. |
| Workflows (VR §1.2) | Durable execution: replay, sleep-months, hooks, auto-retry | Temporal (self-hostable, the gold standard) / Inngest (lighter) / roll-your-own on pgmq + a state table | The real gap. Durable execution with month-long sleep + human-gate hooks is sophisticated; Temporal is real ops (its own cluster + DB) on a 4 GB Server B (VR §3). This is where Vercel’s managed offering is materially ahead. |
Reading
Section titled “Reading”“Not that far” is true for four of six: Queues (have it), Gateway (LiteLLM), Connect (Nango), agent runtime (goose). Sandbox is far but unneeded near-term. The one genuine gap is durable workflow execution — and it is the highest-ops piece to self-host. So an entirely local AI-tooling stack per client is feasible, at the cost of standing up and operating LiteLLM + Nango + pgmq (+ optionally Temporal/Inngest) on each client box — meaningful but bounded, with durable-execution the long pole and the hardware (4 GB) the constraint to watch.
On the owner’s “raindrop.ai vs Vercel” question (OF, Vercel-spec feedback): category error
— Raindrop is an eval-authoring tool (id-104), localhost-only, permanently excluded
from the client-data path (zero egress enforced in lib/eval/graduation.ts; DA §8). Vercel
Workflows/eve is a production worker/agent runtime. Neither replaces the other; Raindrop
never touches client data by design, so it is not in this trade at all.
Recommendation (D)
Section titled “Recommendation (D)”Because the local stack is feasible for the common primitives and the durable-execution gap is the only expensive one, make cloud-vs-local a per-client choice (decision 3) rather than a platform-wide fork — and keep the agent/tooling layer behind our own thin interface so the durable-execution + model-routing + credential-brokering surface can be backed by either Vercel primitives or the local stack, selected per client. This directly answers VR §4 Q1 (lock-in): thin-and-swappable, not all-in on eve — the per-client-choice requirement forces that answer.
E. Per-client vs central topology for agent types
Section titled “E. Per-client vs central topology for agent types”The owner’s confusion, stated honestly (OF): “the spec seems to point to not all agents being ‘per client’, which may be my confusion — I would have thought that each client could use all available agent types within their instance, but perhaps I hadn’t yet thought about what this looks like centrally for us from a Platform-perspective.”
The resolution: separate the data plane from the control plane
Section titled “The resolution: separate the data plane from the control plane”The VR doc treated “a Vercel-hosted eve fleet” as multi-tenant Vercel infra, the inverse of
DR-017 (VR §2, §4 Q2) — its “sharpest strategic fork.” The owner’s steer dissolves most of
that fork: per-client Vercel projects are already the intention (canonical-platform +
the first client’s own project already exist — OF decision-surface pt 2). A per-client
eve/Workflows fleet in the client’s own Vercel project is per-client-isolated, not
multi-tenant. So the real fork is only “client VPS vs client’s own Vercel project” for a
data-plane agent — both are per-client, both honour DR-017’s boundary.
| Plane | What runs here | Topology | Sees client content? |
|---|---|---|---|
| Data plane — every agent that reads/writes the client’s corpus, records, or OKF bundle (the id-71 strawman HA agents: trust sweeps, briefings, watch-agents, expiry sweeps, onboarding — VR §2; goose; anything that “does work on the client’s knowledge”) | Per-client, inside the client’s boundary (client VPS or client’s own Vercel project), with per-client service-actor + read-only DB replica + per-client OKF repo access (OF pt 5) | Yes — hence per-client | |
| Control plane — Platform observability, fleet health, deploy/manage, aggregate spend, agent-run telemetry | Central to Platform | No — telemetry only (run status, tokens, timings, error rates). Never corpus content |
Every client gets all agent types — but each client’s instances of those agents run in that client’s boundary. The central Platform plane is what the owner was missing: it gives one dashboard over all clients’ fleets without any client content crossing into Platform, because it trades in metadata, not data. This is consistent with DR-017, whose promise is explicitly about the data and its processing (“the agent processing a client’s knowledge — and its API spend — lives on that client’s box”) — telemetry and management are not that data.
Recommendation (E)
Section titled “Recommendation (E)”Ratify data-plane-per-client / control-plane-central, and generalise DR-017 from goose to all data-plane agents: the per-client isolation boundary is satisfied by either the client VPS or the client’s own Vercel project. This makes the id-71 headless-agent surface buildable without re-litigating isolation for each agent type, and gives Platform a clean central observability story.
F. The {127.20} Cloudflare-vs-mTLS ingress ruling
Section titled “F. The {127.20} Cloudflare-vs-mTLS ingress ruling”The salvaged assessment (IA) compared three options and recommended Option A — Cloudflare Tunnel + Access service token over mTLS at Traefik, with Tailscale reserved for operator SSH only. That reasoning stands for the “make the origin genuinely unreachable” goal (IA §2, §5). Two things now refine it: (1) the §C termination-model analysis adds an axis, and (2) a current-facts update reopens a fourth option.
Material update — Vercel Static IPs are now self-serve on Pro
Section titled “Material update — Vercel Static IPs are now self-serve on Pro”The IA/S436 premise was “Vercel egress IPs aren’t stable without Enterprise Secure Compute,” which ruled IP-allowlist at Traefik impractical (IA §2). That premise has softened. As of the current docs (last_updated 2026-06-30):
Static IPs (shared pool) are available on Pro and Enterprise, $100/mo per project, giving fixed outbound egress IPs explicitly for “on-premises databases and services behind firewalls” — without Secure Compute. (Static IPs docs)
So a fourth ingress option now exists that the salvaged assessment dismissed: Vercel Static IPs (Pro) + Traefik/firewall IP-allowlist. Its caveats matter, though:
- The pool is shared among a small group of Vercel customers — allowlisting it means allowlisting “any customer in that shared pool,” not only us (weaker source-identity than a Cloudflare service token or a dedicated Secure-Compute IP).
- It leaves 443 publicly listening — the origin stays directly reachable, just source-IP-filtered. It does not retire the “directly public” property (the actual {127.20} goal). Same class as mTLS on that axis.
- $100/mo per project × per client — multiplies per tenant, vs Cloudflare Zero Trust’s free tier.
- Edge runtime is unsupported (fine — the pipeline calls already need Node-side handling).
The four options on the axes that matter
Section titled “The four options on the axes that matter”| Axis | Cloudflare Tunnel | Static-IP allowlist (Pro, new) | mTLS at Traefik | Tailscale/WireGuard |
|---|---|---|---|---|
| Origin “not directly public” | Best — no open port (cloudflared outbound-only on 7844, docs) | Port open, IP-filtered | Port open, cert-gated | Best, but wrong fit for serverless (IA §4) |
| No 3rd party sees content cleartext (§C) | Weakest — TLS terminates at CF edge | Best — origin-terminated | Best — origin-terminated | Best |
| Ops / failure modes | Best — managed, free tier, DNS-only rollback | Moderate — $100/mo/project, shared pool | Worst — cert-expiry outage class, fights Coolify-managed Traefik (IA §3) | High — persistent daemon, mismatched to Vercel serverless |
| Per-client cost at N | Best — free ZT tier | Worst — $100/mo × N projects | Moderate — internal CA + per-client cert | n/a for this hop |
| Fit to Vercel serverless | Native — CF-Access headers, no static IP needed | Native | Node-runtime + custom agent only (IA §3) | Poor (IA §4) |
The one honest tension, and how to resolve it
Section titled “The one honest tension, and how to resolve it”Cloudflare Tunnel is best on reachability, ops, and per-client cost, but worst on the §C
“no third party sees content cleartext” axis because it TLS-terminates at the edge. That
demerit only bites the /extract content path — the primary /walk ingest flow crosses
the ingress as metadata only (files pull-synced from the client’s own bucket, §C). So the
resolution is:
- Keep the content path content-light. Prefer routing extraction through pull-from-bucket
(as
/walkalready does) rather than POSTing bytes over the ingress; where/extractbytes must cross, cover Cloudflare under a DPA (the tunnel is transit-only — no client data at rest in Cloudflare, §B). - With that in place, Cloudflare Tunnel’s edge-termination is a bounded exposure, and its advantages (genuinely unreachable origin, free, DNS rollback) dominate.
Recommendation (F)
Section titled “Recommendation (F)”- Ratify Cloudflare Tunnel + Access service token as the DEFAULT private ingress, routed
through the existing coolify-proxy Traefik to preserve the Inv-13
/walk|/health|/extractpath-scope and the/stage404 (IA §2), bearer retained as a second factor. Prerequisite: move the pipeline subdomain to Cloudflare nameservers. - Adopt Static-IP allowlist (Pro) as the preferred origin-terminated alternative for any
client that contractually requires no third party seeing content cleartext on the
ingress. It is strictly better than mTLS (no cert-expiry outage class, no Coolify-Traefik
tls.optionsfriction) at the cost of $100/mo/project and shared-pool source identity. Demote mTLS to last-resort. (This is the same per-client-choice pattern as decisions 3 and A: a default plus a contractual escape hatch.) - Retire the external
/healthuptime monitor — owner already agreed (OF); liveness is covered by the ingress-independent Docker loopback healthcheck + the Supabasedatapath-watchsignal (IA §1, §5). No Access Bypass needed. - Tailscale/WireGuard for operator SSH/admin only, separately, later (IA §4) — not this gate.
Migration from the DR-015 interim
Section titled “Migration from the DR-015 interim”The interim public+bearer posture (DR-015) holds until the first of: a second client goes
live, or a client contractually requires private ingress. The move is exactly IA §2’s
ordered migration — deploy cloudflared sidecar → Access app (service token) → add the two
CF-Access-* headers to the three pipeline fetches (pipeline.ts, folder-drop.ts,
clean-via-worker.ts, IA §1) → parallel-run → cut DNS to the Tunnel CNAME → close inbound
443/80. Bearer retained throughout; rollback is DNS-only in minutes. One new coupling:
because per-client Vercel projects exist, the service token is minted + stored per client
Vercel project — joins the S440 per-client walk-orchestration gate (IA §6; journal
2026-07-03).
Consolidated implications — what changes if each recommendation is ratified
Section titled “Consolidated implications — what changes if each recommendation is ratified”| # | Decision | deployment-architecture.md | Decision register | id-71 / Vercel spec |
|---|---|---|---|---|
| 1 | Keep compute split; app-on-VPS + self-hosted-Supabase as per-client options | Add a “compute posture” note to §1/§9: app = per-client Vercel project (stateless, no at-rest); VPS/self-host Supabase = per-client contractual option | New DR: “Compute posture — app on Vercel (per-client project, stateless); pipeline on-prem; app-on-VPS + self-hosted-Supabase are per-client contractual options” | Vercel spec: drop the “multi-tenant infrastructure” framing (VR §2) — per-client projects are the model |
| 2 | Zero-egress definition | §4 ingress-posture note + a new “egress model” subsection: at-rest bright line; Anthropic + single-tenant Supabase are accepted contracted processors | New DR: “Zero-egress = no client data at rest in shared multi-tenant infra + terms-protected transit; Anthropic/Supabase-single-tenant are accepted processors; bright line is at-rest-in-multi-tenant” | Resolves VR §4 Q2 (egress vs DR-017) as a definition, not a fork |
| 3 | Per-client cloud-OR-local tooling behind a thin interface | §7 (goose) generalised to the tooling layer; note the local stack (LiteLLM/Nango/pgmq/goose[+Temporal]) as the on-prem option | New DR: “Per-client AI-tooling posture is a CHOICE (cloud in client’s own Vercel project + ZDR, or local stack on client VPS), behind our own thin swappable interface” — settles VR §4 Q1 lock-in as thin-and-swappable | Vercel spec: adopt Workflows/Gateway behind our interface, not eve-all-in; Queues → pgmq baseline |
| 4 | Data-plane per-client / control-plane central | §7 + §9: generalise DR-017 to all data-plane agents; add the central control/observability plane (telemetry-only) | New DR (or DR-017 amendment): “per-client isolation = client VPS OR client’s own Vercel project; ALL data-plane agents per-client; Platform control plane central, telemetry-only, never client content” | Vercel spec: the id-71 HA agent inventory is per-client data-plane; add a Platform control-plane surface |
| 5 | Cloudflare stays on-prem; manage transit | §4: add the TLS-termination table (who sees cleartext); note /extract as the only content-bearing ingress path | (Covered by the §F ingress DR) | — |
| 6 | Cloudflare Tunnel default + origin-terminated escape hatch; /health retired | §4 ingress-posture: replace “Cloudflare Tunnel or mTLS” with the ratified default + Static-IP escape hatch; note /health monitor retired | New DR (the {127.20} ruling): “Cloudflare Tunnel + Access service token default; Static-IP-allowlist (Pro) preferred origin-terminated alternative; mTLS last-resort; /health external monitor retired” — supersedes the open clause of DR-015 | Unblocks {127.20}; couples service-token issuance to the S440 per-client gate |
Open questions I could not resolve from the inputs
Section titled “Open questions I could not resolve from the inputs”-
/extractre-homing. Whether the/extractcleaner path can be re-routed through pull-from-bucket (like/walk) — which would make the ingress entirely content-light and neutralise Cloudflare’s TLS-termination demerit (§C, §F) — is an implementation question the inputs don’t answer. Needs a code-truth pass onlib/extraction/clean-via-worker.tsand the app-side upload/folder-drop rework ({131.24}). -
Which first client is which posture. Decisions 3, A, and F all hinge on a per-client cloud-vs-local / default-vs-escape-hatch choice. The owner notes the first client already uses Hubspot/Asana/Notion (OF) — implying cloud-native — but the actual contractual on-prem requirement per client is a commercial fact not in these inputs. Needs the owner to state, per signed/pipeline client, whether they require strict on-prem.
-
Durable-execution engine choice (if local). If a strict-on-prem client needs the durable workflow layer locally, Temporal vs Inngest vs roll-your-own-on-pgmq is unresolved — it turns on the 4 GB Server B constraint and expected workflow volume (VR §3). Needs a spike, not a ruling.
-
AI Gateway adoption at all. Whether to insert the Vercel AI Gateway (per-tenant spend observability + routing) vs continue calling Anthropic directly (status quo, one fewer third party) is a genuine trade the inputs frame but don’t decide (VR §1.5, §4 Q3). The BYOK- under-ZDR caveat (§B) makes it slightly more friction than it first appears.
-
Cloudflare DPA / nameserver move. Whether the org will (a) move the
aisolutionhub.co.ukpipeline subdomain to Cloudflare nameservers and (b) accept a Cloudflare DPA for/extracttransit is a policy/commercial call only the owner can make — it is the hard prerequisite for the §F default (IA §7).
Ledger-write intents (for the Orchestrator to apply on main — not written here)
Section titled “Ledger-write intents (for the Orchestrator to apply on main — not written here)”- {127.20} journal append: “S456 architecture assessment authored
(
reference/arch-assessment-compute-posture-s456.md). Ingress recommendation refined: Cloudflare Tunnel + Access service token remains the DEFAULT, but (a) the §C TLS-termination analysis adds a ‘no third party sees content cleartext’ axis, and (b) a current-facts update — Vercel Static IPs now self-serve on Pro, $100/mo/project — reopens IP-allowlist as a fourth option and the preferred origin-terminated escape hatch, strictly better than mTLS. mTLS demoted to last-resort./healthexternal monitor retired (owner-agreed). Subtask stays blocked pending owner ratification of the six decisions + the Cloudflare nameserver/DPA prerequisite (OQ 5).” - DR-intents (5), to be written on ratification — one per Exec-summary decision (compute posture; zero-egress definition; per-client tooling-posture-choice-behind-thin-interface; data-plane-per-client/control-plane-central [generalises DR-017]; the {127.20} ingress ruling). Text drafted in the implications table.
- id-71 Vercel-spec rework intent: the research doc’s §4 owner-ratification questions Q1 (lock-in → thin-and-swappable), Q2 (egress → the §B definition), and the “multi-tenant Vercel infra” framing (§2) are resolved by decisions 2–4 + the per-client-Vercel-projects fact; the spec should be reworked to an adoption spec behind our own interface, not an eve-all-in plan. Q3 (cost ceiling), Q4 (timeline vs id-13*), Q5 (orchestrate-only guard-rail) remain open owner rulings.
Addendum (S456, item-6): the refinery model and what it changes
Section titled “Addendum (S456, item-6): the refinery model and what it changes”Status: authored S456 after owner ratification of decisions 1–5 (decision 6 held
CONDITIONAL pending this addendum — {127.20} journal, 2026-07-09). The main paper derived the
ingress ruling from the /extract-era snapshot of the pipeline (upload + URL inlets). The
owner’s steer: re-derive the ingress/egress requirements under the ratified corpus reframe
(canonical:.lavish/corpus-reframe-review.html, cited CR by its own section names; 8/8
rulings R1–R8 ratified S441 → DR-025/DR-026, refining DR-023/DR-020) before the ruling is
final — and answer the rec-4 observability question concretely. Where this addendum
disagrees with the main paper it supersedes it explicitly; everything else stands.
What the reframe establishes (the controlling model)
Section titled “What the reframe establishes (the controlling model)”Four load-bearing propositions, cited to the review’s own sections:
- The pipeline is a refinery, and the gate lives at promotion (CR §2 “The target model — the sieve, the gate that moved, and two loops”; CR §5: “the pipeline is a refinery that turns messy evidence into governed canon — and the gate lives at promotion”). The front door is deliberately light (connect a source, assign retention class — the binding gate, DR-020 as restated by DR-025); authority is earned at the knowledge-admission gate, never inherited from a folder.
- Connectors are the identity of the pipeline, not a deferred fork (CR §3, “Discovery agents, connectors, transcripts, PDF ingestion — elevated from ‘deferred fork’ to the identity of the pipeline”): “it’s the same sieve with more inlets” — uploads, watched folders, SharePoint/Drive, transcript feeds, websites, HRIS are the evidence-streams box of the CR §2 flow diagram, each binding carrying keep / ingest-once / live classes.
- The source-binding register is connector-first by design (CR R8): every binding records origin type, locator, retention class, cadence, auth as first-class columns, so each cocoindex native connector later “slots into an existing row shape instead of forcing a redesign” (encoded as a {138.3} must-encode).
- A fourth pattern exists beyond ingestion: external-referenced (CR §3, DR-025) — knowledge the platform points at but never ingests (CRM stays in HubSpot; agents consume it in place alongside Canonical).
The consequence the main paper under-weighted: the refinery acquires evidence by pulling. In cocoindex a connector is a source the engine reads (CR §2’s sieve; DA §5.4 incremental walk semantics); the recurring trigger fires on loopback inside the box (DA §4 ingress-posture, DA §5.3). “More inlets” therefore means more outbound pull lanes from the VPS, not more inbound crossings of the pipeline ingress.
G. What actually crosses the ingress, per inlet class
Section titled “G. What actually crosses the ingress, per inlet class”Definitions: the pipeline ingress = the Cloudflare-fronted /walk|/health|/extract
surface (DA §4). Pull-from-client-source = the VPS reaches out to fetch evidence
(egress from the box). Push-through-ingress = content bytes arrive inbound across the
pipeline ingress.
| Inlet class (CR §2 / R8 origin types) | How evidence moves | Crosses the pipeline ingress? | New egress lanes from the VPS | Class |
|---|---|---|---|---|
| Gated upload (today) | User → app → corpus bucket in the client’s OWN Supabase project (DR-025 demoted-bucket role); pipeline pull-syncs bucket → VPS pre-walk (DA §5, DR-023) | Only the /walk nudge — bearer + pointer, metadata | Bucket pull-sync (Supabase — existing accepted processor, §B) | Pull |
| Watched folder (keep-and-watch) | Cadence re-walk of the synced working copy; scheduled trigger is loopback (DA §5.3) | Nothing on the scheduled path; metadata nudge if app-triggered | Same bucket/source pull-sync | Pull |
| Drive / SharePoint connectors (live-connected, future) | cocoindex native connector: VPS makes outbound OAuth-credentialled reads of the client’s own Google/Microsoft tenancy | Nothing — connector reads never transit the ingress | NEW: VPS → Graph/Drive APIs (client’s own tenancy; credential brokering per posture — Nango local / Vercel Connect cloud, §D) | Pull |
| Transcript feeds (ingest-once, future) | Two shapes: (a) poll the provider API on cadence — outbound; (b) webhook push — must terminate at the app (public-by-design, proxy.ts-gated) which lands bytes in the client bucket → nudge → pull-sync | (a) nothing; (b) nothing, by design rule — the push is absorbed app-side, never at the pipeline ingress | VPS → transcript-provider API (client’s own account) | Pull (push absorbed at app/bucket) |
| URL / feeds (today) | The app’s SSRF-gated fetch retrieves the page; the fetched HTML body is POSTed through /extract for cleaning (lib/extraction/clean-via-worker.ts:1-28; server.py::_extract_handler contract) | Yes — the one content-bearing crossing. Code-truth materially bounds it: what crosses is already-public web HTML the client asked to import, never client corpus documents; the worker is a pure cleaner — it does not fetch and has no SSRF surface | App-side (Vercel) egress does the fetch, not the VPS | Push (the sole one; see re-homing below) |
| External-referenced (CR §3 fourth pattern) | Never ingested; data-plane agents consume in place (HubSpot etc.) | Nothing — no pipeline involvement at all; register row is metadata only | Agent-side outbound to the client’s SaaS (per-client boundary, §E) | Neither |
Verdict on the §C claim: the “only control metadata transits Cloudflare on the primary
flow” claim survives — and generalises. Every connector-class inlet the reframe adds is
pull-shaped by construction, so the connector-first future makes the ingress more
control-plane-pure, not less. The one push-through-ingress lane is /extract, and code-truth
softens the main paper’s characterisation of it (supersedes §C/§F’s “document bytes”
phrasing): the bytes are app-fetched public-web HTML, not client documents. Two design
rules fall out, both {138.3} must-encodes:
- The pipeline ingress is control-plane only. Push-shaped inlets (webhook feeds, future uploads) terminate at the app/bucket layer; evidence reaches the VPS exclusively by pull. New connectors must never add a content-bearing ingress route.
- Per-binding egress derivation. The connector-first register’s origin-type + locator + auth columns (CR R8) double as the source of a per-binding outbound host allowlist for the VPS — the register that admits an inlet also bounds its egress lane. (Egress policy is adjacent to, not part of, the {127.20} ingress gate.)
/extract re-homing (sharpens main-paper OQ-1, supersedes its framing): the naive
re-homing (“make the worker pull the URL like /walk pulls the bucket”) is wrong — it
would recreate an SSRF surface on B1 that {112.10} deliberately removed (the app’s
validateUrl is the SSRF gate; the worker is fetch-free by contract). The content-light
re-homing that preserves both properties is: app fetches (keeps the SSRF gate) → writes
the HTML to the client bucket landing zone → walk-nudge → pipeline pull-syncs. Whether
that indirection is worth it over a Cloudflare DPA covering public-web-HTML transit is now a
much smaller question than the main paper implied.
H. Does the {127.20} recommendation change?
Section titled “H. Does the {127.20} recommendation change?”It holds, and strengthens. Stated plainly: ratify §F as written — Cloudflare Tunnel
- Access service token as the default private ingress, Vercel Static-IP allowlist (Pro) as
the origin-terminated per-client escape hatch, mTLS last-resort,
/healthmonitor retired. The reframe removes weight from the tunnel’s only demerit: edge TLS termination mattered in proportion to content crossing the ingress, and under the connector-first model the ingress trends toward pure control metadata (§G) while the sole content lane carries public-web HTML. Meanwhile the tunnel’s advantages (origin genuinely unreachable, free Zero Trust tier, DNS-only rollback) are more valuable with more inlets, because the VPS’s inbound surface stays closed no matter how many connectors are added outbound.
One amendment to how the ruling is recorded (not to its substance): the DR that lands the {127.20} ruling must carry the ingress-is-control-plane invariant from §G alongside it — otherwise every future inlet (first webhook-shaped transcript feed, first native connector) re-opens the Cloudflare-vs-origin-terminated debate. The ruling and the invariant are one decision: the tunnel is safe because the ingress is control-plane; the ingress stays control-plane because push inlets terminate app-side. The subdomain move to Cloudflare nameservers + the DPA (main-paper OQ-5) remain the owner’s prerequisite call — with the DPA’s scope now honestly describable as “control metadata + client-requested public-web HTML in transit”.
I. The central observability plane (rec-4) — concrete recommendation
Section titled “I. The central observability plane (rec-4) — concrete recommendation”No single tool is the plane. The recommendation is a two-leg hybrid, both legs telemetry-only per decision 4, with Raindrop explicitly not in it:
- Vercel AI Gateway, team scope — the model-telemetry leg (cloud track). Live docs
(checked 09/07/2026, page last_updated 2026-06-20) confirm the Gateway’s observability is
team-scoped with per-project drill-down: “Stay in your team scope to see aggregated
metrics across all projects”, Requests summaries by project and by API key (request
count, tokens, P75 duration, P75 TTFT, cost), spend charts, and exportable request
logs (observability docs;
longer retention needs Observability Plus).
Because every per-client Vercel project lives in the single Platform team
(
platform-context.md: “each client gets its own Vercel + Supabase project”; thetw-groupteam hostscanonical-platform+ the first client’s project), the team-level AI Gateway dashboard IS the per-client rollup the owner asked about — per-client projects give per-client rows for free, per-API-key summaries give per-agent breakdown within a client, and none of it carries corpus content. Caveats: (a) this leg exists only for requests routed through the Gateway — adopting it for cloud-track clients is what creates the leg (advances main-paper OQ-4 toward “adopt”, matching the owner’s lean); (b) ZDR team-wide is $0.10/1k requests and BYOK keys are skipped by default under ZDR (§B); (c) the rollup depends on client projects staying in the Platform team — a client who demands their own Vercel account drops to leg 2. - The Platform-DB telemetry rollup — the system-of-record leg (covers what the Gateway
cannot see). The pattern already exists and is proven: the pipeline POSTs
/api/internal/pipeline-runs/record→pipeline_runsrows → thedatapath-watchmonitor (DA §5.6;platform-to-client-promote.md§2.2–2.3 uses it as the promote gate). Generalise it to anagent_runs-shaped telemetry feed: every data-plane runtime — on-prem goose, local-stack (LiteLLM spend logs), pipeline walks, and cloud agents alike — posts run status, tokens, timings, error class to the Platform DB. This is the only leg that covers strict-on-prem clients (who never touch the Gateway) and the only one the platform owns end-to-end; it is the system of record, with the Gateway dashboard as the richer live view for the cloud track. - Raindrop is not a leg and cannot be.
platform-context.mdis binding: Raindrop is local dev/CI eval-authoring tooling only (localhost:5899, zero egress enforced inlib/eval/graduation.ts); hosted raindrop.ai is permanently excluded from the client-data path (DA §8). Its place in this story is upstream: evals authored in Raindrop graduate into CI and inform what the telemetry legs should alert on — it is never the hosted runtime plane.
J. Platform-agents lifecycle — the owner’s model, confirmed with three refinements
Section titled “J. Platform-agents lifecycle — the owner’s model, confirmed with three refinements”The model — “build/test platform agents on our own Platform Vercel project fleet, then
propagate to clients when ready” — is correct, and it is not a new mechanism: it is the
already-ratified prove-on-Platform → pin → config-delta promote pattern
(runbooks/platform-to-client-promote.md: prove the full E2E path on the Platform rig →
cut an immutable release → apply a per-client config delta, “the same image moves
Platform → client unchanged; only config differs”) generalised from the pipeline image to
the agent layer. The goose pilot is this model already in motion: pilot on Server B,
staging-pointed, gates G0–G6, then per-client rollout (DR-017; DA §7). Three
refinements so the model stays aligned with decisions 3/4:
- Platform is client-zero, on Platform data. Building/testing on the Platform fleet means exercising agents against the Platform’s own Supabase project and corpus — never a client’s. The Platform Vercel project is a true tenant in the per-client topology, not a shared runtime that peeks across tenants.
- “Propagate when ready” = release-pinned per client, never fleet-push. The promote is
per-client and recorded (
per-client-release-pins.mdappend-only history); an agent version proven on Platform is offered to each client on that client’s schedule, exactly as pipelinevX.Y.Zpins work today. Per-client deltas are minted fresh (service-actor creds, DB refs, AI Gateway keys — the same shape as the runbook §4 env re-key). - The propagation target differs by posture (decision 3). For a cloud-track client the target is that client’s Vercel project (the first client is cloud-native — owner, S456); for a strict-on-prem client it is the local stack on their VPS. The thin swappable interface (decision 3) is what makes one proven agent artefact propagatable to either.
What changed vs the main paper (delta)
Section titled “What changed vs the main paper (delta)”| # | Main paper said | Addendum position |
|---|---|---|
| 1 | §C: content bytes cross the ingress “on the /extract cleaner path” — characterised as document bytes | Softened (supersedes): code-truth shows /extract carries app-fetched public-web HTML (worker is a fetch-free pure cleaner, no SSRF surface); client corpus documents never cross the ingress on any flow |
| 2 | §C claim scoped to the “primary ingest flow” (the /extract-era snapshot) | Generalised: the claim survives per-inlet under the connector-first model — every CR §3 inlet class is pull-shaped; the ingress trends more control-plane-pure as inlets grow |
| 3 | §F ruling stood on its own | Unchanged in substance, amended in recording: the DR must co-carry the ingress-is-control-plane invariant (push inlets terminate app-side; connectors are outbound pull) as a {138.3} must-encode, so new inlets don’t re-open the ruling |
| 4 | OQ-1: re-route /extract “through pull-from-bucket (like /walk)“ | Sharpened (supersedes): worker-side fetching would recreate the SSRF surface {112.10} removed; the content-light path is app-fetch → bucket → pull-sync — and the residual exposure the DPA must cover is public-web HTML only |
| 5 | OQ-4 (AI Gateway) left as an undecided trade | Advanced: team-scope observability confirmed live (per-project + per-API-key rollup, exportable logs); adopting the Gateway for cloud-track clients is what creates the model-telemetry leg of rec-4 — aligns with the owner’s lean; BYOK-under-ZDR caveat stands |
| 6 | Decision 4 named a central telemetry-only control plane but not the tool | Answered (rec-4): hybrid — AI Gateway team dashboard (cloud-track model telemetry) + Platform-DB pipeline_runs→agent_runs rollup (system of record; sole coverage for on-prem); Raindrop ruled out as a hosted plane by the platform-context constraint |
| 7 | OQ-2: which client is which posture — unknown | Part-answered by the owner (S456): first client is cloud-native (per-client cloud track); goose pilot still completes; 4 GB VPS capacity is dev-phase temporary |
| 8 | — (not covered) | New: the connector-first register’s origin/locator/auth columns double as the per-binding outbound egress-host allowlist — the register that admits an inlet bounds its egress lane (ID-138-adjacent, not part of {127.20}) |
Remaining open questions (addendum)
Section titled “Remaining open questions (addendum)”- Vercel team residency as a standing assumption. The rec-4 Gateway leg assumes client projects remain in the Platform’s Vercel team. If a future client demands their own Vercel account, their model telemetry falls to the DB-rollup leg — acceptable, but worth recording as an explicit assumption when decision 4’s DR is written.
- Transcript-feed provider shape. Whether the first transcript inlet is poll- or webhook-shaped is a per-provider fact; either way the §G design rule (webhooks terminate app-side at the bucket) holds — the open item is only which provider and cadence.
agent_runstelemetry schema ownership. Whether the generalised telemetry rollup is specced in ID-138 (register-adjacent) or id-71 (agent-layer) needs an orchestrator call; it is small either way, but decision 4’s DR should name its owner.- Cloudflare DPA + nameserver move (main-paper OQ-5) — unchanged, still the owner’s prerequisite call, now with the narrower honest scope from §H.