Skip to content

chore(deps)!: es-entity 0.20.0, job 0.18.5, obix 0.14.4; bon replaces derive_builder - #912

Merged
bodymindarts merged 2 commits into
mainfrom
task/cala-es-entity-020-01a163d3
Oct 22, 2026
Merged

bodymindarts merged 2 commits into
mainfrom
task/cala-es-entity-020-01a163d3

Conversation

@bodymindarts

@bodymindarts bodymindarts commented Oct 22, 2026 •

Copy link
Copy Markdown
Member

Summary

  • Bump es-entity 0.19.2 → 0.20.0, job 0.18.3 → 0.18.5, obix 0.14.3 → 0.14.4 together (they share es-entity types). errlanes follows es-entity. Both lockfiles regenerated by cargo; fuzz/Cargo.lock was stale on main (es-entity 0.17, cala 0.32.2-dev) and moves forward too.
  • The eight entities (Account, AccountSet, Entry, Journal, Transaction, TxTemplate, VelocityControl, VelocityLimit) hydrate via the generated X::hydrator() / build(events).
  • derive_builder is replaced by bon = "3" everywhere and removed from every manifest. cargo tree -i derive_builder matches nothing for cala-ledger, cala-ledger-core-types, cala-cel-interpreter, cala-perf, cala-ledger-example-rust and the fuzz crate. cala-ledger-core-types never used derive_builder and simply drops it.
  • Identifiers removed between es-entity 0.19.2 and 0.20.0 (errlanes Carrier/Absorb/AbsorbFailBy/Repr/kind/LaneRef, narrow*, fatal(..) lift cases, UninitializedFieldError): only UninitializedFieldError-style hydration was used in cala. job 0.18.5 kept JobSvcConfig's shape; obix 0.14.4's MailboxConfig::build() is infallible (outbox/publisher.rs drops .expect).

API changes (breaking)

Infallible build() (bon typestate — a missing required field is now a compile error):
NewAccount, NewAccountSet, NewJournal, NewTxTemplate, NewVelocityEnforcement, NewEntry, NewTransaction, AccountUpdate, AccountSetUpdate, JournalUpdate.

Fallible build() with a new error type (validation unchanged, now a #[bon] fallible constructor; messages no longer go through to_string()):

builder was now
NewTxTemplateEntry, NewTxTemplateTransaction, NewVelocityControl, NewVelocityLimit, NewPartitionKey, NewLimit, NewBalanceLimit XBuilderError (UninitializedField / ValidationError(String)) cel_interpreter::CelParseRejection
NewParamDefinition NewParamDefinitionBuilderError InvalidParamDefinition (Parse, Evaluation delegate to the CEL rejections; DefaultTypeMismatch { specified, source }, code CALA_PARAM_DEFAULT_TYPE_MISMATCH)
CalaLedgerConfig CalaLedgerConfigBuilderError InvalidCalaLedgerConfig (NoConnection, BothConnections; codes CALA_LEDGER_CONFIG_*)

Update types: AccountUpdate, AccountSetUpdate, JournalUpdate are now plain structs with #[derive(bon::Builder, Default)]; AccountUpdateValues, AccountSetUpdateValues, JournalUpdateValues are removed. X::default() + &mut setters + .build()? becomes X::builder().<setters>.build(). update() still takes impl Into<XUpdate>, and X::default() is still an empty update.

Setters: names, into conversion and Option setters taking T are kept; every optional member also gets maybe_x(Option<_>). Setters consume the builder (owned) instead of &mut self, so statement-style b.x(..); on a let mut builder no longer compiles. metadata(..) stays fallible (Result<Builder, serde_json::Error>) via a bon with closure. NewBalanceLimitBuilder::always_active() consumes the builder and is only callable while start is unset. NewTransaction.correlation_id defaults to id.to_string() via a bon default instead of the custom id setter. XBuilder type names still exist but are now generic over bon's typestate and have no Default; X::builder() is the only entry point.

Tests: the runtime fails_when_mandatory_fields_are_missing / fails_when_missing_required_fields unit tests (NewAccount, NewJournal, NewTransaction, NewTxTemplate, NewEntry) are removed because the case is now a compile error (agreed with Justin). New unit tests pin that invalid CEL, a mistyped param default, and a config with zero or two connection sources are still rejected. All other test edits are mechanical call-shape migrations.

Downstream call-site changes

From the lana-bank checkout (48b17701e5, worktrees and target/ excluded). Counts are X::builder() call sites / files.

Drop .expect(..) / .unwrap() / ? after build() (now infallible):

  • NewAccount — 18 sites / 12 files (e.g. core/accounting/src/chart_of_accounts/{chart_node/entity.rs,ledger/closing_balances.rs}, core/{alt-credit,exchange,fx,holding,payments}/src/**/ledger/mod.rs, tests in core/accounting, core/credit/collection, core/fx, core/exchange)
  • NewAccountSet — 18 / 12 (core/accounting/src/{balance_sheet,profit_and_loss,trial_balance,chart_of_accounts}/…, core/alt-credit/src/credit_facility_product/ledger/mod.rs, core/holding/src/ledger.rs, tests in core/{accounting,alt-credit,credit,deposit,exchange})
  • NewJournal — 9 / 9 (core/accounting/src/journal/service.rs, core/payments/src/ledger/mod.rs, test helpers in 7 crates)
  • NewTxTemplate — 26 / 26 (every template file under core/{accounting,alt-credit,exchange,fx,holding,payments}/src/**/templates* plus 5 test files)
  • AccountSetUpdate — 1 / 1: core/accounting/src/chart_of_accounts/ledger/mod.rs:113, let mut update_values = AccountSetUpdate::default(); update_values.metadata(..).expect(..) → AccountSetUpdate::builder().metadata(..).expect(..).build()

Error type changes (fallible build() stays; only matters where the error is named or converted): NewTxTemplateEntry 66/26, NewTxTemplateTransaction 27/27, NewParamDefinition 123/17, NewVelocityControl 6/6, NewVelocityLimit 9/6, NewLimit 9/6, NewBalanceLimit 9/6, CalaLedgerConfig 23/18. Non-test lana code uses .expect(..) on all of these; the ? sites are tests returning anyhow::Result, which accept the new errors unchanged. No lana file names any cala XBuilderError, XBuilder or *UpdateValues type, and no From/#[from] impl wraps them, so no error-enum changes are needed.

let mut builder patterns (2 sites, both NewTxTemplateEntry with an optional metadata): core/exchange/src/ledger/templates/settle_internal_bitcoin_purchase.rs:221 and core/holding/src/template.rs:173 → a single chain with .maybe_metadata(opt).

Unchanged for lana: .always_active() (9 sites, all inline in chains), .metadata(..) on New* builders (4 sites, still Result), JobSvcConfig, default_expr.

Test plan

Gate output is in the task report: cargo fmt, cargo clippy --workspace --all-targets --all-features -D warnings, nix flake check (fmt, clippy, audit, deny), nix run .#nextest (nextest + doctests + docs, local Postgres), fuzz crate cargo check --all-targets, and make check-event-schemas (no schema diff). No .sqlx changes (no query changes).

🤖 Generated with Claude Code


Note

Medium Risk
Wide breaking API change to every entity/template builder and a major es-entity bump; behavior should match prior validation but downstream crates must update call sites and error types.

Overview
Replaces derive_builder with bon across the workspace and bumps es-entity 0.20.0, job 0.18.5, and obix 0.14.4 (lockfiles updated, including fuzz). Entity hydration for accounts, journals, templates, etc. now uses X::hydrator() from es-entity 0.20 instead of per-entity derive_builder on EsEntity types.

Builder API shifts: many New* / update types use bon::Builder with compile-time required fields (infallible .build()); validated constructors (CalaLedgerConfig, NewParamDefinition, tx-template CEL pieces, velocity limits) return typed errors (InvalidCalaLedgerConfig, InvalidParamDefinition, CelParseRejection) instead of stringly derive_builder validation. Update DTOs are renamed/consolidated (e.g. AccountUpdate replaces AccountUpdateValues). Optional fields gain maybe_* setters; metadata uses bon with closures.

Tests, examples, and perf crates are migrated mechanically (drop .unwrap() on infallible builds, chain builders instead of let mut).

Reviewed by Cursor Bugbot for commit c6a36f2. Bugbot is set up for automated code reviews on this repo. Configure here.

es-entity 0.20 drops derive_builder and generates {Entity}Hydrator, so
the eight entities (Account, AccountSet, Entry, Journal, Transaction,
TxTemplate, VelocityControl, VelocityLimit) hydrate through
X::hydrator() / build(events). obix 0.14.4's MailboxConfig build() is
infallible. job and obix move with es-entity because they share its
types.

derive_builder is replaced by bon everywhere:

- New* and *Update types without validation derive bon::Builder;
  build() returns the value. A missing required field is now a
  compile error, so the runtime "fails when mandatory fields are
  missing" unit tests are gone (agreed with Justin).
- AccountUpdate, AccountSetUpdate and JournalUpdate are now the bon
  structs themselves; the *UpdateValues layer and the &mut Default
  builder pattern are gone (Justin chose bon over a hand-written
  &mut builder). The (values, fields) From impls fill fields
  directly.
- metadata setters stay fallible via bon `with` closures and return
  Result<Builder, serde_json::Error> as before.
- Validating builders become #[bon] fallible constructors with the
  same checks: CEL-expression builders (NewTxTemplateEntry,
  NewTxTemplateTransaction, NewVelocityControl, NewVelocityLimit,
  NewPartitionKey, NewLimit, NewBalanceLimit) return
  CelParseRejection; NewParamDefinition returns the new
  InvalidParamDefinition; CalaLedgerConfig returns the new
  InvalidCalaLedgerConfig. Messages no longer go through to_string().
- NewTransaction's correlation_id defaults to id.to_string() via a
  bon default instead of the custom id setter.

New unit tests pin that invalid CEL, a mistyped param default and a
config with zero or two connection sources are still rejected.

cala-ledger-core-types never used derive_builder and drops it.
fuzz/Cargo.lock was stale on main and moves forward with the bump.

BREAKING CHANGE: New*/*Update builders are bon builders. build() is
infallible except for the validating builders listed above, whose
XBuilderError types are replaced. AccountUpdateValues,
AccountSetUpdateValues and JournalUpdateValues are removed and
*Update::default() + &mut setters no longer exist.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@bodymindarts
bodymindarts marked this pull request as ready for review October 22, 2026 14:25
@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

📊 Performance Report

Commit: c6a36f2
Updated: 2026-10-22 14:55:20 UTC

Cala Performance Benchmark Results (non-representative)

Criterion Benchmark Results (single-threaded)

Benchmark Time per Run Throughput % vs Baseline
post_simple_transaction 2.617ms 381 tx/s 0 (baseline)
post_backdated_transaction_with_effective_balances_365_days 110.791ms 9 tx/s -4132.0%
post_multi_layer_transaction 2.986ms 334 tx/s -14.0%
post_simple_transaction_with_effective_balances 3.081ms 324 tx/s -17.0%
post_simple_transaction_with_skipped_velocity 2.771ms 360 tx/s -5.0%
post_simple_transaction_with_velocity 3.675ms 272 tx/s -40.0%
post_simple_transaction_with_hit_velocity 1.788ms 558 tx/s +31.0%
post_simple_transaction_with_one_account_set 3.161ms 316 tx/s -20.0%
post_simple_transaction_with_five_account_sets 3.769ms 265 tx/s -43.0%
post_simple_transaction_with_ec_account_set 3.678ms 271 tx/s -40.0%

Load Testing Results (parallel-execution)

Scenario tx/s
1 parallel 230.08
2 parallel 364.69
5 parallel 502.82
10 parallel 464.62
20 parallel 474.93
2 contention 260.88
5 contention 251.60
2 acct_sets 198.22
5 acct_sets 198.08

Note: Performance results may vary based on system resources and database state.

Last updated by commit c6a36f2

Cargo.lock:
- rustls-webpki 0.103.15 -> 0.103.16 (RUSTSEC-2026-0382)
- webpki-roots 1.0.6 -> 1.0.10 (RUSTSEC-2026-0381)
- yanked: chacha20 0.10.0 -> 0.10.2, spin 0.9.8 -> 0.9.9,
  js-sys/web-sys 0.3.86 -> 0.3.106 and wasm-bindgen 0.2.109 ->
  0.2.129 (moved together; web-sys pins js-sys exactly)

fuzz/Cargo.lock:
- rustls 0.23.45 -> 0.23.46 (RUSTSEC-2026-0346..0349)
- rustls-webpki 0.103.15 -> 0.103.16, webpki-roots 1.0.9 -> 1.0.10
- yanked: chacha20 0.10.1 -> 0.10.2

Both crates arrive transitively via sqlx; no manifest changes. The
remaining warnings (im, sized-chunks, bitmaps unmaintained/unsound)
come from im 15.1.0, the latest release, required directly by
es-entity and obix, so no lockfile bump clears them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@bodymindarts
bodymindarts merged commit 6295c58 into main Oct 22, 2026
7 checks passed
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.

1 participant