Repository navigation
Description
Problem
InMemoryLedger::create_transfers (pkgs/id/src/currency_poc/ledger.rs:249-258) posts a linked chain that is never terminated. The trait documentation (ledger.rs, LedgerBackend::create_transfers) defines a chain as a contiguous run ending at a transfer with linked == false, but the chain-splitting loop
let mut chain_end = chain_start;
while batch[chain_end].linked && chain_end + 1 < batch.len() {
chain_end += 1;
}
let chain = &batch[chain_start..=chain_end];stops at the end of the batch even when the last leg still has linked == true, and the resulting "chain" is validated and committed like a properly terminated one. A real TigerBeetle submission leaves such a chain open (the linked flag promises a following leg), so scenario tests that pass against the in-memory reference backend can rely on behavior a production binding over the official client would reject — exactly the divergence this backend exists to prevent (mod.rs: "a production binding would implement the same trait"; tests.rs header: the same scenarios are to run against a real cluster).
Evidence (verified this run, laptop probe, main caacf3a)
Probe crate with verbatim copies of the currency_poc modules (md5 ledger.rs 3c2ccc964b2bcc0e29232fae8966c41d, matching main caacf3a), funded-ledger fixture copied from tests.rs:
- Single transfer id 700, amount 100,
linked: true, no terminator:results=[Ok(())],lookup_transfer(700)returns the transfer, user spendable rises to 10100 — the unterminated chain posted. - Two legs (ids 710/711, amounts 100/200), both
linked: true, no terminator:results=[Ok(()), Ok(())], both transfers stored. - Control: the same transfer with
linked: falseposts (expected) — the probe fixture is sane.
Why it matters
The in-memory backend is the reference semantics for the future TigerBeetle client binding and the only ledger the #2289 scenario tests run against today. Silently accepting an open linked chain lets malformed batches (e.g. a caller that builds legs and forgets to clear linked on the last leg, or a truncated batch) pass every PoC test while failing — or behaving differently — against a real cluster. The executor itself always terminates its batch (executor.rs sets linked: false on T3), so this is a backend-fidelity gap, not an executor bug.
Acceptance criteria
-
create_transfersrejects a batch whose final chain is unterminated (last leglinked == true): no leg of that chain posts, no balance moves, and the per-leg results report an error for every leg of the open chain (a dedicatedTransferErrorvariant if the existing codes cannot express it). - Properly terminated chains and single unlinked transfers behave exactly as before; all existing currency_poc tests pass unchanged.
- New tests: single unterminated transfer rejected; multi-leg unterminated chain rejected atomically; a terminated chain following an unterminated one in the same batch is handled per the documented per-chain result contract.
- The
LedgerBackend::create_transfersdoc comment states the unterminated-chain behavior so a future client binding implements the same rule.
Related: #2289 (the PoC this backend belongs to). Distinct from #4071 / #4069 (pkgs/id/src/currency.rs authorisation validation/fold, a different module).
Activity
dezren39 commentedon Nov 2, 2026
🤖 Agent note · filed
new-issue-creator-code-a)~/git/fleet/probe-2026-11-01-laneA-currencypoc/(laptop); queue packet enqueued this run (repo-health-code-pilot).7 remaining items
dezren39 commentedon Nov 2, 2026
🤖 Agent note · state: done
5b048028b:create_transfersatpkgs/id/src/currency_poc/ledger.rs:249-258stops chain scanning at end-of-batch and commits without requiring the last leg to havelinked=false. Fresh runtime probe was attempted but timed out waiting for a fleet build slot; the earlier filed laptop probe oncaacf3aerecords both the single- and two-leg unterminated batches posting, with the unlinked control passing. No implementation PR exists.repo-health:v1:fix:developing-today/code:issue:4121). Issue relabeledtask/small-fix,task/fix,queue/queued,status/ready.dezren39 commentedon Nov 2, 2026
Pickup — task 6332 claimed by lane code-k (repo-worker-code). Revalidated fresh: issue #4121 is OPEN, no hard-stop labels, no implementation PR or existing branch found. Working the unterminated linked-chain rejection in pkgs/id/src/currency_poc/ledger.rs on the laptop.
Merge pull request #4517 from developing-today/queue/6332-4121-reject…
dezren39 commentedon Nov 2, 2026
Done — task 6332 complete: PR #4517 merged (merge sha 0ea90ec) and issue #4121 closed by the merge.
InMemoryLedger::create_transfersnow rejects an unterminated final linked chain atomically (LinkedEventChainOpenon the final leg,LinkedEventFailedon earlier legs of the open chain; nothing stored, no balances move), documented onLedgerBackend::create_transfers. Targeted tests on the laptop under fleet-build-lock:cargo test --manifest-path pkgs/id/Cargo.toml --lib currency_poc— 20 passed, 0 failed, 1 ignored, including the 3 new regression tests. Codex review completed on the merged commit with no findings; CodeRabbit passed.