Implementation design · 001-cash-snapshot

Point-in-time cash-account snapshots

How we will build it.

Status Draft Spec 001-cash-snapshot Owner Brian Corbin · @briancorbinxyz Branch 001-cash-snapshot Created Read time

Realise the two-book snapshot as a small, std-only Rust crate: exact i64 cents, a hand-rolled business-day calendar, and a settlement_date that reads the standard cycle in force on each trade's trade date. snapshot folds a trade book into IBOR (traded) and ABOR (settled) balances as of an instant. The one subtlety — and the biggest risk — is the settlement-cycle edition: the cycle is a domain fact that must be grounded in the corpus and pinned by edition, so a cutover in the rule is a re-grounding, not a code guess.

1 · Principles check

Verify this design respects every principle in v0.1.0. Any violation requires either a principles amendment or a deliberate exception logged below.

PrincipleComplianceNotes
P-2 · Small, reversible changesOKOne crate, one public snapshot entry point; the settlement-cycle edition is data, changeable by re-grounding, not a rewrite.
P-3 · Explicit over implicitOKMoney is exact i64 cents; a settlement date is always a business day — no floating point, no silent weekend settle.
P-5 · Record the whyOKD-001..D-006 each cite the §3 grounding row they rest on — a corpus edition for a domain fact, the crate source for the stack pick.
P-9 · Decisions are groundedOKEvery domain decision is verified against a pinned corpus edition; the one assumed decision (D-005) is a product knob, deliberately un-grounded.
P-7 · Done means verifiedOKThe crate ships with 5 passing cargo test cases spanning the cutover and the IBOR/ABOR reconcile — mechanical, not asserted.

2 · Technical context

Language(s)
Rust (2021 edition), standard library only — no external crates.
Frameworks
None. A single library crate, settlement.
Architecture
Single-module domain library: a SettlementCalendar, an edition-correct standard_cycle, and a pure snapshot fold over a trade book. No I/O, no framework.
Storage
None — the caller owns the trade book and calendar; the crate is pure computation.
Testing
Rust #[cfg(test)] unit tests on fixed fixtures spanning the 2024 cutover; cargo test.
Coverage
Diff-aware: the settlement and snapshot paths carry direct tests; a change never lowers coverage of the code it touches. Never a single universal %.
Perf targets
Not in scope — a snapshot is an in-memory fold over a bounded book; there is no latency SLO in this slice.
Constraints
Exact integer cents (no floating point on money); settlement dates are always business days; the settlement cycle is edition-pinned domain data, not a hard-coded constant.

3 · Grounding & evidence

Every design-bearing fact this design rests on, and how it was confirmed — read this before the approach: it separates what the design knows from what it assumes (per REQ-LIFECYCLE-006). Status is verified (opened the source this turn), spike (decidable only by a time-boxed investigation — run it, record the finding), or assumed (taken as true without verification). A must-tier decision may not rest on an assumed/unresolved-spike fact unless accepted as a <spec-risk> (see §8).

Claim the design rests onSourceStatusFinding / note
The US standard settlement cycle in force is T+1 — a trade settles one business day after trade date, from the 28 May 2024 compliance date. KB-0001@2024-05-28 (finance-settlement corpus) verified SEC Rule 15c6-1 shortened the standard cycle to T+1, compliance date 28 May 2024 — the current corpus edition, which supersedes the earlier T+2 edition. Re-grounded from KB-0001@2017-09-05 after the cutover. Grounds D-001.
IBOR is a trade-date (traded-cash) view; ABOR is a settlement-date (settled-cash) view; PBOR is out of scope. KB-0003@2024-01-15 (finance-settlement corpus) verified Books of record differ chiefly in cash basis and timing: IBOR shows traded cash immediately, ABOR once settled. Grounds D-002.
A snapshot is a balance "as of" an instant; settled cash counts trades whose settlement date is on or before the as-of time. KB-0004@2024-01-15 (finance-settlement corpus) verified A correct as-of snapshot applies the settlement rule in force on each trade's trade date, not today's. Grounds D-003.
FX settlement risk is on the full principal of the unsettled leg; PvP settlement eliminates principal risk. KB-0002@2022-07-08 (finance-settlement corpus) verified Report exposure on principal with a PvP flag (BIS CPMI). Grounds D-004.
A 60-second snapshot cache TTL is an acceptable freshness/cost trade-off. — (product choice) assumed A local product knob, not a domain fact; deliberately not grounded against the corpus. Grounds D-005.
A std-only Rust crate with i64 cents and a hand-rolled calendar realises the whole computation. impl/src/lib.rssettlement_date, snapshot, standard_cycle, T1_EFFECTIVE verified The crate compiles std-only and passes 5 cargo test cases spanning the cutover and the IBOR/ABOR reconcile. Grounds D-006.

4 · Approach

The crate is one module. Date is a day-count (Howard Hinnant's civil ⇄ days algorithms) so ordering and business-day arithmetic are cheap and total. SettlementCalendar holds weekends plus a holiday set and offers is_business_day / add_business_days; settlement_date composes the latter with standard_cycle(trade_date), which returns the cycle length in force on that trade date. snapshot folds a trade book into a Snapshot { ibor_cents, abor_cents }: a trade counts toward IBOR when its trade date is on or before the as-of instant, and toward ABOR when its settlement date is.

The single load-bearing choice is that the cycle length is domain data pinned by edition, not a constant. standard_cycle reads T+1 on or after the 28 May 2024 compliance date and T+2 before it; that cutover is grounded against KB-0001@2024-05-28 and exercised by tests that straddle it — never a guess in code.

Trade book fills + as-of settlement_date edition-correct cycle Snapshot IBOR + ABOR
A trade book plus an as-of instant is folded through the edition-correct settlement_date into a two-book Snapshot.

5 · Alternatives considered

OptionExact moneyZero-dep footprintEdition controlTotal
Rust, std-only — chosen55515
Rust + a date crate (chrono/time)53513
Python + pandas2237

A date crate would buy calendar conveniences the hand-rolled day-count already covers, at the cost of a dependency and less direct control over the business-day rule. Python's float money basis fails the exact-cents constraint outright. The std-only crate wins on all three axes and keeps the settlement cycle a one-constant, fully-owned edition switch.

6 · Decisions

D-001 · Settlement date from a business-day calendar (T+1)

Status
Accepted
Context
FR-001 needs a trade's settlement date. The standard US-equity cycle is T+1 from the 28 May 2024 compliance date, grounded on the §3 corpus row KB-0001@2024-05-28, which supersedes the earlier T+2 edition — re-grounded here after applying 2024-05-28-usd-t1-settlement.
Decision
Settlement date = trade date + 1 business day (T+1) for trades on or after 28 May 2024, and + 2 (T+2) before, where business days exclude weekends and the calendar's US market holidays. The cycle length is read from standard_cycle(trade_date), not hard-coded at the call site.
Consequences
+ point-in-time correct and edition-pinned; a cutover is a re-grounding, not a rewrite. − the pinned edition must be re-grounded when the rule changes, or the design drifts from the live corpus (exactly the staleness signal this example demonstrates).

D-002 · Cash basis per book — IBOR traded, ABOR settled

Status
Accepted
Context
FR-002 needs two balances from one account. The §3 corpus row KB-0003@2024-01-15 gives the basis: IBOR is trade-date (traded cash), ABOR is settlement-date (settled cash); PBOR is deferred.
Decision
Snapshot { ibor_cents, abor_cents }: IBOR sums trades with trade date ≤ as-of; ABOR sums trades with settlement date ≤ as-of. PBOR is out of scope for this slice.
Consequences
+ one fold yields both books; their difference is cash in flight. − a consumer must not read ABOR as available cash — holds are a later slice.

D-003 · As-of snapshot semantics

Status
Accepted
Context
SC-001 and SC-002 require a balance "as of" an instant. The §3 corpus row KB-0004@2024-01-15 fixes the semantics: settled cash counts trades whose settlement date is ≤ the as-of time, under the rule in force on each trade date.
Decision
snapshot(opening, book, as_of, cal) is a pure fold; a trade contributes to ABOR only once cal.settlement_date(trade_date) <= as_of. Opening balance seeds both books.
Consequences
+ a historical as-of reproduces exactly, because each trade settles under its own edition. − correctness depends on the calendar's holiday set being right for the window.

D-004 · FX exposure on principal with a PvP flag

Status
Accepted
Context
FR-003 asks for FX settlement exposure. The §3 corpus row KB-0002@2022-07-08 (BIS CPMI) says settlement risk is on the full principal of the unsettled leg, and PvP eliminates principal risk.
Decision
For a two-legged trade, report exposure on the principal of the unsettled leg and carry a boolean PvP flag; a PvP-settled trade reports zero principal risk.
Consequences
+ the exposure number matches how settlement risk is actually measured. − FX is a SHOULD in this slice; the single-currency path ships first.

D-005 · Snapshot refresh interval (60 s TTL)

Status
Accepted
Context
FR-004 (MAY) allows a refresh cadence. This is a local product decision — a freshness/cost trade-off, not a domain fact — so it is grounded assumed and, per the design's grounding rules, a product choice must not manufacture a corpus citation to look verified.
Decision
Default a 60-second cache TTL for a computed snapshot, product-configurable; below the TTL a cached snapshot is returned, above it the snapshot is recomputed.
Consequences
+ bounds recomputation cost with a single knob. − a stale-tolerant default; a consumer needing to-the-second freshness sets the TTL to zero.

D-006 · Implementation stack — Rust, std-only

Status
Accepted
Decision drivers
Exact integer money · zero external dependencies · direct control of the business-day / edition rule
Considered options
  • Rust, std-only — chosen — + exact i64 cents, no dependency to audit, full control of the cycle constant. − a hand-rolled day-count to own.
  • Rust + a date crate — + calendar conveniences. − a dependency for arithmetic the day-count already covers.
  • Python + pandas — + fast to sketch. − float money fails the exact-cents constraint.
Context
This is a stack pick, not a domain fact, so it is grounded on real code, never the corpus: the §3 row impl/src/lib.rs — the symbols settlement_date, snapshot, standard_cycle, and T1_EFFECTIVE — and its 5 passing cargo test cases.
Decision
Implement as the std-only Rust crate settlement: i64 cents, a hand-rolled SettlementCalendar, and an edition-correct standard_cycle.
Consequences
+ no supply chain, exact money, one-constant edition control. − the calendar and day-count are ours to maintain and test.

7 · Project structure

Only the new or changed paths, grouped by the single-module boundary the §6 decisions draw.

impl/
  Cargo.toml            crate: settlement (std-only)
  src/
    lib.rs              Date, SettlementCalendar, standard_cycle, Trade, Snapshot, snapshot() + 5 tests

8 · Risks & mitigations

RiskLikelihoodImpactMitigation
R-1 · The pinned settlement cycle (D-001) goes stale when the standard cycle changes, so the design asserts a rule the live corpus no longer carries.HMRe-ground D-001 against the newer corpus edition on any cutover; the corpus-staleness validate warning makes the drift loud rather than silent.
R-2 · The holiday set is wrong for the window, so a settlement date lands on a non-business day.LHis_business_day excludes weekends and holidays; tests pin Memorial Day 2024 across the cutover.
R-3 · A consumer reads ABOR as available cash and over-spends against holds not yet modelled.MMName the two books explicitly; available cash is a deferred slice (spec §3 out-of-scope), documented on the Snapshot type.

9 · Complexity tracking

Anywhere this design introduces complexity not strictly required by the spec, justify it here.

The day-count and business-day calendar are hand-rolled rather than pulled from a date library. This is deliberate: it removes a dependency, keeps money and dates as plain integers, and makes the settlement cycle a single owned constant that a corpus re-grounding can flip — the whole point of the worked example.

10 · Open questions

None outstanding — every domain decision is grounded against a pinned corpus edition, the stack pick against the real crate, and the one product knob (D-005) is deliberately left as an assumed default rather than an open question.

11 · Change log

  1. Initial design. Std-only Rust crate: settlement-date from a business-day calendar (D-001, T+2, grounded on KB-0001@2017-09-05), IBOR/ABOR cash basis (D-002), as-of snapshot semantics (D-003), FX exposure + PvP (D-004), a 60 s refresh TTL as a product knob (D-005, assumed), and the std-only Rust stack pick grounded on the real crate (D-006).
  2. Re-grounded D-001 after applying 2024-05-28-usd-t1-settlement: T+2 → T+1, and its corpus pin from KB-0001@2017-09-05 to KB-0001@2024-05-28 (the current edition), clearing the corpus-staleness warning.