# Canonical operational graph platform evaluation

**Research date:** 2026-08-21
**Platforms evaluated:** Airtable, Notion databases/data sources, Supabase, Cloudflare D1 + Workers
**Evidence rule:** Official first-party product documentation only. No accounts or external systems were touched.

## Answer first

**No. The hypothesis is false under the stated requirements.** None of the four products is both:

1. a managed, usable operational product with mobile and agent access; and
2. a no-custom-code substrate that *enforces* canonical identity, claim-level provenance/conflict preservation, atomic expiring agent leases, conditional authority, and receipt-gated closure under concurrent writers.

The platforms divide cleanly:

- **Airtable and Notion** are managed human-facing products. They can *represent* most of the nouns with tables/properties, relations, formulas, permissions, and automations, but they do not supply database-grade uniqueness on user-provided external IDs, compare-and-set lease acquisition, transactions, or invariant-enforced state transitions. They are credible projections and exception/approval surfaces, not a strict canonical truth engine.
- **Supabase and Cloudflare D1/Workers** are managed application infrastructure. They can host enforceable invariants, but only after custom schema, policy, state-machine, API, identity, and UI work. Calling the hosting managed does not make the application no-code.

**Exact recommendation:**

- If **zero custom code is non-negotiable**, designate **none** of these as canonical. Use **Airtable as a non-authoritative operational projection/exception surface** and keep source-native systems authoritative. A serialized integration writer would still be needed before allowing automated write-back.
- If Mitch accepts a **small, versioned custom truth layer**, choose **Supabase managed Postgres as the canonical operational graph substrate**. It is the shortest path to real uniqueness, typed foreign keys, row/column authorization, transactional lease/state transitions, generated APIs, realtime, webhooks, and scheduled work. Keep Airtable optional and disposable as the mobile/human read-and-approval projection.
- Do **not** choose Notion as the canonical store. Do **not** choose D1/Workers for this layer unless Cloudflare-only placement is more important than minimizing custom application code; D1 requires building substantially more of the safe application boundary yourself.
- In either operating mode, keep **Linear as a thin execution projection**: one issue per independently closable real-world commitment, never the authority for evidence, claims, leases, grants, or closure.

## Current connector reality

The connector facts supplied for this decision affect deployment friction, not the substrate verdict:

- Linear is live, but its live route proves only that issues can be projected and reconciled; it does not provide the canonical evidence/authority/lease contract.
- Notion and Supabase plugins are available. Availability proves a callable route, not that a production-safe data model, agent identity boundary, RLS policy, or transition API exists.
- The Airtable plugin is recommended but not installed. This report did not install it, authorize an account, or infer plan entitlements. Airtable mobile fit, permission behavior in Mitch's base, and actual connector identity attribution remain **UNKNOWN** until a synthetic pilot.
- The correct Cloudflare account is accessible. That makes Cloudflare a practical home for narrow glue, but it does not remove the Worker/API/policy/UI code required to make D1 canonical.

No connector was installed, no account was created, no plan was purchased, and no external system was mutated during this evaluation.

## What was counted as “no custom code” and “canonical”

“No custom code” permits normal SaaS configuration: tables/databases, fields/properties, relations, views, formulas, first-party permissions, first-party automations, and first-party MCP/OAuth connections. It does **not** permit JavaScript/Python scripts, Workers or Edge Functions, a webhook receiver, an external integration service, SQL functions/triggers/RLS policies, or a custom mobile/web application.

“Canonical” means the invariant survives uncoordinated or adversarial writers. It is not enough that an agent is prompted to behave. At minimum, the substrate must reject or quarantine:

- two records with the same source-system external identity;
- dangling or wrong-type links;
- a second agent claiming an unexpired lease;
- a non-owner heartbeat or completion attempt;
- an action that lacks the exact required authority grant;
- “done” without a durable action receipt and fresh readback;
- a new claim that silently overwrites a contradictory prior claim.

This distinction is decisive. A view that highlights bad states is useful, but it is not enforcement.

## Adversarial capability matrix

Legend: **Native** = platform primitive can enforce the requirement; **Partial** = can represent or approximate it without code but cannot guarantee it; **Code** = enforceable only with custom SQL/script/application logic; **Absent** = no first-party facility at the required layer.

| Required control | Airtable | Notion databases | Supabase | Cloudflare D1 + Workers |
|---|---|---|---|---|
| Stable external IDs + uniqueness | **Partial.** Airtable's own record ID is unique and immutable, but a source's external ID is an ordinary field. Dedupe and upsert are workflows, not a global unique constraint. | **Partial.** Page UUIDs and the auto-number ID property are stable; the ID is Notion-generated and cannot carry a source's own identity. A text external ID has no documented uniqueness constraint. | **Native** for primary keys, UUIDs, unique indexes/constraints; external identity can be a composite unique key. | **Native** for primary keys/`CREATE UNIQUE INDEX`; application-generated external IDs are straightforward. |
| Typed linked records / referential integrity | **Partial.** Linked-record fields are typed to a table and bidirectional, but UI cardinality restrictions are not hard integrity constraints across all write paths. | **Partial.** Relation properties link pages in a chosen database and can be one- or two-way; no documented SQL-like delete actions or hard cross-record constraint layer. | **Native.** Postgres foreign keys, data types, many-to-many join tables, and delete/update actions. | **Native.** D1 enforces foreign keys by default and supports SQLite constraint actions. |
| Field/claim provenance and conflict preservation | **Partial.** A normalized Claims table can be configured, but Airtable revision history is a UI audit aid, not an immutable claim ledger; external-sync changes can be hidden, retention is plan-limited, and history can be cleared. | **Partial.** Created/edited-by/time and webhook authors exist, but there is no first-party immutable field-claim/conflict ledger. It must be modeled as more databases and maintained by automation/integration logic. | **Code.** Excellent substrate for append-only claims, observations, conflicts, hashes, and event tables, but the ontology, immutability rules, triggers, and conflict detector are custom. | **Code.** D1 can store the same normalized/event model; triggers/checks and the conflict logic are custom SQL/Worker code. |
| Agent lease with atomic claim, expiry, heartbeat, reclaim | **Absent for strict enforcement.** Fields and time automations can approximate a lease; the first-party scheduler's fastest documented cadence is 15 minutes, and no compare-and-set/transaction primitive is exposed to no-code automations. | **Absent for strict enforcement.** PATCH updates and automations can set lease properties, but the API documents no conditional-write precondition or transaction. Automations also cannot trigger other automations. | **Code, strongly enforceable.** Supabase Queues natively hides a delivered message for a visibility window, but the canonical entity lease, owner-bound heartbeat, reclaim, and atomic state transition still require a transaction/RPC and policies. | **Code, enforceable.** Cloudflare Queues provides leased pull delivery, but permits a late acknowledgement even after redelivery to another consumer. A Worker/D1 conditional transition and idempotency rule are still required for one canonical owner/effect. |
| Authority gates | **Partial.** Field/table edit permissions apply to UI, mobile, automations, and API; Interfaces can expose constrained buttons. Permissions are primarily actor/field/table controls, not a row-state/action/amount policy engine. | **Partial.** Workspace/database/page access and page-level access rules exist. `Can edit content` permits editing every property value on accessible rows, and a UI page lock explicitly does not stop API updates. | **Code, strongly enforceable.** RLS handles row predicates, Postgres column privileges restrict fields, and RPC/functions can expose only allowed transitions. Policies and roles are custom SQL and must be tested. | **Code.** Cloudflare Access authenticates requests, but the Worker must validate identity and implement record/action policy. D1 has no documented first-party row/column policy layer comparable to Postgres RLS. |
| Closure receipts and “cannot close without receipt/readback” | **Partial.** Receipt records, links, formulas, field locks, and button-triggered automations can approximate the workflow. Airtable does not supply a cross-table transactional constraint making the receipt immutable and closure impossible through every writer. | **Partial.** Related receipt pages and formulas can display completeness, but accessible editors/API connections can still update status; page lock is not an API gate. | **Code, strongly enforceable.** Foreign keys plus a single state-transition function/trigger can require a receipt/readback row in the same transaction; RLS can make receipts append-only. | **Code.** Foreign keys, checks/triggers, and transactional batches can enforce it, but a Worker must expose the safe transition and authorization boundary. |
| APIs, webhooks, realtime, automations | **Native/strong.** Web API, change webhooks, incoming webhook triggers, no-code automations, and hosted MCP. Complex integrity still pushes work into “Run a script” or external middleware. | **Native/partial.** REST API, connection webhooks, database automations, outgoing webhooks, and hosted MCP. Connection webhook events are change signals rather than full content, can be aggregated or omitted after state reversal, may arrive out of order, and target at-most-once delivery; consumers must refetch current state. | **Native/strong primitives.** Generated REST API, database webhooks, Realtime, RPC/functions, Cron, Queues, and Edge Functions. Complex business operations still require SQL/functions or application code. | **Code-heavy.** D1 has a Worker binding and an administrative REST API. Cloudflare's own guide says external application access should use a proxy Worker. Cron, Queues, Workflows, and custom MCP are programmable services, not no-code database automations. |
| Mobile operational usability | **Native/strongest.** iOS/Android apps and mobile Interfaces exist, with documented feature gaps; automations cannot be configured in the mobile apps. | **Native/strong.** iOS/Android supports reading, editing, and comments; database offline download is currently limited to the first 50 rows of the first view. | **Absent as an end-user operational product.** Supabase supplies a developer dashboard/Table Editor and SDK quickstarts for building mobile apps. A usable operator UI must be built or bought. | **Absent as an end-user operational product.** D1 is queried from Workers/Pages/dashboard/CLI. A mobile/responsive operational UI must be built. |
| Multiple agents / cross-agent access | **Native/strong access, weak coordination.** Hosted Airtable MCP reads/writes using the connecting user's permissions; Web API/service identities can also access bases. It does not add lease or conflict semantics. | **Partial.** Hosted Notion MCP reads/writes with user OAuth, but official docs say it is unsuitable for headless use because a user must complete OAuth. REST internal connections can run headlessly after pages are shared. | **Native APIs; production MCP caveat.** Auth + REST/RPC support many scoped clients. Supabase explicitly describes its hosted MCP as development/testing tooling and recommends not connecting it to production, so production agents should use the application API/RPC, not developer MCP. | **Code.** Cloudflare offers managed account-level MCP and APIs, but application-level graph tools/permissions require a Worker or custom remote MCP server. Account MCP access is not the same as a safe operational action API. |

## Platform findings and hidden glue

### 1. Airtable: best managed surface, not a strict truth engine

What is genuinely native:

- `RECORD_ID()` exposes Airtable's platform-assigned unique record identifier, giving each Airtable record an internal identity distinct from a source-system key. [Finding Airtable IDs](https://support.airtable.com/articles/4688931572-finding-airtable-ids) and [Airtable formula functions](https://support.airtable.com/articles/7330071120-airtable-formula-field-functions-reference).
- Linked-record fields express one-to-one, one-to-many, and many-to-many relations and automatically maintain reciprocal links. [Understanding linked record relationships](https://support.airtable.com/articles/1484376934-understanding-linked-record-relationships-in-airtable).
- Field and table edit permissions apply wherever edits occur, including mobile, extensions, and API calls. This is useful for reserving receipt/status fields to a service identity or automation. [Field and table editing permissions](https://support.airtable.com/articles/2296468758-airtable-field-and-table-editing-permissions).
- Airtable supplies change webhooks, incoming webhook automations, conditional automation branches, and a hosted MCP server that can read/update records while honoring the user's Airtable permissions. [Webhooks API overview](https://support.airtable.com/articles/7385030819-airtable-webhooks-api-overview), [Incoming webhook trigger](https://support.airtable.com/articles/6618712925-airtable-automation-trigger-when-webhook-received), [Conditional automation groups](https://support.airtable.com/articles/8153928625-conditional-groups-of-automation-actions), and [Airtable MCP](https://support.airtable.com/articles/9897799762-using-the-airtable-mcp-server).
- Airtable has real iOS/Android use and mobile-optimized Interfaces, though the official feature matrix shows notable gaps (including no mobile automation configuration). [Mobile Interfaces](https://support.airtable.com/docs/mobile-interfaces-in-airtable) and [desktop/mobile feature differences](https://support.airtable.com/articles/9609457174-airtable-desktop-and-mobile-feature-differences).

Where the canonical claim fails:

- An Airtable record ID is not the source system's external ID. Airtable's own duplicate tooling is explicitly a find/review/merge workflow, and its automation recipe finds and *flags* duplicates after creation. The Web API's `performUpsert` can find/create/update in one API call, which is useful adapter idempotency, but the official documentation does not describe it as a table-wide unique constraint governing UI, automation, MCP, and other write paths. [Dedupe extension](https://support.airtable.com/articles/2534579068-dedupe-extension) and [API call limits and `performUpsert`](https://support.airtable.com/articles/7735693959-managing-api-call-limits-in-airtable).
- Linked-record cardinality is not uniformly enforced: Airtable documents that multiple links can still be created through automations or copy/paste even when “Allow linking to multiple records” is off. [Understanding linked-record relationships](https://support.airtable.com/articles/1484376934-understanding-linked-record-relationships-in-airtable).
- Record revision history is not a canonical provenance ledger. It is inspected one record at a time, has plan-dependent retention, may hide externally synced changes, and can be irreversibly cleared. [Record-level revision history](https://support.airtable.com/articles/3516802427-record-level-revision-history-in-airtable).
- A no-code lease would be “find apparently unleased row, then update it,” leaving a race between concurrent agents. Airtable's time automation can run no faster than every 15 minutes, which is not a heartbeat primitive. [Scheduled-time automation](https://support.airtable.com/v1/docs/at-a-scheduled-time-automation-trigger).
- Conditional automations are sequential action groups, not database transactions; only the first matching group runs and conditions cannot be nested. Complex invariants therefore migrate toward Airtable's own “Run a script” action, which is custom code by the stated test. [Conditional automation groups](https://support.airtable.com/articles/8153928625-conditional-groups-of-automation-actions) and [Run a script](https://support.airtable.com/articles/6328053615-airtable-automation-action-run-a-script).

Hidden glue required to call Airtable canonical:

1. a single serialized writer or external lock service;
2. insert-time external-ID uniqueness and idempotency service;
3. normalized Claim, Evidence, Conflict, Lease, AuthorityGrant, ActionRequest, Receipt, and Event tables;
4. code that prevents invalid state transitions across tables;
5. webhook receiver, retry/DLQ, origin/echo suppression, and post-write source readback;
6. durable export of history/receipts beyond Airtable's UI history semantics.

Once that glue exists, Airtable is the operator surface over the canonical engine, not the engine itself.

### 2. Notion: capable relational workspace, weaker operational enforcement

What is genuinely native:

- Notion's auto-number ID property is unique, uneditable, and never changes; page objects also have UUID identifiers and edit metadata. [Unique ID](https://www.notion.com/help/unique-id), [database properties](https://www.notion.com/help/database-properties), and [Page object](https://developers.notion.com/reference/page).
- Relation properties connect items in selected databases and can be one- or two-way; rollups aggregate across them. [Relations and rollups](https://www.notion.com/help/relations-and-rollups).
- Notion supports database/page access, `Can edit content`, `Can create`, and page-level access rules. [Sharing and permissions](https://www.notion.com/help/sharing-and-permissions) and [custom database permissions](https://www.notion.com/help/guides/assign-custom-database-permissions).
- Database automations can react to page/property changes or schedules and can edit properties, add/edit pages, notify users, and send a webhook. [Database automations](https://www.notion.com/help/database-automations).
- The REST API, connection webhooks, hosted MCP, and mobile apps are real. [Webhooks](https://developers.notion.com/reference/webhooks), [Notion MCP](https://developers.notion.com/guides/mcp/overview), and [Notion mobile](https://www.notion.com/help/notion-for-mobile).

Where the canonical claim fails:

- Notion's ID property is Notion-generated and read-only in the API. It cannot serve as a caller-supplied `(source_system, external_id)` key. A separate text property is writable but has no documented unique constraint. [Page property values](https://developers.notion.com/reference/page-property-values).
- `Can edit content` allows editing property values on accessible rows. Notion does not document field-specific business authorization comparable to row + column database policy. More sharply, the Update Page API states that `is_locked` only locks the page in the Notion UI and **does not affect API updates**. [Update page](https://developers.notion.com/reference/patch-page).
- The Update Page API is a PATCH by page ID; the official request shape documents no compare-and-set token, `If-Match`, or multi-record transaction. Two agents can both read an expired lease and then overwrite the lease properties.
- Automations cannot be triggered by other automations, operate over a roughly three-second change window, and may not act on restricted pages. These are useful workflow rules, not a transactional state machine. [Database automations](https://www.notion.com/help/database-automations).
- Connection webhooks require a reachable public receiver that verifies and processes events. More importantly, Notion documents them as signals rather than complete change records: a consumer must refetch current content; events can be aggregated, may arrive out of order, and target at-most-once delivery. A rapid create/delete/undelete sequence may produce only a summarized event or none if state returns to the original. They are not a durable canonical event log. [Webhooks](https://developers.notion.com/reference/webhooks) and [event types and delivery](https://developers.notion.com/reference/webhooks-events-delivery).
- Hosted Notion MCP requires user OAuth and explicitly does not support bearer-token authentication; Notion says this may not suit fully automated/headless agents. Headless access falls back to an internal REST connection/token and manually shared pages. [Connecting to Notion MCP](https://developers.notion.com/guides/mcp/get-started-with-mcp) and [Notion authorization](https://developers.notion.com/guides/get-started/authorization).
- Mobile is good for human use, but offline database downloads currently include only the first 50 rows of the first view. [Offline pages/databases](https://www.notion.com/help/use-pages-offline).

Hidden glue required is the same class as Airtable's—serialized/idempotent writes, lease authority, receipt-gated transitions, conflict records, webhook service, retries—plus a headless integration API. Notion's excellent document UX does not solve those operational invariants.

### 3. Supabase: best canonical substrate, not a no-code operational product

What is genuinely native:

- Each project is a full managed Postgres database. Columns have database types; primary keys are unique; foreign keys and join tables create typed relations. Supabase manages daily backups and offers point-in-time recovery on paid plans. [Tables and data](https://supabase.com/docs/guides/database/tables) and [database overview](https://supabase.com/docs/guides/database/overview).
- Postgres RLS applies row predicates to every access, and column privileges can separately restrict update/select on sensitive fields. [Row Level Security](https://supabase.com/docs/guides/database/postgres/row-level-security) and [Column Level Security](https://supabase.com/docs/guides/database/postgres/column-level-security).
- Supabase generates a REST API from tables, views, and functions, retaining Postgres relations, roles, grants, and RLS. [Data REST API](https://supabase.com/docs/guides/api) and [creating API routes](https://supabase.com/docs/guides/api/creating-routes).
- Database functions are callable through RPC; this is the right boundary for a single atomic `acquire_lease`, `heartbeat_lease`, `request_action`, or `close_with_receipt` transition. [Database functions](https://supabase.com/docs/guides/database/functions) and [RPC reference](https://supabase.com/docs/reference/javascript/rpc).
- Database webhooks fire after INSERT/UPDATE/DELETE through asynchronous `pg_net`; Realtime streams committed changes; Cron uses `pg_cron`. [Database Webhooks](https://supabase.com/docs/guides/database/webhooks), [Postgres Changes](https://supabase.com/docs/guides/realtime/postgres-changes), and [Cron](https://supabase.com/docs/guides/cron).
- Supabase Queues is a Postgres-native durable queue. It documents exactly-once delivery to a consumer *within* a configurable visibility window, archival, dashboard monitoring, and RLS/API permissions. Its public `read` function accepts a visibility timeout. This is a useful managed work-delivery primitive, but it is not by itself a canonical entity lease with named owner, heartbeat, and owner-bound completion. [Supabase Queues](https://supabase.com/docs/guides/queues) and [Queues API](https://supabase.com/docs/guides/queues/api).

Why it still fails the no-code hypothesis:

- The canonical ontology and all nontrivial invariants are not a prebuilt product. Claims, observations, conflicts, leases, grants, action requests, receipts, event/outbox rows, immutability, and state transitions must be designed and versioned.
- RLS and column grants are SQL policies; exact action gates and cross-table closure invariants require database functions/triggers or a trusted application layer. Supabase's own docs describe functions as SQL/PLpgSQL living in the database. [Database functions](https://supabase.com/docs/guides/database/functions).
- The generated REST API removes CRUD boilerplate, not business-logic work. Supabase documentation explicitly points to Postgres functions and Edge Functions for custom operations. [Data REST API](https://supabase.com/docs/guides/api) and [connecting Edge Functions to Postgres](https://supabase.com/docs/guides/functions/connect-to-postgres).
- Supabase supplies a developer Dashboard/Table Editor, not a polished end-user operational app. Its official mobile guides teach developers to create Flutter/Expo applications and write UI/query code. [Flutter quickstart](https://supabase.com/docs/guides/getting-started/quickstarts/flutter) and [Expo React Native quickstart](https://supabase.com/docs/guides/getting-started/quickstarts/expo-react-native).
- The hosted Supabase MCP is explicitly described as development/testing tooling; Supabase recommends not connecting it to production or giving it to end users. Production agents need application-scoped Auth + REST/RPC rather than developer-power MCP. [Supabase MCP](https://supabase.com/docs/guides/ai-tools/mcp).
- A current breaking change matters to pilots: new tables are no longer exposed to Data/GraphQL APIs automatically by default; explicit exposure/grants must be part of acceptance. [Supabase breaking-change changelog](https://supabase.com/changelog?types=breaking-change).

Supabase therefore wins **only after** changing the requirement from “no custom code” to “minimal, managed, versioned custom truth layer.” It wins because the custom work expresses the domain invariants directly instead of rebuilding database/auth/API primitives.

#### Recommended Supabase contract

The minimum truth layer is small but explicit. These are canonical records, not columns hidden inside one task row:

| Canonical relation | Required invariant |
|---|---|
| `operational_objects` | Stable platform UUID, object type, accountable owner, lifecycle state, current next action, acceptance test, and monotonically advancing revision. |
| `source_aliases` | One mapping per `(source_system, external_id)` enforced by a composite unique constraint; source-native ID and revision/hash are never replaced by a title match. |
| `edges` | Typed `from_object`/`to_object` foreign keys with validity and supporting evidence; no dangling relationships. |
| `evidence_observations` and `claims` | Append-only source observation plus field-path assertion, actor, observed time, source revision/hash, and confidence/status. A new assertion never overwrites its predecessor. |
| `conflicts` and `resolutions` | Contradictory live claims remain linked and visible until a named authority resolves them; the resolution adds a record instead of deleting history. |
| `leases` | Named agent/task owner, acquired/heartbeat/expiry times, lease revision, and state. A narrow transaction/RPC, using database time, is the only acquire/heartbeat/release/reclaim route. |
| `authority_grants` | Exact object/action, target/recipient/destination, scope or amount, approver, status, issued time, expiry, and grant revision. Grants authorize only the matching transition. |
| `action_requests` | Unique idempotency key, proposed action, requester, required grant, state, and expected canonical revision. |
| `receipts` and `events` | Append-only effect and fresh-readback evidence with actor, action, source, timestamps, artifact/hash/link, and truth status. Closure RPC rejects absent, mismatched, mutable, or unverified receipts. |
| `projection_outbox` and `linear_projections` | One durable outbox intent and one stored Linear issue ID per independently closable object; retries use idempotency keys and post-write readback. |

Ordinary agents should not receive generic table-update power over accepted claims, lease ownership, authority, lifecycle, or closure. RLS and column grants expose reads and append-only proposal/evidence paths; narrow RPC functions perform the guarded transitions. A durable event/outbox row is committed with each accepted state change so Realtime or webhook delivery is a wake-up signal, not the source of truth.

This is why Supabase beats the other three for the stated contract: Postgres can reject an invalid state *at commit time*. Airtable and Notion can display or flag many invalid states but lack the documented zero-code transaction/conditional-write primitives to reject every race. D1 can also enforce the model, but only after more of Auth, safe application API, policy, event, agent-tool, and operator-UI layers are built around it.

### 4. Cloudflare D1 + Workers: capable Cloudflare-native build, most hidden application work

What is genuinely native:

- D1 is Cloudflare's managed serverless database using SQLite semantics, with disaster recovery, Worker bindings, and an HTTP management API. [D1 overview](https://developers.cloudflare.com/d1/).
- D1 supports primary keys and unique indexes, including uniqueness enforcement, plus `STRICT` tables and CHECK constraints. [Use indexes](https://developers.cloudflare.com/d1/best-practices/use-indexes/) and [SQL statements](https://developers.cloudflare.com/d1/sql-api/sql-statements/).
- D1 defines and enforces foreign keys by default, including `RESTRICT`, `CASCADE`, `SET NULL`, `SET DEFAULT`, and deferred validation. [D1 foreign keys](https://developers.cloudflare.com/d1/sql-api/foreign-keys/).
- `D1Database.batch()` is transactional: statements execute sequentially and a failure rolls back the sequence. Sessions can provide sequential consistency and a first-primary read. [D1 Database API](https://developers.cloudflare.com/d1/worker-api/d1-database/).
- Cron Triggers, Queues, and remote MCP infrastructure exist. [Cron Triggers](https://developers.cloudflare.com/workers/configuration/cron-triggers/), [Queues](https://developers.cloudflare.com/queues/), and [remote MCP servers](https://developers.cloudflare.com/agents/model-context-protocol/guides/remote-mcp-server/).

Why it fails the no-code hypothesis more sharply than Supabase:

- D1's built-in REST API is intended for administrative use. Cloudflare's official external-access tutorial says an application outside Workers should build a proxy Worker to customize access and limit queries/tables. [Build an API to access D1](https://developers.cloudflare.com/d1/tutorials/build-an-api-to-access-d1/).
- D1 does not document a built-in PostgREST-like per-table application API, Auth, RLS, database webhook product, or operational UI. The Worker must parse/validate requests, authenticate principals, implement row/action policy, invoke D1, emit events, and format safe responses.
- Cloudflare Access authenticates the request, but the official docs still require the Worker/origin to validate the Access JWT. Authentication is not the domain authority rule. [Validate Access JWTs](https://developers.cloudflare.com/cloudflare-one/access-controls/applications/http-apps/authorization-cookie/validating-json/).
- Cron requires a `scheduled()` handler; push queues require producer/consumer Worker code. Queues are at-least-once and Cloudflare tells applications to use a unique ID/idempotency key when duplicates would be harmful. Pull consumers do expose a `lease_id` plus visibility timeout and give concurrent consumers unique batches, but Cloudflare also documents that it will accept an acknowledgement after the lease timeout even when the message was meanwhile delivered to and acknowledged by another consumer. Queue delivery therefore cannot be the sole proof of one canonical completion; the D1 mutation still needs an idempotent, owner-checked transition. [Cron Triggers](https://developers.cloudflare.com/workers/configuration/cron-triggers/), [Queue delivery guarantees](https://developers.cloudflare.com/queues/reference/delivery-guarantees/), and [pull consumers](https://developers.cloudflare.com/queues/configuration/pull-consumers/).
- Cloudflare's managed MCP can administer Cloudflare through OAuth/API tokens, but it does not automatically expose a domain-safe operational graph API. Cloudflare's custom MCP guidance is explicitly a guide to **build and deploy** a Worker. [Cloudflare's MCP servers](https://developers.cloudflare.com/agents/model-context-protocol/cloudflare/servers-for-cloudflare/) and [Build a remote MCP server](https://developers.cloudflare.com/agents/model-context-protocol/guides/remote-mcp-server/).
- D1/Workers supplies no first-party human operational mobile client; a Pages/Workers web app must be built.

D1 is technically capable. The issue is product shape: adopting it as canonical means building the safe API, policy engine, automation consumers, agent tools, and mobile UI that Supabase already partly supplies as managed primitives.

## Managed/no-code tradeoff in one table

| Platform | What the vendor manages | What Mitch's system would still have to own | Appropriate role |
|---|---|---|---|
| Airtable | Human UI, mobile apps, records/links, permissions, automations, API/webhooks/MCP | Strict external-ID uniqueness, concurrency/leases, cross-table invariants, durable claim/conflict/receipt semantics, reliable integration readback | Human projection, exception queue, approval surface |
| Notion | Document/database UI, mobile, relations, permissions, automations, API/webhooks/MCP | Same strict invariants plus headless-agent integration and webhook receiver; more bespoke workspace upkeep | Knowledge/context surface, not canonical operations |
| Supabase | Postgres, backups, Auth, generated API, RLS primitives, Realtime, webhooks, Cron, functions runtime | Domain schema, migrations, policies, functions/triggers, agent identities, integration adapters, operator UI | **Recommended canonical substrate if bounded code is accepted** |
| D1 + Workers | SQLite-compatible DB, serverless runtime, network/auth building blocks, queues/cron, platform MCP | Nearly the whole safe application boundary: API, Auth integration, authorization, state machine, webhooks/events, idempotency, agent tools, UI | Cloudflare-native custom application; not no-code |

## Linear remains a thin execution projection

Linear has useful execution primitives: issue relations for blocking/related/duplicate work, an official MCP route for issue/project operations, a GraphQL API, and change webhooks. Those capabilities make it a good downstream execution surface, not the authority for the broader operational graph. [Linear issue relations](https://linear.app/docs/issue-relations), [Linear MCP](https://linear.app/docs/mcp), [Linear GraphQL API](https://linear.app/developers/graphql), and [Linear webhooks](https://linear.app/developers/webhooks).

The projection contract is deliberately narrow:

1. Create at most one Linear issue for each independently closable canonical operational object—not one per email, document, source record, agent, session, or intermediate observation.
2. Put the canonical object ID and revision, bounded outcome, accountable owner, current authorized next action, acceptance test, genuine dependencies, and required closure receipt in the projection.
3. Resolve updates by the stored Linear issue ID, never a fuzzy title search. Use an idempotency key, update once, re-read the issue, and store the projection/readback receipt canonically.
4. Treat Linear comments, assignee/status changes, and webhook deliveries as intent or drift signals to reconcile. They do not overwrite accepted claims, lease ownership, authority grants, or closure truth.
5. Project `Done` only after the canonical closure transition has already accepted the exact authority, effect receipt, and fresh readback. A Linear-side `Done` without that receipt is drift, not completion.

The live Linear connector therefore satisfies reachability for the projection route only. It does not change the platform decision.

## Falsifiable pilot

### Gate 0: kill-test the “no-code canonical platform” hypothesis

Before any production connection, use an isolated workspace/project and synthetic data only. Permit platform UI configuration, formulas, built-in permissions, built-in no-code automations, and first-party MCP. Prohibit scripts, SQL functions/triggers/RLS policies, Workers/Edge Functions, external automation vendors, and custom webhook receivers.

Create at least these entities: Commitment, SourceAlias, Claim, Conflict, Lease, AuthorityGrant, ActionRequest, Receipt, Event. Give two independent agent principals write access and one read-only principal.

Run all tests concurrently where applicable:

1. **External-ID uniqueness:** submit the same `(source_system, external_id)` 20 times from two agents. Pass = exactly one SourceAlias exists and every losing write returns a deterministic duplicate/no-op result. Flagging or merging later is failure.
2. **Typed links:** attempt a dangling alias, a claim linked to the wrong entity type, and deletion of a referenced commitment. Pass = all invalid mutations are rejected before commit.
3. **Claim conflicts:** submit two contradictory values for the same `(entity, field)` with separate source/evidence. Pass = both claims remain immutable and a Conflict record is created; neither overwrites the other.
4. **Lease race:** have both agents acquire the same expired lease simultaneously. Pass = exactly one acquisition succeeds. Only the owner can heartbeat; after expiry, exactly one contender can reclaim it.
5. **Authority:** have the read-only agent and an expired grant attempt a consequential transition. Pass = the write is rejected, not merely highlighted. The exact target/scope must match the live grant.
6. **Receipt-gated closure:** try to mark Done with no receipt, a receipt for another action, an unverified-effect receipt, and a valid receipt. Pass = only the valid case commits atomically; receipt update/delete is rejected.
7. **Event/API behavior:** every accepted mutation produces one durable event; retried identical requests produce no duplicate effect; a consumer can resume from a cursor after interruption.
8. **Mobile:** on iPhone, find an exception, inspect provenance/conflict, approve only an internal synthetic action, and verify closure/readback without opening a developer console.
9. **Cross-agent least privilege:** each agent can access only its permitted operations, and its identity is visible in durable receipts—not just in a transient UI history.

**Binary result:** any requirement that needs a script, external service, SQL policy/function, Worker, or custom app falsifies the no-code hypothesis. On official documented capabilities, Airtable and Notion fail items 1, 4, and 6 as hard invariants; Supabase and D1 fail the zero-code/mobile boundary because their enforcement and operator surfaces must be built.

### Gate 1: recommended Supabase truth-engine pilot, only if bounded code is accepted

Use one isolated Supabase branch/project, synthetic data, separate agent users/roles, and a migration committed to private version control. Do not connect Basecamp, Gmail, financial systems, customer data, or any production source.

The pilot passes only if:

- a composite unique key prevents every duplicate SourceAlias;
- foreign keys reject every dangling/wrong relation;
- Claim and Receipt rows are append-only to ordinary agents;
- one RPC transaction atomically acquires/heartbeats/reclaims leases using database time;
- RLS and column grants deny every unauthorized direct table write;
- the only closure RPC requires an exact AuthorityGrant plus a valid Receipt/readback and writes Commitment + Event atomically;
- two agent clients running at least 100 randomized concurrent operations produce zero duplicate identities, zero dual active leases, zero lost claims, zero unauthorized effects, and zero receipt-less closures;
- retrying the same idempotency key 20 times yields one effect and one canonical receipt;
- database webhook/realtime consumers can restart and reconcile from durable Event rows without treating delivery as the source of truth;
- an authenticated phone-sized operator surface completes the mobile scenario above without exposing a service/secret key;
- export/rebuild into a fresh branch reproduces all canonical rows, relations, and receipt hashes.

Immediate fail conditions include any policy bypass through the generated Data API, use of `service_role`/secret keys in a client, a direct status update that bypasses the closure RPC, more than one lease winner, destructive last-write-wins conflict handling, or a mobile workflow that exists only in the developer dashboard.

## Final decision

The honest choice is not “which no-code database can secretly do database transactions and policy?” None can. The choice is:

- **Source-native authority + optional non-authoritative Airtable projection** when no custom truth layer is allowed; or
- **Supabase canonical truth layer + optional Airtable projection** when strict enforcement is worth a small maintained codebase.

In both cases, Linear remains the thin execution projection. For Mitch's requested canonical operational graph—where claims, authority, leases, readback, and receipts are the point rather than decoration—the second is the only recommendation that can pass a real concurrency and authority gauntlet without building almost the entire platform from scratch.

## Evidence boundary: documented facts versus inference

**KNOW — directly documented by the vendors:** the internal/native identifier behaviors, relation and foreign-key facilities, edit-permission/RLS primitives, API and webhook shapes, automation limits, mobile product surfaces, MCP authentication posture, Supabase Queue visibility semantics, and Cloudflare Queue acknowledgement behavior cited above.

**INFER — architectural conclusions drawn from those documents:**

- “No vendor-documented insert-time uniqueness or conditional-write primitive” means Airtable/Notion cannot be trusted to reject the adversarial races in this test without another writer/lock layer. This is an inference from the documented write models and limits, not a vendor statement that uses the phrase “not canonical.”
- Supabase is the *shortest path* and D1 entails *more application work* are comparative engineering judgments. The documented primitives support them, but only a measured implementation pilot can establish Mitch's actual time, cost, and maintenance burden.
- Airtable is the best optional operator projection is a product-fit recommendation based on its documented mobile Interfaces, permissions, automations, API/webhooks, and MCP—not a proven result from Mitch's account or iPhone.

**UNKNOWN until the isolated pilot runs:** deployed policy correctness, real concurrent behavior of the exact schema/RPCs, mobile usability for Mitch's workflow, webhook latency/recovery under his load, integration-specific readback, operational maintenance burden, and account-plan entitlements. No official document can promote those outcomes to verified production facts.
