> **See also:** [ROADMAP.md](../ROADMAP.md)

## v1.7.0 — Decoupled Compute

> **Release Theme**
> Move delta computation and change capture out of the PostgreSQL backend
> process, so that a deployment which has genuinely outgrown one machine's CPU
> can add compute without changing its SQL.
>
> This was originally planned for v0.82.0–v0.83.0 (pre-resequencing) and has
> been moved past 1.0 deliberately. Pre-1.0 effort is better spent making a
> single PostgreSQL instance go surprisingly far (v0.88.0–v0.89.0) and making
> the product trustworthy (v0.82.0–v0.87.0, v0.90.0–v0.98.x) than on a second
> process most users will never deploy. Everything here remains **strictly
> optional**: a deployment without external processes continues to work exactly
> as it does today.

### External worker

| Item | Description | Ref |
|------|-------------|-----|
| DC-1 | **`pg_trickle_worker` binary.** A standalone Rust binary in `crates/worker/` that connects via `tokio-postgres`, reads stream table metadata from the catalog, reads change buffers via `COPY ... TO STDOUT (FORMAT binary)`, computes delta SQL with the extracted DVM engine, applies the MERGE, advances the frontier and records refresh history. Stateless — all state stays in PostgreSQL. Ships as a single static binary. | MT-1 |
| DC-2 | **Coordination protocol.** The in-process scheduler becomes a coordinator: it inserts jobs into `pgtrickle.pgt_worker_jobs`; workers claim them with `pg_try_advisory_xact_lock(pgt_id)` and heartbeat every 5s; the coordinator reclaims jobs whose heartbeat is older than 30s; unclaimed or expired jobs fall back to in-process execution. New catalog table `pgtrickle.pgt_worker_registry` (`worker_id`, `hostname`, `pid`, `started_at`, `last_heartbeat`, `status`, `capabilities`). | MT-2 |
| DC-3 | **Failover and fallback parity.** Every code path proven identical between in-process and external execution: same delta SQL, same MERGE, same reason codes, same freshness accounting. A property test runs the same workload both ways and asserts identical results. | — |

### External change capture

| Item | Description | Ref |
|------|-------------|-----|
| DC-4 | **`pg_trickle_cdc` binary.** A standalone consumer in `crates/cdc-consumer/` that subscribes to logical replication using the `pgoutput` protocol, decodes WAL events and writes change buffers in the same schema as trigger-based capture. Zero work on the application's write path. Tracks the consumed LSN through replication feedback. Deployment modes: sidecar (same host) and remote (`COPY ... FROM STDIN (FORMAT binary)`). | MT-4 |
| DC-5 | **`pg_trickle.cdc_mode = 'external'`.** When set, the extension creates no triggers and no slots of its own, expects the external consumer to populate change buffers, and monitors buffer freshness — alerting through `health_check()` if the consumer falls behind. | MT-4 |
| DC-6 | **Zero-copy same-host transfer.** For a sidecar worker on the same host, move change buffer pages over shared memory and a UNIX domain socket instead of the PostgreSQL protocol. | LT-10 |
| DC-7 | **Shared-memory change buffer ring for hot sources.** Deferred from the v0.87.0 low-impact-refresh work (LOW-3). It must be respecified as multi-producer — a source above 10K writes/s is written by many concurrent backends, so the original single-producer/single-consumer lock-free design does not apply — and it needs a crash story that works for trigger-based capture, which has no WAL position to rebuild from. It belongs here because it is a write-path decoupling problem, and it stays opt-in. | LOW-3 |
| DC-8 | **Parallel delta computation fan-out.** Deferred from the v0.88.0 engine work (PERF-O4). The original design proposed spawning parallel SPI connections per source branch, which SPI cannot do: it runs inside the calling backend's transaction and is not thread-safe. A real implementation uses background workers or `dblink`-style connections, which is exactly the machinery DC-1/DC-2 introduce. | PERF-O4 |

**Exit criteria:**
- [ ] External worker computes and applies deltas with results identical to
      in-process execution across the full E2E suite
- [ ] Worker crash mid-refresh is reclaimed and completed with no lost or
      duplicated changes
- [ ] `cdc_mode = 'external'` removes all trigger overhead, measured against the
      v0.87.0 write-path benchmark
- [ ] Deployments with no external processes are byte-for-byte unaffected
