fix(core): bound Tx.count, agree a group's size, and evict a partial tx (C3) - #363
Merged
Conversation
…tx (C3) A rewritten `count` pinned atomic-transaction members in the receiver's buffer for the life of the replica, and `encode_state` handed them to the next one. The 1000-member cap ARCHITECTURE named is now a protocol constant enforced at the decode boundary, at the apply seam an in-process caller reaches without crossing it, and at the mint (an oversized group is emitted untagged). A bucket's size is what its members agree it is, so a rewritten first arrival no longer decides when the group commits. Everything a local judgement cannot separate — a member that never arrives, a bucket resolved at a size rewritten on every member, two envelopes of one op id — waits for `evict_partial_transactions`, which untags rather than discards so the ops still merge and no id is freed. Releasing a bucket that merely looks unreachable is arrival-order dependent and was rejected for it.
vieiralucas
force-pushed
the
core/c3-tx-count-bound
branch
from
July 28, 2026 00:29
8f0f1c8 to
a23329d
Compare
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.
Tx { id, count }tells a receiver to hold a group's members untilcountof them are present. Nothing boundedcountat the decode boundary and nothing ever gave up on a partial group, so a rewritten envelope pinned members in the buffer for the life of the replica — persisted byencode_state, and (since C6) counted among the ids the replica holds. Completeness was also read offbuffer[idxs[0]].tx.count, whichever member landed first. Hardening: nothing hangs or panics today.The cap is a protocol constant, enforced at both ends
MAX_TX_MEMBERSnow sits besideTx.0and anything past the cap — the members never enter the buffer, which is what persists.applyrefuses the same sizes for an op that reaches it without crossing the codec (in-process relay, SDK) — same answer at both seams, and refusing holds nothing.tag_atomicleaves an oversized group untagged rather than tagged with a size whose refusal takes the whole framed batch: otherwise an oversized transaction becomes dropped ops, not a non-atomic one.A group's size is what its members agree it is
tx_declared_countrequires unanimity across the bucket; a bucket without it names no group and is never complete. Read off one member, a rewrite chooses when the group commits.Eviction is the give-up path, not a repair rule
Document::evict_partial_transactions()untags every group still waiting and reports how many. A member that never arrives is indistinguishable from one still in flight, so how long to wait is the caller's policy — the core reads no clock.What two cold-review passes changed
m1(3), m2(3), m3(2)deliveredm1,m2,m3released all three, deliveredm1,m3,m2released two and heldm2against a bucket already given up on. One op set, two states — and stranding on 4 of 6 orders where the defect it replaced stranded on 2. Only a judgement on a member's own declared size is order-free.Rejected
TxId::deriveof its members: with unanimity the wrong-size commit is already gone, so it buys nothing state-observable while newly depending on no seam ever renumbering a seq under a live tag.Filed, not bundled
Gates
crates/core/tests/transaction.rs+16 cases (every shape reproduced first, a spliced snapshot for the presentation that never commits, a six-order sweep pinning nothing is released early);crates/core/tests/convergence.rsgains a malformed-count arm that fails at seed 0 against the bucket-wide rule, plus a rewritten-smaller arm.--no-fail-fast, measured: no codec bound 2 · no refusal atapply1 · count off the first member 4 · no mint cap 1 · eviction a no-op 10 · eviction discarding instead of untagging 11 · a committed member waved past the readiness gate 8. Unmutated tree 0.cargo test --workspacegreen,cargo fmt --allclean, Miri clean on the touched suites.Summary by cubic
Bound atomic transaction size to a 1000-member protocol constant, required unanimous group size across members, and added an eviction path to prevent unbounded buffering and order‑dependent commits. Docs now state the cap and the eviction policy. Addresses C3; follow-ups: C20 (policy to call eviction) and C21 (order-dependent commit of rewritten groups).
New Features
Document::evict_partial_transactions()to untag and apply all waiting groups; returns the number evicted. Leaves op IDs held; caller decides when to run it.Bug Fixes
MAX_TX_MEMBERS = 1000as a protocol constant. The codec refusescountof 0 or > cap;applyalso refuses out-of-range counts for in-process callers;tag_atomicemits oversized groups untagged so ops still merge.countacross members; mixed counts never complete and wait for eviction.Written for commit a23329d. Summary will update on new commits.