# Delta re-read: `endpoint digest --json` @ `0324c37` (W4b acceptance)

**Reader:** perri · branch `build/teardown-authority-w4b`, PR #41 · delta sections only.

## Verdict on the four inferences: all four RESOLVED — I would infer none of them now.

| # | Was inferred | Now |
|---|---|---|
| 1 | `--follow` delta shape | **Documented.** `{version, from, turns}`, one object per line, apply = truncate-to-`from` then append, `from == 0` = full replace. I can build this. |
| 2 | `--last` absent | **Documented** in the flags table, incl. `--last 1` = the turn-end view. |
| 3 | `version` lifetime | **Documented, and better than I asked for** — process-lifetime, resets on daemon restart, *"compare with `!=`, never `>`"*. That is precisely the silent stall I predicted, named and closed. |
| 4 | `seq` freeze on partial turns | **Documented and reframed better than my model.** "Open turns re-deliver, by design" + *"the cursor is not stuck, it is correctly refusing to skip content that has no committed position yet"* corrects my framing: I called it a livelock; it is intended re-delivery. |

Two lines earn specific credit because they pre-empt bugs I would otherwise have shipped:

- *"Only the follow stream is line-delimited"* — the snapshot is pretty-printed across many lines, so
  an NDJSON reader built for `--follow` silently fails on a snapshot. I would have written one reader
  for both. This sentence is the difference between working and a parse error at 3am.
- The `!=`-not-`>` rule. My existing comparator would have been `>`.

## Yes — I now reach for a DIFFERENT architecture

Before: snapshot polling on a timer, `--after` cursor, `--follow` unusable. Now: **`--follow --json`
as the primary path** for my interrupt-watch (it is a latency-sensitive watchdog — deltas beat a 15s
poll), **with a slow snapshot poll retained purely as a liveness backstop** — see residual B. I would
also drop my hand-rolled `--last 12` window scan in favour of the documented `--last` + a `version !=`
gate, and adopt `after_predates_window` on the snapshot path (I have no missed-rows signal today).

## Three NEW residuals, surfaced by the new text

**A. `!=` has a collision hole on daemon restart — the one I would fix before v0.39.0.**
`version` is process-lifetime and resets on restart. If I last saw `version: 5`, the daemon restarts,
and by my next poll the fresh run has bumped back to `5`, then `!=` reports *unchanged* and I skip a
pull whose content is entirely different. `>` fails loudly (stall); `!=` fails **silently** (skipped
content), which is the worse failure and exactly the class that cost me a 37-minute inbound black
hole in v0.25.2. The rule is right, but it needs a companion: expose a **daemon run id / boot id**
alongside `version`, and let consumers compare `(run_id, version)`. Without it the correct comparator
is unwritable — no amount of reader discipline closes a counter collision. (Narrow window, real.)

**B. "There are no heartbeats" means a `--follow` consumer cannot distinguish idle from dead.**
Stated as a property of the stream; its consequence for the consumer is not. A silent stream is
indistinguishable from a crashed daemon, a broken pipe, or a wedged endpoint — and for a *watchdog*
(the thing that notices an agent went quiet) that is the precise failure that matters: my watcher
would sit happily on a dead pipe concluding "nothing to heal". Either document a reconnect/liveness
expectation ("re-open the stream if silent for N", or "EOF is the only liveness signal") or say
plainly that follow consumers must run an independent liveness timer. I inferred the latter and kept
a backstop poll; another reader will not.

**C. "De-duplicate on your side" — on what key?** Partial-turn entries carry no `seq`, and `ts` is
optional on `Agent`/`ToolSprint`. So the only key available is positional-plus-content (turn index,
entry index, hash of `text`/`tools`), which is fragile if a partial turn's earlier entries can be
revised rather than only appended. One sentence — "entries in a partial turn are append-only; key on
(turn index, entry index)" — makes the advice actionable. Right now the page tells me to de-dupe and
leaves me to invent the identity.

## Minor / unresolved-but-cheap

- **Flag interaction unspecified:** `--last N --follow` — legal? The table says `--last` "applies to
  the snapshot pull", which hints no, but does not say. Same for `--after` + `--follow` (I read the
  no-`after_predates_window` note as implying `--after` is snapshot-only).
- **Follow resume after a drop:** not stated. I infer a reconnect yields a fresh base update
  (`from == 0`), which combined with the version-reset rule self-heals — derivable, not written.
- `from` is a **window** index; if a consumer retains more history than the server window, truncate-
  to-`from` is only correct because a slide forces `from == 0`. That reasoning is implicit.

## Bottom line

The gate's four criteria are met — nothing on my original list still requires inference, and the
`--follow` section is complete enough to implement against cold. **A is the one I would not ship
without**: it is a silent-skip hole in the very rule this revision added.

---

## Addendum — todlando's source answers (2026-07-20), and what they change for claude-spt

**`seq` IS restart-stable** (`digest.rs:288-292`: `(ledger_ordinal << 32) | per-session line index`;
the ordinal is the persisted, prune-stable ledger ordinal, the line index is on-disk transcript
position). The digest is projected on demand from disk records — nothing in `seq` derives from
process state. **`version` is the only process-lifetime number on this contract.** So the
`(version, max agent-produced seq)` tiebreak works, with the periodic unconditional pull as the belt.

**Entry mutation semantics (residual C, grounded):** entry POSITIONS are append-only — entries are
pushed, never reordered or removed — but **the LAST entry mutates in place**: a growing `ToolSprint`
pushes into `tools` and overwrites its own `seq`/`ts`. So the dedupe key is **(turn index, entry
index)** with the trailing entry treated as **replace-in-place**. A content hash would report a
growing sprint as brand-new on every tool call — the exact fragility flagged in C.

### Consequences for our adapter (act on these when the `--follow` migration lands)

1. **Dedupe key is positional, not content.** Any delta consumer must replace-in-place on the
   trailing entry. A naive append would double-count a growing sprint as repeated agent activity.
2. **The tiebreak is BLIND during an open turn.** Partial-turn entries carry no `seq`, so `max_seq`
   cannot advance while a turn is open. If a `version` collision lands in exactly that window, BOTH
   halves of the pair match while content differs. Narrow, but it is the intersection of residual A
   and the open-turn rule — and it is precisely why part (1), the periodic unconditional pull, is
   the belt and not decoration. Reported to todlando so the page does not oversell the pair.
3. `interrupt_watch.rs`'s current heal logic is unaffected — it keys on agent-produced kinds on the
   latest turn, and mutate-in-place only ever reflects real agent tool use.
