Skip to content

docs(replicate): seq is an interval index, not a frame counter - #11

Merged
brayniac merged 1 commit into
mainfrom
docs/seq-is-an-interval-index
Sep 18, 2026
Merged

brayniac merged 1 commit into
mainfrom
docs/seq-is-an-interval-index

Conversation

@brayniac

Copy link
Copy Markdown
Contributor

The doc said Frame::Rows.seq "counts from zero per source per connection". The
code needs less than that:

let gap = match st.last_seq {
    Some(last) => seq > last.saturating_add(1),
    None => false,
};

last_seq starts None, so a first value is never compared, and the only check
is the step between consecutive frames. Nothing anywhere depends on the starting
value.

Why the over-promise had a cost

A consumer's publisher sends the subscription's interval index — the
observation's timestamp divided by the interval the subscriber asked for. It
satisfies the gap check identically and carries strictly more information, and
it read as non-conforming against the letter of the doc.

They're right, and the doc was mandating the weaker option. A frame counter
increments by one whether or not an interval was skipped, so a skipped interval
arrives as a contiguous sequence with an undetectable hole in the middle.
Rule 6 says a gap means a lost reading; with a counter it can only mean a lost
frame in transit. An interval index makes rule 6 mean what it says.

One thing added beyond the report

Derive the index from the row timestamp, not the wall clock. FORMAT.md §5
anchors ts to a monotonic clock precisely so it survives a wall-clock step; an
index taken from the wall clock inherits the step and can go backwards.

That matters more than it looks, because a backwards value is not reported
today
. The check is seq > last + 1, so a repeat or a regression reads as "no
gap", is applied silently, and regresses last_seq. With a frame counter from a
well-behaved publisher that cannot arise; once the contract admits a
clock-derived index, it can. The docs now name that gap rather than leaving it
implicit.

Whether the subscriber should detect a non-increasing seq is a separate
question and a behaviour change, so it is not in this PR.

Scope

Docs only — frame.rs, mod.rs rule 6, WIRE.md §4.3, CHANGELOG. No code
change, and a publisher that counts from zero still conforms.

🤖 Generated with Claude Code

The doc said `Frame::Rows.seq` "counts from zero per source per connection".
The code needs less: `last_seq` starts None, so a first value is never
compared, and the only check is `seq > last + 1`. Nothing anywhere depends on
the starting value.

That over-promise had a cost. A consumer's publisher sends the subscription's
interval index -- the observation's timestamp divided by the interval the
subscriber asked for -- which satisfies the gap check identically and carries
strictly more information, and it read as non-conforming against the letter of
the doc.

They are right, and the weaker option was the one being mandated. A frame
counter increments by one whether or not an interval was skipped, so a skipped
interval arrives as a contiguous sequence with a hole in the middle that
nothing can detect. Rule 6 says a gap means a lost reading; with a counter it
can only mean a lost frame in transit. An interval index makes rule 6 mean what
it says.

Adds one thing the report did not raise: derive the index from the row
timestamp, not the wall clock. FORMAT.md 5 anchors `ts` to a monotonic clock
precisely so it survives a wall-clock step, and an index taken from the wall
clock inherits the step and can go backwards. A backwards value is not reported
today -- the check is `seq > last + 1`, so a repeat or a regression reads as
"no gap" and is applied silently. That gap in the subscriber is now named in
the docs rather than left implicit; whether to detect it is a separate question.

No code change. A publisher that counts from zero still conforms.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@brayniac
brayniac merged commit 8c0a7bf into main Sep 18, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant