Visitar URL original
refactor: promote transaction tolerance semantics to booking as the canonical by robcohen · Pull Request #1735 · rustledger/rustledger · GitHub
Skip to content

refactor: promote transaction tolerance semantics to booking as the canonical - #1735

Merged
robcohen merged 4 commits into
mainfrom
refactor/tolerance-single-source
Jul 10, 2026
Merged

robcohen merged 4 commits into
mainfrom
refactor/tolerance-single-source

Conversation

@robcohen

@robcohen robcohen commented Jul 9, 2026

Copy link
Copy Markdown
Member

What

Promotes the pipeline's transaction balance-tolerance semantics into rustledger-booking as the canonical, option-parameterized implementation, and defuses the decoy that shadowed it.

Why

Phase-1 correctness sweep, tolerance family. The repo had two functions with near-identical names and opposite standing:

  • rustledger_booking::calculate_tolerance — exported, documented, zero production callers. Uses each amount's fixed inferred_tolerance() and ignores every ledger option (tolerance_multiplier, infer_tolerance_from_cost, inferred_tolerance_default).
  • rustledger_validate::validators::transaction::calculate_tolerances — the real thing (quantum × multiplier per posting, cost/price-inferred accumulation, per-currency floors with "*" wildcard), buried in a private module and unreachable from outside the validator.

Any new consumer (embedder, report, plugin) reaching for "the tolerance function" would find the decoy and silently diverge from rledger check. This is the same drift category as #1648/#1726: a canonical that isn't where consumers look.

How

  • Move, not rewrite: the validator's calculate_tolerances + decimal_quantum bodies move verbatim to rustledger-booking as transaction_tolerances(txn, &ToleranceOptions); ToleranceOptions mirrors the three ledger knobs so the semantics are consumable without a ValidationOptions dependency.
  • Validator delegates: its calculate_tolerances(txn, &ValidationOptions) keeps its signature and becomes a thin wrapper over the canonical — behavior-identical.
  • Decoy defused: calculate_tolerance and is_balanced are re-documented as low-level amount-level primitives that are not the pipeline's balancing semantics, with pointers to transaction_tolerances (kept un-deprecated: booking's own tests/proptests use them legitimately as primitives).

Testing

  • Existing validator tolerance suite (base quantum max, cost-inferred, price-inferred, per-currency floor, wildcard default) now exercises the delegation end-to-end — all green, pinning behavior-identity.
  • cargo test -p rustledger-booking -p rustledger-validate, clippy --all-features --all-targets -D warnings, cargo fmt --check, and RUSTDOCFLAGS="-D warnings" cargo doc all pass.

🤖 Generated with Claude Code

…anonical

The validator's calculate_tolerances (quantum x multiplier per posting,
cost/price-inferred accumulation, per-currency default floors) was the
only real implementation of the pipeline's balance-tolerance semantics,
yet it lived buried in a private validators module while
rustledger-booking exported calculate_tolerance — a look-alike primitive
with zero production callers that ignores every ledger option. Any new
consumer reaching for "the tolerance function" would find the decoy.

Move the semantics verbatim into rustledger-booking as
transaction_tolerances(txn, &ToleranceOptions), with ToleranceOptions
mirroring the three ledger knobs (tolerance_multiplier,
infer_tolerance_from_cost, inferred_tolerance_default incl. the "*"
wildcard). decimal_quantum moves with it. The validator's
calculate_tolerances becomes a thin wrapper wiring ValidationOptions
into the canonical, so its behavior and public surface are unchanged.

Re-document booking's calculate_tolerance and is_balanced as low-level
amount-level primitives that are NOT the pipeline's balancing semantics,
pointing at transaction_tolerances — so the decoy can no longer be
picked by mistake.

Behavior-identical: the existing validator tolerance suite (base
quantum, cost-inferred, price-inferred, per-currency floor, wildcard)
now exercises the delegation end-to-end and stays green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@robcohen
robcohen requested a review from a team as a code owner July 9, 2026 17:41
Copilot AI review requested due to automatic review settings July 9, 2026 17:41

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Promotes the validator’s transaction balance-tolerance logic into rustledger-booking as a canonical, option-parameterized implementation so all consumers (validator, LSP, embedders, plugins) can share identical tolerance semantics.

Changes:

  • Added ToleranceOptions plus canonical transaction_tolerances() (and moved decimal_quantum()) into rustledger-booking.
  • Refactored rustledger-validate’s calculate_tolerances() to delegate to rustledger_booking::transaction_tolerances() using ValidationOptions.
  • Updated validator tolerance tests to exercise the delegation path (and call the moved decimal_quantum()).

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
crates/rustledger-validate/src/validators/transaction.rs Replaces inlined tolerance logic with a thin wrapper delegating to booking’s canonical implementation; adjusts tests accordingly.
crates/rustledger-booking/src/lib.rs Introduces canonical transaction tolerance computation with option knobs; re-documents existing low-level tolerance primitives.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread crates/rustledger-booking/src/lib.rs Resolved
@github-actions

github-actions Bot commented Jul 9, 2026 •

Copy link
Copy Markdown
Contributor

📊 Benchmark Results

Tool Time Memory
rustledger 32.5ms ± 0.7ms 23.5 MB
beancount 899.9ms ± 11.3ms 50.7 MB
Comparison 27.7x faster 2.2x less

vs main branch (2026-07-10)

Metric main this PR Change
Time 33.7ms 32.5ms -3.6% ✅
10K transactions · 5 runs, 2 warmup · hyperfine
What do these numbers mean?
  • Time: Wall-clock time to parse and validate the ledger (± std dev)
  • Memory: Peak resident set size (RSS)
  • vs main: Compared to latest nightly benchmark on main branch

@github-actions

github-actions Bot commented Jul 9, 2026 •

Copy link
Copy Markdown
Contributor

✅ Compatibility Test Results

Metric Result
Check Compatibility 100%
BQL Compatibility 100%
Full AST Match 100%
Total Files 811
What's tested
  • Check: Exit codes and error counts match bean-check
  • BQL: Query results match bean-query
  • Files: ~800 test files downloaded from 10+ beancount repositories

Full results available in workflow artifacts

robcohen and others added 3 commits July 10, 2026 02:30
The doc (inherited verbatim from the validator) claimed the
per-posting maximum; the implementation has always summed
contributions per cost currency and then max'd against the base
quantum tolerance. Describe what the code does.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…eview)

The wildcard applies only to currencies appearing as posting UNIT
currencies; a currency present only via cost/price inference gets no
wildcard floor (a named per-currency default still reaches it).
Behavior inherited verbatim from the validator — the doc claimed
"all currencies".

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@codecov

codecov Bot commented Jul 10, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.77419% with 3 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
crates/rustledger-booking/src/lib.rs 96.20% 3 Missing ⚠️

📢 Thoughts on this report? Let us know!

@robcohen
robcohen merged commit 076b026 into main Jul 10, 2026
52 of 53 checks passed
@robcohen
robcohen deleted the refactor/tolerance-single-source branch July 10, 2026 09:13
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.

2 participants