# Stage 2 — frozen committed export and balance-fold contract

Frozen by root ratification on 25 October 2026. This extends read/export behavior without modifying any Stage 1 journal, posting, identity or correction API. The original 28-topic plan's plan-only restrictions have been superseded by the user's subsequent execution approval. This file owns shared export semantics for Event-Sourced Balance Fold and Bitemporal Ledger Versioning.

## Learning contract and scope

Reconstruct one institution account's exact posted balance from complete committed journal history; explain where the opening state came from; reproduce a checkpoint; identify missing, duplicated, conflicting or reordered evidence before reporting a complete balance. Pending/rejected commands and reservations are not committed journal events. Available funds and hold lifecycles are separate tutorials.

The canonical implementation is a deterministic portable read model. It validates an export against trusted source-head evidence; it neither authenticates the source cryptographically nor establishes live database commit behavior.

## Unchanged Stage 1 rules

Cedar Teaching Bank is fictional, ledger CB-GENERAL/entity CB-A; customer deposits are credit-normal liabilities. Money inputs remain positive canonical decimal strings, at most 30 digits per leg, 2–32 ordered legs and at least two distinct accounts. Same-entity/same-ledger/same-currency journal balancing is exact. Raw account balance is debit-positive; normal balance flips raw sign for credit-normal accounts.

Command fields are exactly schema_version, ledger_id, entity_id, journal_id, business_operation_id, currency, effective_at, source_available_at, booking_period and legs. Leg fields are exactly account_id, side and amount_minor. Version is d30-journal-v1. Strict identifiers, positive strings, genuine Gregorian UTC milliseconds and retained semantic leg order remain unchanged.

A read validator does **not** rerun present-day posting eligibility. A now-closed account's historical journals still count; today's open-period list cannot reject already committed history. Validate immutable account type/normal side/scope/currency metadata and original command structure, clocks, exact balancing and retained adjustment evidence. Contra accounts remain excluded in this variant.

## Exact shared export schemas

All objects reject missing/unknown fields. JSON object property order is irrelevant; journal/group arrays retain semantic order. Identifiers use the frozen ASCII identifier grammar.

The portable reference accepts at most 4096 committed groups across the complete prefix plus suffix, rejecting a larger history as INVALID_GROUP. This is an implementation resource bound, not a ledger-size limit or performance claim. Checkpoint raw-balance representations are defensively limited to 128 characters, above every aggregate reachable under this profile; values are never truncated.

### Exported journal

Exactly:
- `command`: complete strict Stage 1 command object.
- `sequence`: canonical positive decimal string, at most 30 digits.
- `recorded_at`: original trusted server recording timestamp.
- `adjustment_reason`: retained string. Its result after Python-whitespace trimming must be nonempty if booking month differs from economic month; retain the supplied bytes, including padding. Otherwise use an empty string in this read profile.

This nested form adapts both the Stage 1 flat portable journal and SQL command/result row. Adaptation does not alter the original command or its recording clock.

### Committed group

Exactly:
- `schema_version`: d30-committed-group-v1.
- `group_id`: stable unique identity in one ledger stream.
- `kind`: posting or correction.
- `ledger_id`, `entity_id`.
- `available_at`: trusted observer receipt after successful COMMIT, not a claim of the exact physical commit instant.
- `journals`: ordered array of exported journals.
- `correction`: null for posting, otherwise the exact link below.

Posting groups contain exactly one journal. Correction groups contain exactly two journals, reversal first and replacement second. A correction link has exactly correction_id, original_journal_id, reversal_journal_id, replacement_journal_id and reason. Reason is an already-trimmed 1–240 Unicode-scalar string matching the frozen correction convention.

Correction member command ledger/entity/currency/effective/source/booking fields agree with each other. The link names the two actual member journal IDs. Derive and verify the exact reversal from the previously committed original: preserve every account/amount/position, flip only debit/credit. The original must precede the correction group. One full reversal per original, no reversal-of-reversal and no cyclic/self-target shortcut. A later group may correct a replacement as a new original. Both member journal/business identities are unique across the scoped history.

### Trusted source head

Exactly stream_id, ledger_id, entity_id, observed_at, head_sequence and receipt_ref.

Head sequence is a canonical nonnegative decimal string, at most 30 digits, including zero. The head and receipt originate in trusted source/context independently of the supplied group list. Merely placing a self-consistent last sequence in a supplied export does not establish completeness. The source observation must come from one consistent committed snapshot; unrelated Read Committed queries can observe different database states.

The sequence is the profile's transactional committed ledger counter. Ordinary nextval gaps are not interchangeable with this gap-free profile.

## Clock and ordering invariants

- Each journal satisfies effective_at≤recorded_at and source_available_at≤recorded_at.
- Each journal recording timestamp≤its group's available_at≤head.observed_at.
- Journal recording timestamps are nondecreasing in ledger sequence; equal timestamps are allowed.
- Group available_at values are nondecreasing in canonical sequence order; tied receipts are allowed.
- Source availability need not be monotonic across different journals. Late evidence may have an older source timestamp.
- Preserve distinct recording times for SQL reversal/replacement members. Do not invent equality to simulate atomicity.
- Atomic visibility comes from the whole committed group and its one receipt.
- The knowledge cutoff must be≤head.observed_at; otherwise reject KNOWLEDGE_BEYOND_EXPORT. An old source snapshot cannot establish later completeness.

## Query and selection

Canonical query has exactly schema_version (d30-balance-fold-v1), ledger_id, entity_id, account_id, currency, effective_cutoff, knowledge_cutoff and checkpoint. Checkpoint is null for genesis or a complete checkpoint object below. There is no query watermark.

Select complete groups with available_at≤knowledge_cutoff, including all groups tied at an equal receipt time. Within selected groups, include account legs only from journals with effective_at≤effective_cutoff. Boundaries are inclusive; individual contributions therefore occupy [effective_at,+infinity)×[group.available_at,+infinity).

Economic cutoff may precede or follow knowledge cutoff. A later economic cutoff still returns only accepted contributions known by the knowledge cutoff; it is not a forecast. Booking-period reporting is a different filter and is not substituted for the economic cutoff.

Validate the entire evidenced full stream or checkpoint suffix through the trusted head **before** temporal filtering. A missing future-unselected group still makes the supplied export incomplete relative to the trusted head. No precise complete balance is returned from such a partial input.

## Coverage, duplicates and order

Genesis input starts at sequence 1 and covers every sequence through head_sequence. A checkpoint suffix starts at checkpoint.through_sequence+1 and covers through head_sequence. Every group contains consecutive journal sequences. No watermark or checkpoint may split the correction pair.

Exact duplicate group ID/payload rejects DUPLICATE_GROUP. Same group ID with changed payload rejects GROUP_ID_CONFLICT. Do not silently sort input, merge repeated groups or double-count duplicate delivery. Novel lower sequences reject OUT_OF_ORDER_GROUP; forward gaps reject SEQUENCE_GAP; a missing tail rejects INCOMPLETE_EXPORT. Repeated journal ID or business operation ID across distinct groups rejects DUPLICATE_JOURNAL / DUPLICATE_BUSINESS_OPERATION.

An empty genesis export with trusted head 0 returns zero and validated empty coverage. Nonzero opening balances must be evidenced by explicit opening journals or the registered checkpoint; no unexplained scalar is injected.

## Checkpoints and original-history context

Checkpoint fields are exactly schema_version (d30-balance-checkpoint-v1), checkpoint_id, stream_id, ledger_id, entity_id, account_id, currency, normal_side, through_sequence, effective_cutoff, raw_balance_minor, last_group_id, last_recorded_at, last_available_at and provenance_ref.

Signed raw balance strings are canonical zero or signed nonzero integer strings; no negative zero, plus sign, exponent, decimal or leading zero. Aggregate balances are not truncated to a per-leg maximum. Sequence 0 checkpoint has raw 0 and null last_group_id/recorded/available timestamps.

The trusted context has exactly head and checkpoint_registry. Registry entries have exactly checkpoint and prefix_groups. Every entry must have a structurally valid complete checkpoint and a prefix_groups list within the4096-group resource bound, even when the current query starts at genesis. Unused well-formed prefixes need not be replayed; the selected cache prefix is fully audited. The query's complete checkpoint must semantically equal the trusted registry entry at its scoped identity; matching just its ID is insufficient. Caller-supplied balance fields do not establish trust.

For this auditable teaching reference, a nonzero checkpoint registry retains its complete validated prefix groups through its group-end sequence. The implementation validates that prefix and independently recomputes its balance for the fixed effective_cutoff before seeding the suffix. This detects a corrupted cached balance as CHECKPOINT_BALANCE_MISMATCH and supplies original-journal/correction indexes for subsequent exact-reversal checks. It is deliberately not a performance benchmark or a claim of compact authenticated checkpoint storage.

Registry prefix plus supplied suffix must meet the same global sequence, clock, identity and correction invariants. The suffix itself starts strictly at p+1; a delivery overlapping the trusted checkpoint rejects CHECKPOINT_OVERLAP. A checkpoint after the query's knowledge cutoff rejects CHECKPOINT_AFTER_KNOWLEDGE. A changed economic cutoff rejects CHECKPOINT_QUERY_MISMATCH and requires genesis replay. Wrong stream/account/entity/currency/normal-side/provenance/complete registry fields reject CHECKPOINT_MISMATCH or UNKNOWN_CHECKPOINT.

Checkpoints are caches backed by trusted registry/provenance and rechecked prefix evidence here, not cryptographic proof. A production adapter may persist separately validated indexes/snapshots, but omitting prefix validation requires an explicit different trust profile; that variant is outside this reference.

## Proposed public API and stable output

Python `fold_balance(query, groups, accounts, context)` / TypeScript `foldBalance` is self-contained and returns:
- status: ok or rejected.
- code: BALANCE_FOLDED or typed reason.
- balance: null on rejection, otherwise account_id/currency/normal_side/raw_balance_minor/normal_balance_minor.
- coverage: null on rejection, otherwise stream_id/receipt_ref/head_sequence/validated_through_sequence/visible_through_sequence/checkpoint_id/observed_at.
- trace: empty on rejection, otherwise visible committed groups only, with group_id/first_sequence/last_sequence/available_at/selected_journal_ids/raw_delta_minor/raw_balance_minor/normal_balance_minor.
- checkpoint: null on rejection, otherwise a new complete checkpoint for the visible complete-prefix position and the fixed effective cutoff.
- checkpoint_registry_entry: null on rejection, otherwise the new checkpoint and its complete visible prefix_groups, suitable for trusted host persistence.

No future-unavailable group identities, amounts or deltas appear in the query trace. Later source-head metadata is evidence provenance, not a model feature or a claim that it was known at the historical query instant.

Output checkpoint IDs are deterministic within scope, using CP-{through_sequence}-{effective cutoff with punctuation removed}; scoped checkpoint identity includes stream/entity/ledger/account/currency. Runtime monetary JSON is string-valued. Pure functions never mutate inputs.

Structural/schema errors use INVALID_SCHEMA/INVALID_IDENTIFIER/INVALID_TIMESTAMP/INVALID_AMOUNT/INVALID_SEQUENCE/INVALID_ACCOUNTS/INVALID_CONTEXT as appropriate. History errors add SCOPE_MISMATCH, CURRENCY_MISMATCH, UNSUPPORTED_CURRENCY, INVALID_GROUP, INVALID_CORRECTION_LINK, INVALID_REVERSAL, ALREADY_REVERSED, REVERSAL_OF_REVERSAL, CLOCK_ORDER_VIOLATION and the coverage/checkpoint reasons above. Rejection supplies no apparently complete balance or partial accepted state.

## Independent canonical expectations

The companion fold-independent-fixtures.json preserves:
- Funding100000; erroneous Ada→Ben2500; exact reversal2500/replacement Ada→Cora2400; later fee250.
- Ada normal balances100000→97500→97600→97350 across complete visible groups.
- Before the correction group's receipt, including between member recording timestamps, Ada stays97500. At receipt equality both members appear and Ada becomes97600.
- Economic cutoff20October with later knowledge excludes the23October fee and returns97600.
- Checkpoint after sequence2 at economic cutoff20October has raw Ada−97500; resumed correction contributes raw−100, giving−97600.
- Huge integer funding and full-prefix replay preserve exact string arithmetic.
- Missing, duplicate/conflicting, reordered, split-correction, stale-head and wrong/corrupted checkpoint cases reject without a complete balance.

## Primary research and boundaries

Microsoft Azure Architecture Center's official Event Sourcing pattern explains ordered replay, projections, snapshots, compensating events and duplicate-consumer concerns. It does not establish this accounting schema or a performance result. PostgreSQL 18 transaction/isolation documentation supports complete committed visibility and consistent snapshot requirements; its sequence documentation explains why nextval gaps are not committed-counter completeness evidence.

All financial data is synthetic; arithmetic is independently author-derived; chosen schemas/cutoffs/limits are implementation choices. Historical-example decision: not useful for deterministic replay mechanics. Future cryptographic integrity tutorials supply stronger verification; this stage does not borrow their guarantees.
