docs(replicate): seq is an interval index, not a frame counter - #11
Merged
Merged
Conversation
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>
This was referenced Sep 18, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The doc said
Frame::Rows.seq"counts from zero per source per connection". Thecode needs less than that:
last_seqstartsNone, so a first value is never compared, and the only checkis 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§5anchors
tsto a monotonic clock precisely so it survives a wall-clock step; anindex 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 "nogap", is applied silently, and regresses
last_seq. With a frame counter from awell-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
seqis a separatequestion and a behaviour change, so it is not in this PR.
Scope
Docs only —
frame.rs,mod.rsrule 6,WIRE.md§4.3, CHANGELOG. No codechange, and a publisher that counts from zero still conforms.
🤖 Generated with Claude Code