# ADR-0004 — C1 scope: lib-owned checkpoint mode only

**Status:** Accepted (user deferral, 2026-07-21) · **Supersedes:** the C1 design's sink-owned /
start-position scope (design § Scope item 7)

## September 21, 2026 implementation-currency amendment

The July 21 C1 scope below is historical. Its sink-owned checkpoint and explicit-start deferrals were discharged by the 1.2.0 changes recorded in [CHANGELOG](../../CHANGELOG.md#120---2026-08-23). OBSERVED through `nl -ba` and `rg -n` source reads: `AssemblerServer.init` handles `:sink_owned` by reading `sink.checkpoint/0`; `Pipeline.resolve_start_position/2` accepts a retained checkpoint, explicit `Position`, or `:current`, and the connection/assembler receive the selected position. These source facts supersede the old present-tense refusal and "only run-path wiring is owed" statements. Sink-owned effect-once still requires the consumer's atomic data-plus-position write and its own real acceptance; no fresh runtime or registry proof was run for this amendment.

## Context

The C1 streaming-spine design scoped **two** checkpoint modes — sink-owned (the sink persists the
position atomically with its own data write, read back through `c:Capstan.Sink.checkpoint/0`) and
lib-owned (the position persisted by a `Capstan.CheckpointStore`) — and three start positions
(`:checkpoint`, an explicit `%Capstan.Position{}` override, and `:current`). During C1
implementation the `AssemblerServer` was wired for lib-owned mode only, and the spine threads a
start position to the `Connection`'s dump while seeding the assembler's watermark from the
checkpoint store alone. Honoring a sink-owned atomic write path and an explicit start-position
override end-to-end is a C1-completeness follow-up; shipping them half-wired would resume the
dump from an override while the watermark started empty — a silent checkpoint hole.

The user deferred the sink-owned path and explicit start positions for C1 rather than ship them
partially wired.

## Decision

**C1 ships lib-owned checkpoint mode and resume-from-durable-checkpoint
(`start_position: :checkpoint`, the default) ONLY.** Everything else in the design's checkpoint /
start-position scope is deferred and **refused fail-closed today**, not silently ignored:

| Deferred capability | Refusal reason (value-free atom) |
|---|---|
| Sink-owned checkpoint mode (no `:checkpoint_store`) | `:sink_owned_mode_unsupported` |
| Explicit `%Capstan.Position{}` start override | `:start_position_override_unsupported` |
| `start_position: :current` | `:start_position_current_unsupported` |

The `Capstan.Sink` behaviour still declares `checkpoint/0`, and `Capstan.Pipeline` still validates
per-mode callback required-ness (including the sink-owned requirement of `checkpoint/0`) — the
contract surface exists and is validated. What C1 does not do is **run** a sink-owned pipeline:
`Capstan.start_link/1` refuses it before any child starts. `start_position: :checkpoint` resumes a
populated store from its persisted watermark and starts a fresh store from the server's currently
available log.

This SUPERSEDES the design's sink-owned / start-position scope for C1. The deferred work is
tracked in `docs/ROADMAP.md`.

## Consequences

- A sink-owned or explicit-start-position configuration is refused honestly with a distinct
  value-free reason, rather than crashing deep in `AssemblerServer` init or — worse — running with
  a watermark that silently disagrees with the dump's resume position (the checkpoint hole).
- The strongest guarantee the taxonomy offers — effect-once on the sink-owned atomic path — is
  **not** available in C1; lib-owned mode is at-least-once with a bounded duplicate window across a
  kill/restart. Consumers needing atomic effect-once wait for the deferred sink-owned row.
- No partially-wired path ships, so no silent-loss surface is created by the deferral.

## Evidence

`lib/capstan.ex:31-60` (moduledoc scope), `:103-136` (the three fail-closed refusals) ·
`lib/capstan/pipeline.ex:24-27,110-117` (per-mode validation retained; override/`:current`
refused) · `lib/capstan/sink.ex:9-27` (behaviour declares `checkpoint/0`; required-ness is a
per-mode config concern) · `lib/capstan/error.ex:28-30` (the three atoms in the error catalog).
