Class CausalPast
Both are the same object — a frontier of (channel, position) pairs — used from
two sides of one comparison: coverageOf(CausalPast) answers whether the past
recorded against served data accounts for everything a client's token names. A write tier
stamps a validated token onto produced messages as causes; a read tier refuses to serve
data whose recorded past does not cover the token, and refreshes the token by merging in
what it served. That buys session consistency — read-your-writes, monotonic reads,
writes-follow-reads — for participants outside the delivery protocol (issue #96).
The wire form is the frozen causes grammar itself (CausesCodec), so
decode(byte[]) is exactly as strict as the engine's own header decode: a token
that is truncated, miscounted, padded or out of canonical order is refused, never
salvaged. A salvaging token parser is the same hazard as a salvaging codec — a weaker
frontier read from damaged bytes silently weakens the session guarantee.
Coverage deliberately inverts the delivery gate's disposition towards unknown
channels. Deliverability.decide(Causes, Set, Deliverability.SettledView) skips a cause on a channel outside the received
set, because a gate that waited for what it will never see would wait forever. A read
tier is not a gate: a channel its recorded past cannot verify must mean do not
serve, not serve anyway. Every channel a token names is therefore checked, and a
channel the past has never recorded is reported as a gap.
Instances are immutable; merge(ChannelId, long) and merge(CausalPast)
return new pasts. The engine never reads this type: it is a companion over the public
surface, not part of the delivery protocol, and holding one grants no delivery guarantee.
- See Also:
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic final recordThe outcome of one coverage check. -
Method Summary
Modifier and TypeMethodDescriptioncauses()Returns the frontier this past carries.coverageOf(CausalPast token) Decides whether this past covers a token: whether everything the token names is at or below what this past records.static CausalPastdecode(byte[] encoded) Decodes a past from the frozen wire grammar, exactly as strictly as the engine decodes aparsley.causesheader.byte[]encode()Encodes this past in the frozen wire grammar.booleaninthashCode()Returns a hash consistent withequals(Object).booleanisEmpty()Returnstruewhen this past names no channel.Merges one observed coordinate: the delivered message's own(channel, position)at a projector's seam, or the coordinate a produce acknowledgement confirmed at a write tier.merge(CausalPast other) Merges another past pointwise: per channel, the greater position wins.static CausalPastnone()The empty past: a session that has observed nothing.static CausalPastBuilds a past over an existing frontier.intsize()Returns how many channels this past names.toString()Returns the past rendered for diagnostics.
-
Method Details
-
none
The empty past: a session that has observed nothing.- Returns:
- a past naming no channel
-
of
Builds a past over an existing frontier.- Parameters:
causes- the frontier to carry- Returns:
- the past
- Throws:
IllegalArgumentException- ifcausesis null
-
decode
Decodes a past from the frozen wire grammar, exactly as strictly as the engine decodes aparsley.causesheader.- Parameters:
encoded- the encoded past, asencode()produced it or as read from a record'sCausesCodec.HEADER_KEYheader- Returns:
- the past
- Throws:
CausesCodec.UndecodableMetadataException- if the bytes cannot be trusted, for any of the reasonsCausesCodec.decode(byte[])names; a token that cannot be decoded must be treated as no token, never as a partial one
-
encode
public byte[] encode()Encodes this past in the frozen wire grammar.The bytes are canonical — one past, one spelling — and are valid as a
parsley.causesheader value, which is what lets a write tier stamp a validated token straight onto a produced record.- Returns:
- the encoded past
-
causes
Returns the frontier this past carries.- Returns:
- the frontier this past carries
-
isEmpty
public boolean isEmpty()Returnstruewhen this past names no channel.- Returns:
truewhen this past names no channel
-
size
public int size()Returns how many channels this past names.Bound this, and the
encodedwidth, before trusting an inbound token: a token is untrusted input even when this application minted it.- Returns:
- how many channels this past names
-
merge
Merges one observed coordinate: the delivered message's own(channel, position)at a projector's seam, or the coordinate a produce acknowledgement confirmed at a write tier.- Parameters:
channel- the channel observedposition- the position observed on it- Returns:
- a past carrying the greater of
positionand any position already named forchannel; this instance is unchanged, and is returned itself when it already covers the coordinate - Throws:
IllegalArgumentException- ifchannelis null orpositionis negative or the reserved maximum no channel assigns
-
merge
Merges another past pointwise: per channel, the greater position wins. This is how a read tier folds the served data's recorded past into the client's token before re-minting it.- Parameters:
other- the past to merge in- Returns:
- a past covering both; this instance is unchanged, and when either side already covers the other — the steady state of a session re-reading settled data — that side is returned itself, so an unchanged token need not be re-encoded
- Throws:
IllegalArgumentException- ifotheris null
-
coverageOf
Decides whether this past covers a token: whether everything the token names is at or below what this past records.The check reuses the core's decision (
Deliverability.decide(Causes, Set, Deliverability.SettledView)) with the token's own channel set as the received set, so no channel is skippable: a channel this past has never recorded fails the check with an empty recorded position, where the delivery gate would have skipped it. Serving on an unverifiable channel is exactly the read-your-writes violation this type exists to prevent, so the error here is always in the conservative direction — a refusal to serve, never a stale serve.- Parameters:
token- the past that must be accounted for, typically a client's session token- Returns:
- the verdict, naming every gap when this past falls short
- Throws:
IllegalArgumentException- iftokenis null
-
equals
-
hashCode
public int hashCode()Returns a hash consistent withequals(Object).- Overrides:
hashCodein classObject- Returns:
- a hash consistent with
equals(Object)
-
toString
-