packages feed

exchangealgebra-0.5.0.0: ChangeLog.md

# Changelog for ExchangeAlgebra

## 0.5.0.0 - 2026-09-04

The 0.5 line was first prepared on 2026-06-07 around a selectable value type, with recovery tag `recovery/0.5.0.0-dev-2026-06-08`. Before publication, it absorbed the account registry and semantics, the Definition 7 contra amendment with netting presentation, the JCCI/EDINET vocabulary, checked-conversion posting capability, categorical phase-1 laws, the CL-SBM industrial network generator, and the audit-eval tooling.

Selectable value type: `Double` (default, fast) / `MoneyDouble` (typed fast FP)
vs an exact non-negative `Decimal` (`MoneyDecimal`) for determinism/auditability.
**Breaking** (PVP major):
`HatVal` lost its `RealFloat` superclass and gained `showValue`. See the README
"Choosing a value type" and "Migrating to 0.5.0.0" sections.

### Highlights
- Add selectable value types with `MoneyDecimal` and `MoneyDouble`, while removing the `RealFloat` superclass from `HatVal`.
- Add an exhaustive account registry and `AccountSemantics` covering roles, posting capability, and JCCI/EDINET presentation names.
- Amend Definition 7 with `isContra`, contra-aware projections, and netting presentation in `bsRows` / `plRows`.
- Make closing entries cover every Cost and Revenue account.
- Enforce posting capability by processing context in checked conversion.
- Encode `AccountTitles` Binary tags as big-endian `Word16`.
- Document the categorical phase-1 laws for `mapBasePart`, `foldEntries`, and `postFromNetBy`, pinned by property tests.
- Add trial-balance validation, consolidation-worksheet validation, JGAAP reporting transformation, and derived period-result metrics.
- Add the ordered CL-SBM `industrialNetwork` / `industrialFlows` generator and `industrialEx1`.
- Add audit-eval compatibility, scoring, checkpoint, Track S checked-loader, and generated-suite tooling in the examples.
- Improve performance with strict `Journal.fromList`, an exact-projection fast path, faster journal append, and projection-sharing trial-balance rows.
- Tighten module boundaries: `Alg`, `Journal` and `TransTable` are abstract (`Algebra.Internal` holds the representation); posting authority lives in `Accounting.PostingPolicy`, account balances in `TrialBalance.Balance`, spill codec and restore in `Simulate.Spill`; `Write` no longer depends on `Simulate`; Chart plotting sits behind the `visualize` flag; typed `mapPosting`, `replaceNotes` and `mkJournal` replace implicit contracts.

### Breaking
- **BREAKING: `Alg`, `Journal` and `TransTable` are abstract.** `Alg` exports
  only `Zero`, `(:@)`, `_val` and `_hatBase`; the multi-posting `Liner`
  representation, `Pair` and the cache fields live in the new
  `ExchangeAlgebra.Algebra.Internal` (outside the PVP contract). `Journal` is
  built with `mkJournal`, `(.|)` or `fromList`; `TransTable` with `table`,
  `(.->)` or `(|%)`. Hand-built values could desynchronise the cached axis
  indices and make wildcard projections answer wrongly without an error.
- **BREAKING: binary spill files are validated on read.** `readBinarySpillFile`
  now raises an error at the first undecodable chunk instead of silently
  truncating the remainder, and `restoreJournalFromBinarySpill` rejects
  out-of-order, overlapping, gapped, or empty chunk ranges (previously a
  partially readable or stale file was merged as if complete, dropping every
  term up to the last readable chunk). Its constraints gain `Enum t` and
  `Show t`, both already implied by `StateTime`. `Simulate.Lite` now truncates
  the spill file when a run opens it (`WriteMode` instead of `AppendMode`), so
  re-running with the same path no longer accumulates stale chunks.

- **BREAKING: checked conversion now enforces posting capability by processing
  context.** `checkedEntryIn`, `checkedEntryTextIn`, `checkedJournalIn`, and
  `certifyJournalTextIn` admit ordinary postings plus exactly the capability
  owned by `ClosingProcess`, `ConsolidationWorksheet`, or
  `EngineComputation`. The existing context-free functions now delegate to
  `OrdinaryJournal`, so they reject closing-only, consolidation-only,
  engine-generated, and non-postable coordinates with `PostingNotAllowed`.
  Unknown account text remains a vocabulary failure, while a resolved but
  context-disallowed title is a structural rejection. Algebra construction,
  balance rules, and unchecked conversion (including `Convert.Csv`) are
  unchanged.

- **BREAKING: LLM-facing account metadata now separates bookkeeping and
  reporting semantics.** `AccountSemantics` records account roles, posting
  capability, the meaning of the legacy five-way division, home-side
  semantics, and reporting eligibility for all 235 concrete titles;
  `AccountTitle` remains explicitly outside the domain. `AccountInfo` exposes
  these fields instead of the ambiguous `aiDivision` / `aiHomeSide` pair, so
  direction encodings such as `IncomeSummary = Assets` and
  `NetIncome = Cost` are no longer presented as statement classifications.
  The exchange-algebra basis, legacy division/side/PIMO behaviour, Binary
  encoding, closing, projections, and financial-statement rows are unchanged.

- **BREAKING: closing entries now cover every Cost and Revenue account.**
  `finalStockTransfer` derives its policy from the exhaustive account registry;
  previously it closed only 17 SNA-era accounts. `NetIncome` and `NetLoss`
  are permanent explicit `NoClose` overrides: their division encodes the
  P/L presentation side, so the division-derived rule would invert their
  transfer sign; the dedicated net-income transfer owns their closing.

- **BREAKING: `AccountTitles` binary tags now use Word16 big-endian encoding**
  instead of Word8. This removes the 256-constructor ceiling and rejects
  out-of-range tags through the `Get` failure channel. Journals and other
  values persisted with the old format cannot be read by 0.5.0.0.

- **BREAKING: account division semantics for contra accounts** (Definition 7
  amendment, Land 2). `AllowanceForDoubtfulAccounts` and
  `AccumulatedDepreciation` are now classified `Assets` with the new
  `ExBaseClass` method `isContra = True` (previously `Liability`). Home side
  and PIMO are both derived from `(whatDiv, isContra)`: home side =
  `defaultSide` of the division, reversed for contra; PIMO =
  `pimoFromDivision`, flipped by `pimoFlip` (PS↔MS, IN↔OUT) for contra.
  Observable invariants: `whichSide`, `whatPIMO` and `fixedCurrent` are
  unchanged for every account (the two contra accounts keep the Credit home
  side and MS); only `whatDiv` — and, in the pre-Land1 assistance API,
  `aiDivision` and descriptions — changed, for exactly these two accounts.

- **BREAKING: `(<=>)` on `AccountDivision` is now derived via
  `pimoFromDivision`**, matching Proposition 5.3.8 (Deguchi 2004; PS⇔IN,
  PS⇔MS, OUT⇔IN, OUT⇔MS). Migration table (ordered cases; every other pair
  is unchanged): `(Assets, Revenue)` False→True, `(Revenue, Assets)`
  False→True, `(Cost, Revenue)` False→True, `(Revenue, Cost)` False→True.
  Exchange checks on bases should use `whatPIMO` (contra-aware), not bare
  divisions.

- **BREAKING: real contra deduction/netting presentation (Definition 7,
  Land 3).** `bsRows` and `plRows` now render active presentation groups as
  gross rows, deduction rows, and a net row instead of placing contra assets
  in the Liability column or dropping P/L contra accounts. The shared
  `ExchangeAlgebra.Reporting.Group` module defines the five registry-backed
  groups and keeps stored and rendered magnitudes non-negative; a leading
  minus sign is introduced only when rows are rendered. Statements without a
  contra posting keep their ordinary rows, while formerly hidden abnormal
  balances are no longer included in column totals. Contra amounts exceeding their gross
  parent, multiple contra rows, absent parents, and nested groups have explicit
  test coverage. Column totals are calculated from displayed net amounts.
  The six division projections now exclude contra accounts entirely;
  select them with `projContraAssets` (Assets division) or the generic
  `projContra` (attribute-based: keeps both Hat and Not postings).

- **BREAKING: Add shared JCCI B-column names.** The 6 labels accepted by
  `parseAccountTitle` (`未払金`, `借入金`, `仮払金`, `仮受金`, `有価証券`,
  `投資有価証券`) now produce `AmbiguousAccount` with a list of candidates
  instead of resolving uniquely. Use canonical constructor names or explicitly
  select a candidate based on context.

- `whichSide` now rejects a `HatNot` (wildcard) base with an error instead of
  silently treating it as `Hat` (design-review C5): stored postings are always
  `Hat`/`Not` (same policy as `isHat`), so a wildcard reaching `whichSide`
  means a query-side value leaked into a posting-side computation. __Breaking__
  only for code that relied on the silent-`Hat` behaviour.

- The universal `instance (HatVal n) => Show (n -> n)`
  (`ExchangeAlgebra.Algebra.Transfer`) was removed (design-review C5):
  __breaking__ for code that `show`ed raw rule-list tuples. `TransTable`'s own
  `Show` still prints `<function>` without it; one doctest was adjusted.

- `ExchangeAlgebra.Simulate.Lite` export hygiene (design-review C5):
  __breaking__. `Stage` is now exported name-only (build with
  `stageFor`/`stage`/`stageOf`, read the name via `stageName`); the `GLite*`
  Generic-plumbing classes are exported name-only (their primed methods are
  internal Rep wiring — user code only names the classes in constraints).

- The `ExchangeAlgebra` umbrella no longer re-exports `ExchangeAlgebra.Simulate`:
  __breaking__ (design-review C1). The simulation engine exports very generic
  names (`copy`, `modify`, `update`, `initialize`, `normal`, `initAll`, …) that
  polluted the recommended bookkeeping entry point. Migration: add
  `import ExchangeAlgebra.Simulate` where those names are used — the module now
  follows the same "import directly" policy as `Bookkeeping`/`Simulate.Lite`/
  `Simulate.Network`/`Simulate.Policy` (documented in the umbrella Haddock).
  The bundled examples were migrated mechanically (import line only).

- `ExchangeAlgebra.Algebra.Base.Element` no longer re-exports the whole
  `Data.Hashable` and `GHC.Generics` modules: __breaking__ (design-review C1).
  Only the two names needed to define an `Element` instance remain re-exported
  (`Hashable(..)` and `Generic`); the previous module-level re-exports leaked
  their entire namespaces through `Base` → `Algebra` → the umbrella. Migration:
  import `Data.Hashable`/`GHC.Generics` directly for any other names.

- `Element` class wildcard methods (`ExchangeAlgebra.Algebra.Base.Element`):
  __breaking__. The misspelt `wiledcard` method family is renamed to the correct
  spelling, with no compatibility aliases (audit R2). Migration (旧名 → 新名):
  `wiledcard` → `wildcard`, `haveWiledcard` → `haveWildcard`,
  `isWiledcard` → `isWildcard`, `ignoreWiledcard` → `ignoreWildcard`. Any
  `instance Element` defining `wiledcard` (and overriding `haveWiledcard` /
  `isWiledcard` / `ignoreWiledcard`) must rename those method definitions; all
  call sites use the new names. The `(.#)` wildcard shorthand is unchanged.
  The bundled SICE-frozen examples were updated by mechanical identifier rename
  only (the rename is compile-following and preserves their semantics/values).

- `(.*)` (scalar product) now **rejects a negative / non-finite scalar** with an
  `error`, instead of silently producing out-of-domain (negative) postings (the
  algebra is over non-negative values; audit divergence C). The check is on the
  scalar only — `0 .* x = Zero` and non-negative scalars are unchanged, and the
  fast internal value map is preserved. Covered by `testScalarRejectsNegative`;
  the bundled `ripple`/`CGE` Double examples are unaffected (their production
  amounts stay non-negative).

- `HatVal` no longer has `RealFloat` as a superclass; it gains a `showValue ::
  n -> String` method. This lets non-floating-point value types (e.g. an exact
  `Decimal`) become `HatVal` instances. The `Double` / `NN.Double` instances render
  byte-for-byte identically to before (the old internal `showV` was inlined into
  each instance's `showValue`). `Fractional` is kept, so numeric literals still
  work for value types. Downstream code that relied on `HatVal n => RealFloat n`,
  or defined its own `HatVal` instance, must adapt (add `showValue`).

- `Journal.fromList` is now a strict left fold (`L.foldl' (.+) mempty`) instead of
  the lazy right fold (`foldr (.+) mempty`). It is `O(N)` and ~15× faster at
  N=10000 / ~40× at N=20000 in the core benchmark (the lazy right fold built a deep
  thunk that was expensive to force). The posting **multiset is preserved**; the
  only change is the accumulation order of same-note/same-base postings within one
  `Alg` sequence. That `Seq` order is observable through `Eq` / `Show` / `toAlg` /
  `Binary`, and for `Double` through the last-ULP of `norm` / `bar`. For the exact
  `MoneyDecimal` value type the order never affects `norm` / `bar` / balance. (The
  interim `fromListFast`, added during staging, was folded back into `fromList`.)

- Removed: `Journal` `_jVersion` field (`ExchangeAlgebra.Journal`): __breaking__. This
  write-only counter was never observed by any read path (audit R3/F2). The
  `Journal(..)` constructor now has one fewer field and the `_jVersion` record
  accessor is gone; the internal `mkJournal` no longer takes a version argument.
  The `Binary` instance is unaffected (it serialises via `toMap`/`fromMap` and
  never touched `_jVersion`), so the on-disk/spill format is unchanged.

- Removed: `forceBalance` (`ExchangeAlgebra.Algebra`): removed unused, unexported,
  untyped `undefined` placeholder (audit R3).

### Added
- Add `ExchangeAlgebra.TrialBalance.Balance`: one `AccountBalance` type
  (`NoBalance` / `DebitBalance` / `CreditBalance`) and one set of netting
  primitives (`balancePair` in debit-then-credit order, `netPair`,
  `combineBalances`, `balanceFor`, `balanceSide`, `balanceAmount`,
  `accountBalances`) shared by trial-balance validation, JGAAP presentation
  and the consolidation worksheet. The worksheet's separate `BalancePosition`
  type, whose pair order was credit-then-debit, is gone; its constructors are
  the shared ones re-exported, so `CW.CreditBalance` keeps working.
- Add `ExchangeAlgebra.Simulate.Spill`: spill options, chunk writers, the
  checked readers and journal restoration now live in one module that depends
  only on `Algebra` and `Journal`. `Simulate` and `Write` re-export the
  historical names unchanged; `Write` no longer imports `Simulate` and
  `Simulate.Policy` no longer imports `Write`. `Write.writeTermIO` drops its
  unused `StateTime` constraint (`Ix t` suffices).
- Add `ExchangeAlgebra.Accounting.PostingPolicy`: `ProcessingContext`,
  `postingAllowedIn` and `postingCapabilityFor` now live in the accounting
  layer; `Convert.Checked` re-exports them and `Consolidation.Worksheet` no
  longer depends on the input adapter. `Convert.Csv.splitTrim` is exported and
  shared with the `Simulate.Network` CSV readers, and
  `Convert.concreteAccountTitles` is the registry's definition re-exported.
- Add typed `mapPosting` / `mapMaybePosting` (one posting to exactly one, or
  to zero or one, with the same zero normalisation as `(.@)`), the explicit
  `Journal.replaceNotes` (left-biased whole-note replacement), and
  `Journal.Transfer.finalStockTransferAggregated`, the name that makes visible
  that the Journal-level closing folds the note axis onto the plank via `(.-)`.
  `Journal.mkJournal` is now exported as the safe constructor.
- Add `SpillReadError` / `SpillRangeIssue`, `readBinarySpillFileChecked`,
  `restoreJournalFromBinarySpillChecked` and `renderSpillReadError`, the
  `Either`-returning forms of the spill readers.

- `examples/audit-eval` second-experiment harness (audit-harness T3 / T5): the
  generator now covers five task categories (`closing`, `statements` and
  `consolidation` join the existing kinds in `gen/kinds.py`) with dual pandas /
  EA oracles, parameter-only closing adjustments (both oracles compute the
  amounts independently), voucher-id contracts in `given.transactions`, and a
  per-cell manifest with a task-bundle digest (`gen/make_manifest.py`,
  `TASK-FORMAT.md`). The runner adds a no-code-execution arm C with tool-event
  counting, `--chart-of-accounts`, `--skill v3`, a full V gate (voucher
  reconciliation plus a canonicalisation dictionary), manifest-hash checks on
  fresh runs and byte-pinned frozen v1 prompts; the scorer reports
  `posting_complete` and a three-valued outcome with explicit infra-missing
  handling. Examples-only; no library code touched.
- `examples/audit-eval/harness` documentation (audit-harness T4c): a transfer
  catalog (`CATALOG.md`, 19 of 27 library operations adopted plus two loader
  recipes), `SKILL-ea-v3.md`, the A′ named-call contract (`APRIME-CALLS.md`
  with `aprime-calls.schema.json`) and the `LoadChecked` bypass-guard design
  note. Examples-only; no library code touched.
- Add `industrialNetwork` / `industrialFlows` for deterministic ordered CL-SBM
  trade networks and exact demand-driven flows, plus the `industrialEx1`
  accounting example.

- Add a read-only `audit-eval` compatibility replay tool that pins frozen
  confirmatory inputs and compares historical and current checked-loader
  verdicts without regenerating model outputs.

- Add an opt-in `side` scoring contract to `audit-eval`. Ledger and
  trial-balance balances are compared as an actual debit/credit/zero side plus
  a non-negative amount, while the frozen signed-value `v1` contract remains
  the default for confirmatory-result reproducibility.

- Add dedicated `ConsumptionTaxRefundReceivable`, `PropertyTaxPayable`, and
  `DepositsReceivedFromOfficers` constructors for the corresponding JCCI
  level-2 A-column names. Add `AccountSpec.asLabelJa` for all 235 concrete
  titles and a complete JCCI level-2 A-column presentation-label sweep.

- Add typed, read-only reporting metrics. `PeriodResultMetric` represents one
  identity whose value is structurally `PeriodProfit`, `PeriodLoss`, or
  `PeriodBreakEven`; `GrossProfitMetric`, `OrdinaryProfitMetric`, and custom
  metric IDs are likewise separate from account-basis coordinates. Reporting
  subtotal definitions now carry this identity, profile-resolved labels, an
  explicit absent-title policy, and duplicate-identity validation.

- Add `periodResultOfAlg` / `periodResultOf`, which derive period profit or loss
  from genuine statement-classified revenue and cost coordinates without
  inserting a balancing account. After-closing trial-balance validation now
  reports residual period-result or reporting-subtotal coordinates explicitly.

- Add a JGAAP reporting transformation from validated trial balances with
  standalone/combined scope, reciprocal elimination, maturity allocation,
  materiality and contra policy, profile labels, auditable subtotals, and final
  debit-credit reconciliation.

- Add a trial-balance validation boundary with explicit reciprocal, temporary,
  closing-residual, abnormal-side, reclassification, and maturity-evidence
  findings, plus an opaque policy-controlled boundary for downstream reporting.

- Add a consolidation-worksheet validation boundary that preserves source and
  adjustment provenance, rejects imbalanced adjustments individually before
  aggregation, and checks net-income attribution, retained-earnings, and
  non-controlling-interest linkage across P/L, S/S, and B/S columns.

- Add pre-change goldens and a regeneration tool ahead of the 0.5.0.0
  separation of account-title semantics from the presentation layer. They
  freeze Binary bytes, registry/closing/side/PIMO, Assist metadata, projection
  membership, and legacy BS/P&L output for 232 concrete titles. Also add closed
  inventory checks for classification-related consumers to detect unintended
  differences and omitted consumers in subsequent lands.

- Add a checkpoint mechanism that splits and resumes long-running confirmatory
  runs of `audit-eval` at cell boundaries. It rejects drift in the
  task/model/backend/git surface/hash, corrupted or duplicate JSONL, and resume
  forks before execution, and supports lineage audits with independent
  verification and merge CLIs.

- Add the JCCI 2022 bookkeeping level 2 / level 3 A-column / B-column lists as
  frozen fixtures, with a coverage gate for 316 distinct normalized queries.
  295 queries resolve uniquely, while 21 queries for permitted shared names or
  generic profit-and-loss names are rejected as `AmbiguousAccount` with frozen
  candidate sets. Also add post-vocabulary ordinal, semantics, account-info,
  and suggestion fixtures and a regeneration tool, plus synchronization tests
  for 232 titles / 5 contra accounts in the Python account mirror.

- Add 116 account titles from JCCI bookkeeping level 2 commercial bookkeeping,
  with English display names conforming to the EDINET 2026 'general commercial
  and industrial' taxonomy, to `AccountTitles` and the exhaustive account
  registry. Limit the EDINET English labels to external display names while
  preserving the compatibility and uniqueness of internal constructor IDs and
  Japanese aliases. Also explicitly mark 3 contra accounts and 3 accounts
  excluded from closing transfers as registry attributes.

- Definition 7 amendment support: `ExBaseClass.isContra` (registry-delegated
  default), `defaultSide`, `pimoFromDivision`, `pimoFlip`,
  `projContraAssets`, and `projContra`.

- `JournalCert` and `certifyJournalText` in
  `ExchangeAlgebra.Convert.Checked` add staged certification for text-originated
  journal batches. Duplicate txids and structural errors are rejected first,
  then debit/credit balance is checked from sides and amounts independently of
  account-title resolution. Balanced batches with vocabulary-only failures are
  returned as `BalancedUnresolved`, including resolved postings, unresolved
  account text/errors with 0-origin indices, and exact debit/credit totals;
  fully resolved batches produce the same `Journal` as `checkedJournal`.

- `ExchangeAlgebra.Optimize` (new subsystem): a pluggable optimization
  solver interface — the `Solver` class fixes
  `optimize :: Monad m => strategy -> Config strategy -> (Candidate strategy
  -> m Double) -> Candidate strategy -> m (Candidate strategy, Double)`, so
  objectives can run stateful simulations (`ST s`) while each solver threads
  its own seeded pure RNG (reproducible runs, no random-monad constraint on
  the objective). Ships two strategies: `ExchangeAlgebra.Optimize.Annealing`
  (simulated annealing over an arbitrary candidate type; configurable cooling
  schedule / neighbor move / acceptance rule, with `geometricCooling` and
  `metropolis` provided) and `ExchangeAlgebra.Optimize.GA` (real-coded genetic
  algorithm over `Vector Double` chromosomes; tournament selection, uniform
  crossover, per-gene Gaussian mutation, elitism, optional per-gene bounds,
  `defaultGAConfig`). Further strategies (DE/PSO/CMA-ES) are added by giving
  a new strategy type a `Solver` instance — no interface change. Objective
  values must be finite (fail-fast on NaN/Infinity) and configurations are
  validated up front; solvers never re-evaluate an already-scored candidate.
  This subsystem is a generic numeric layer independent of the
  redundant-algebra core.

- `circulant` (`ExchangeAlgebra.Simulate.Network`): a deterministic circulant
  (ring-lattice) generator where each buyer draws its `min k (N-1)` suppliers
  from the `k` nodes that follow it cyclically. Needs no `StdGen` and is built
  in `O(kN)` (never scans the `O(N²)` ordered pairs), so it stays usable at the
  `N` a market-scale run needs — unlike `kRegular` / `erdosRenyi`, whose
  generation cost is `O(kN²)` / `O(N²)`. `|E| = min k (N-1) · N` exactly, with
  no duplicate or self edges. Doctested.

- `ExchangeAlgebra.Assist` (new module): deterministic assistance layer for
  LLM-facing workflows. `describeAccount` / `allAccountInfos` expose per-account
  metadata (division and home side derived from `classifyAccountDivision` /
  `whichSide`; English/Japanese names and description machine-generated from
  the `AccountTitles` Haddock in `Element.hs` via
  `tools/gen-assist-descriptions.py`, checked in as
  `ExchangeAlgebra.Assist.Descriptions` and guarded by a drift test);
  `suggestAccounts` gives deterministic keyword lookup (no LLM); and
  `explainEntryError` / `explainJournalErrors` / `explainSourceErrors` render
  `Convert.Checked` rejections as structured one-line feedback for retry loops.

- `ExchangeAlgebra.Convert.Checked` (new module): checked construction for
  externally generated (LLM/runner) journal entries. `checkedEntry` /
  `checkedEntryText` reject empty entries, wildcard `Side`/`AccountTitle`,
  non-positive amounts and debit/credit imbalance at construction time
  (errors accumulate as `NonEmpty EntryError` with 0-origin posting indices);
  `checkedJournal` additionally pre-scans txid duplicates (`DuplicateTxId`)
  before notes are merged into the `Journal`; `reconcileSources` performs
  source-coverage reconciliation (missing / unknown txid / amount mismatch)
  between input transactions and the note-indexed journal. Balance uses the
  new `exactBalanced` (strict `==` over `norm . decL` / `norm . decR` — the
  exact-equality predicate is closed under `(.+)`, unlike the tolerance-based
  `balance`). Accepted values are built with `journalFromSides`, so the
  unchecked path's semantics are unchanged. Property tests (accept-iff,
  equivalence, submonoid closure, duplicate rejection, reconciliation) and
  doctests included.

- `stepBackWith` / `spillDeleteDecision` (`ExchangeAlgebra.Simulate`): the
  eviction-window arithmetic and the per-chunk delete decision are now pure,
  exported, unit-tested functions — the __single source__ of "which term range
  is evicted" (design-review C4). Previously the same logic lived inline in
  three places: the classic `runSimulationWithSpill` loop (`backBy` +
  `deleteRangeForChunk`), `Simulate.Lite`'s retention loop (`backByTerms`),
  and implicitly behind the `policySpillOptions` bridge. Both engines now call
  the shared functions (classic passes `prevTerm`, Lite passes `pred` — each
  engine keeps its own notion of "previous term"); behaviour is unchanged and
  the decision table is pinned by tests.

- Pure row builders for the legacy CSV writers (design-review C7): `bsRows`,
  `plRows`, `journalRows`, `accountLedgerRowsJournal` and
  `compoundTrialBalanceRows` are the pure counterparts of `writeBS` /
  `writePL` / `writeJournal` / `writeAccountOfJournal` /
  `writeCompoundTrialBalance`, which are now thin `writeCSV` wrappers around
  them — same "pure `*Rows` + IO wrapper" shape as `worksheetRows` /
  `postClosingTrialBalanceRows` / `accountLedgerRows`. Output is bit-for-bit
  unchanged (pinned regression tests were added before the refactor and pass
  unmodified after it); each new builder carries Haddock + doctests.

- `BaseClass` instance for 7-tuples (design-review C5): `Element` and
  `AxisDecompose` already had 7-tuple instances, so every Element tuple arity
  is now also usable as a base.

- `examples/audit-eval`: full 23-task pilot suite (representative tasks #4–#23
  converted to `tasks/*.json` with per-task `ea_account_map`) and a v2 task/output
  contract (`TASK-FORMAT.md`) extending the runner beyond journal-posting arrays:
  `derived` (statement figures), `findings` (audit defect detection with a fixed
  type taxonomy), `decision` (classification calls) and judgment escape-hatch
  scoring. Scoring is collision-aware (many-to-one `ea_account_map` entries are
  matched via candidate sets disambiguated by amount) and the finding-type
  vocabulary is normalized — both fixes remove name-translation measurement bias
  from arm comparisons (same rationale as the P1 account-map fix). Runner gains
  multi-seed runs (`--seed 0-4`) and an append-mode `metrics/summary.csv`.
  Follow-up (seed-0 forensics): the exact `derived` key vocabulary is now
  injected into every arm's output contract (keys are the output schema, not
  the answer — third P1-family fairness fix) and the codex timeout is raised
  to 360s (largest task returned empty at 240s).
  Contract v2.1: canonical printing is now harness-owned —
  `harness/EmitCanonical.hs` projects the postings JSON from the EA algebra
  value itself (same `whichSide` convention as the oracle, roundtrip-closed)
  and the arm-A/D minimal instruction forbids hand-assembled JSON. This pins
  the printing seam observed in pilot seed 0 (a correctly-built journal
  misprinted by model-written string code) to the measurement layer; the
  versioned SKILL treatment artifact is untouched.
  Examples-only change; no library code touched.

- `examples/audit-eval` Track S Land 3: arm Aprime now uses the
  `LoadChecked.hs` checked-loader gate with raw/rich retry feedback, arm A can
  select `SKILL-ea-v2`, and runner metadata records effective model / CLI
  versions automatically. Examples-only change; no library code touched.

- `examples/audit-eval` Track S Land 4: `gen/` now has a deterministic generator
  fairness pass, independent pandas/EA double-oracle adoption via
  `DeriveEA.hs`, explicit defect injection checks, and `make_suite.py` for
  generated suites. Examples-only change; no library code touched.

- `ExchangeAlgebra.Simulate`: the `StateSpace` methods `initT` / `lastT` are now
  exported. Their Haddock has always described them as customizable (they let an
  instance override the simulation start/end term, and `runSimulationWithSpill`
  consults them), but the export list only exposed
  `StateSpace(event, randomSeeds)`, so external instances could not actually
  override — or even name — them. Purely additive.

- `CumulativeTranslationAdjustment` `AccountTitles` constructor (為替換算調整勘定,
  classified as `Equity`) — the equity/OCI account that absorbs the foreign-currency
  translation adjustment. This is the only library primitive that foreign-currency
  translation requires: the translation itself (relabel a `CountUnit` currency axis
  and rescale the value at the exchange rate) is expressed with the existing
  `ExchangeAlgebra.Algebra.Transfer` machinery (`createTransfer`/`.->`/`|%`), and the
  CTA residual is posted from the caller, so no new translation operator is added to
  the library. Classification and exhaustiveness tests updated.

- `ExchangeAlgebra.Bookkeeping.priorPeriodErrorCorrection` — prior-period error
  correction builder (前期修正/誤謬訂正): the current-period portion is charged to
  an expense account while the prior-period portion is routed, by construction, to
  `RetainedEarnings` (IAS 8 / ASC 250-10 retrospective restatement), so the caller
  cannot misbook the prior-period amount to the income statement. Adds the
  `AmortizationExpense` `AccountTitles` constructor (無形固定資産償却費, Cost;
  distinct from tangible-asset `Depreciation`); classification and exhaustiveness
  tests updated. Balanced by construction (`norm (decL x) == norm (decR x)`).

- `ExchangeAlgebra.Bookkeeping` — equity-method closing builders
  (`equityMethodEarningsEntry`, `equityMethodDividendEntry`, `equityMethodEntries`)
  plus `equityMethodBalance`, the engine-recomputed carrying amount
  (`norm . bar . projByAccountTitle InvestmentInAssociate`), so the
  `cost + Σ(share of NI) − Σ(dividends)` roll-forward of an equity-method
  investment is correct-by-construction rather than hand-written. Adds two
  `AccountTitles`: `InvestmentInAssociate` (関係会社株式, Asset/Fixed) and
  `EquityInEarningsOfInvestee` (持分法による投資利益, Revenue). All builders are
  debit-credit balanced (`norm (decL x) == norm (decR x)`); the exhaustiveness
  and classification unit tests cover the two new titles.

- `ExchangeAlgebra.Algebra.netPairMapBy` — the pair read-out of the paper's
  class-net operator ν_κ (`def:class-net`, notes Def 2.7). For each bucket key it
  returns a non-negative `(notTotal, hatTotal)` pair, built by netting each base's
  two sides (bar-like cancellation) and summing the residual on the winning side
  — `(Σ_{n>h}(n−h), Σ_{h>n}(h−n))`. `balanceMapBy` is its signed-difference
  version: `balanceMapBy kf == fmap (\(n,h) -> n − h) . netPairMapBy kf`. Both
  components are non-negative, so `netPairMapBy` is well-behaved on non-negative
  value types (the `n − h` identity with `balanceMapBy` only holds on a signed
  type such as `Double`/`MoneyDecimal`). Single pass; redundancy is intentionally
  reduced (named, not an implicit `bar`).

- `ExchangeAlgebra.Simulate.Lite` — `stageOf` / `StageTagged`: a note-tagged BSP
  stage whose note type is fixed to `(tag, t)` by construction. Each agent emits
  a bare `Alg v b`; the runner attaches the single note `(stTag, t)` in exactly
  one place (`runStage`), eliminating the write-site `alg .| (Tag, t)`
  duplication. Because the tag and any downstream `projWithNote [(tag, t)]` are
  now checked against the same constructor, a stringly-typed note mismatch is a
  compile error rather than a silently empty projection. `stageFor` / `stage` /
  the existing `StageFor` constructor are unchanged (purely additive: `Stage` is
  now a GADT with both constructors). Multi-note stages (e.g. a closing stage
  posting both `(Closing, t)` and `(Carryover, t+1)`) keep using `stageFor`,
  which still returns a fully general `Journal`. Also adds `stageName`
  (`stName` for `StageFor`, `show stTag` for `StageTagged`) for stages that may
  be either constructor. Determinism is unaffected — the per-agent `StdGen` is
  still derived from `(specSeed, termIx, stageIx, agentIx)` only, and the note
  attachment is a pure post-transform.

- `ExchangeAlgebra.Write` — three closing-document CSV writers (and their pure
  row-builders, for testing/composition). `writeWorksheet` / `worksheetRows`
  render an 8-column worksheet (8 桁精算表): per account title, the
  trial-balance, adjustment, profit-&-loss and balance-sheet debit/credit column
  pairs. The trial-balance and adjustment columns come from the pre-adjustment
  ledger and the adjustment entries respectively; the final balance of
  `pre .+ adj` is routed by `whatDiv` (Cost/Revenue → P/L, Assets/Liability/
  Equity → B/S). The closing row is the profit/loss balancing figure
  (当期純利益/純損失) placed so each statement's debit/credit pair balances; since
  `norm` is a homomorphism the P/L and B/S imbalances coincide — that equality is
  the worksheet's own self-check (it is *not* enforced: an inconsistent input
  still emits both figures so the discrepancy stays visible).
  `writePostClosingTrialBalance` / `postClosingTrialBalanceRows` produce a
  post-closing trial balance (繰越試算表) listing only the real
  (Assets/Liability/Equity) accounts — nominal Cost/Revenue accounts are excluded
  by construction. `writeAccountOf` (previously an unimplemented stub) and the new
  `writeAccountOfJournal` / `accountLedgerRows` render the general ledger
  (総勘定元帳 / T-account): every posting on a title is listed individually in
  date order with **no aggregation**, so the redundant sequence is preserved as
  the audit trail (`writeAccountOfJournal` additionally carries each posting's
  note/摘要). The trial-balance and post-closing balances use an explicit
  `diffRL` netting (the same aggregation as `writeCompoundTrialBalance`); no
  implicit `bar`. All three have Haddock doctests on their pure row-builders and
  unit tests (worksheet self-check P/L diff == B/S diff == net income; post-closing
  TB excludes Cost/Revenue; ledger preserves posting count).

- `ExchangeAlgebra.Bookkeeping` — a new module of *closing-adjustment entry
  builders* (決算整理仕訳) at the 日商簿記 3 級 level. Unlike
  `ExchangeAlgebra.Algebra.Transfer` (which relabels existing ledger balances),
  these record fresh postings whose amounts come from outside the ledger
  (period-end inventory, estimated allowance, depreciation, tax). The base
  polymorphism is absorbed by a caller-supplied injection `type MkBase b = Hat ->
  AccountTitles -> b`. Builders: `cogsAdjustmentEntries` (cost of goods sold under
  the periodic/3-account method, 売上原価算定), `depreciationIndirectEntry` /
  `depreciationDirectEntry` (減価償却, 間接法/直接法), `allowanceReplenishmentEntry`
  (差額補充法) / `allowanceResetEntries` (洗替法) for the allowance for doubtful
  accounts, the four deferral/accrual entries (経過勘定) `prepaidExpenseEntry` /
  `unearnedRevenueEntry` / `accruedRevenueEntry` / `accruedExpenseEntry`,
  `consumptionTaxSettlementEntry` (消費税確定; a tax refund `received < paid` is
  rejected as out of 3-級 scope), and `corporateTaxInterimEntry` /
  `corporateTaxSettlementEntries` (法人税等の中間納付・確定). `reversingEntry` is a
  vocabulary alias for the Hat operation `(.^)`: it expresses the opening
  reversing entry (再振替仕訳) and the correction entry
  (訂正仕訳 = `reversingEntry wrong .+ correct`), whose redundant sequence is
  retained as an audit trail of the correction. Every builder is constructed only
  with the smart constructor `(.@)` (zero amounts normalise to `Zero`,
  negative/non-finite amounts are rejected) and is debit-credit balanced
  (`norm (decL x) == norm (decR x)`), verified as a QuickCheck property for all
  builders plus unit tests on representative lecture figures.

- `AccountTitles` — added `ReversalOfAllowanceForDoubtfulAccounts` (貸倒引当金戻入,
  `Revenue`), the credit counterpart released by the allowance builders when the
  estimate is below the current balance. Appended before the `AccountTitle`
  wildcard (existing ordinals preserved) and added to the classification
  exhaustiveness table.

- `AccountTitles` — added ~49 account titles at the 日商簿記 3 級 (elementary
  Japanese bookkeeping) level, each with an English/Japanese bilingual Haddock
  gloss: assets (e.g. `PettyCash`, `NotesReceivable`, `MerchandiseInventory`,
  `Land`, `Fixtures`, `Patent`, `CashOverShort`), liabilities (e.g.
  `AccountsPayable`, `NotesPayable`, `BankOverdraft`, `AllowanceForDoubtfulAccounts`,
  `AccumulatedDepreciation`), equity (`LegalRetainedEarnings`), costs (e.g.
  `ProvisionForDoubtfulAccounts`, `BadDebtLoss`, `PaymentFees`, `MiscellaneousLoss`,
  `CorporateIncomeTaxes`, `CommunicationExpenses`) and revenues (e.g.
  `GainOnSalesOfFixedAssets`, `RecoveryOfBadDebts`, `MiscellaneousIncome`).
  Valuation accounts (`AllowanceForDoubtfulAccounts`, `AccumulatedDepreciation`)
  are classified under `Liability` (B/S contra-asset presentation deferred to the
  Write side), keeping values non-negative and the Hat/Not structure intact. New
  constructors are appended before the `AccountTitle` wildcard so existing
  `Enum`/`Binary` ordinals are preserved. `AccountTitles` now also derives
  `Bounded`. A new exhaustiveness table test pins `(whatDiv, whichSide,
  fixedCurrent)` for every constructor and fails if a new title is left
  unclassified, guarding against `classifyAccountDivision`'s wildcard silently
  treating a title as `Assets`. This also completed the `fixedCurrent` cases for
  the pre-existing `AccountsReceivable` (now `Current`) and `Sales` (now `Other`),
  which previously had no case and would `error` on a non-exhaustive pattern.

- `ExchangeAlgebra.Simulate.Policy` — a declarative vocabulary for managing the
  size of a long simulation's audit trail, decided once when the ledger is
  built. A `LedgerPolicy` bundles three orthogonal choices: **retention**
  (`Retention` = `RetainAll` | `RetainRecent Int`, the resident-history window),
  **spill** (`spillTo :: Maybe FilePath`, an optional binary backup of evicted
  terms), and **compaction** (`Compaction` = `FullAudit` | `CompressClosedTerms`).
  `CompressClosedTerms` applies `compress` only to *closed* terms — it is
  norm- and balance-preserving (only the within-term posting sequence is
  collapsed) and the in-progress term always keeps its full audit trail; per the
  prohibition on implicit `bar`/`compress` it is reachable only through this
  named policy. The term a `Note` belongs to is fixed by the `HasTermAxis` class
  (type family `TermOf n`, method `termOf`): **the term is the last component of
  the Note**, with shipped `(e, t)` and `(e1, e2, t)` instances and a one-line
  instance for bespoke Notes. Two bridges connect the policy to the existing
  spill engine: `policySpillOptions` builds a binary `SpillOptions` for the
  classic `runSimulationWithSpill`, deriving the per-chunk extraction and the
  eviction range from `termOf` (replacing the ~20 lines of hand-written
  `filterWithNote` plumbing), and `restoreLedger` rebuilds the full ledger from a
  spill file plus the in-memory remainder (lossless with an exact value type).
  `defaultLedgerPolicy` (`RetainAll` / `Nothing` / `FullAudit`) is exactly the
  classic full-audit behaviour. **Data-loss note:** `spillTo = Nothing` together
  with `RetainRecent w` *discards* evicted terms with no backup — documented
  prominently. `Simulate.Lite` gains `runLiteWithPolicy`, an `IO` runner whose
  BSP loop is identical to `runLite` but which, at each term boundary, compresses
  closed terms (under `CompressClosedTerms`) and evicts/spills out-of-window
  terms (under `RetainRecent`); under `defaultLedgerPolicy` it is observationally
  equal to `runLite`. The existing `SpillOptions`, `runSimulationWithSpill` and
  `runLite` are unchanged.

- `ExchangeAlgebra.Simulate.Network` — separates a market's *trade relation*
  from its *technology*. `TradeNetwork k` is a sparse directed "who may supply
  whom" graph (edge `(i, j)` = supplier `i` of buyer `j`); `InputCoefficients
  k v` is the matching sparse, buyer-major coefficient table, with the invariant
  `supp(A) ⊆ edges(G)` enforced by the smart constructors. All three types are
  abstract (no exported constructors) and every read-out (`nodes`, `edges`,
  `suppliersOf`, `buyersOf`, `inputsOf`, `coefficient`, `edgeCount`) is returned
  in ascending order, so results never depend on hash-table iteration. The key
  operation `sigmaEdges g f` runs the familiar Σ notation over a network's
  *edges* (cost `O(E)`) instead of over all ordered pairs (`O(N²)`); with
  `completeNetwork` the two coincide exactly
  (`sigmaEdges (completeNetwork ks) f == sigma2When ks ks (/=) f`), so an
  all-pairs model can adopt a sparse market structure without changing its Σ.
  Includes deterministic network generators driven by an explicit `StdGen`
  (`completeNetwork`, `kRegular`, `erdosRenyi`, `scaleFree` Barabási–Albert,
  `sectorBlock` stochastic-block), random coefficient generation with an
  optional Hawkins–Simon (productivity) column-sum rescale (`randomCoefficients`
  / `CoefOptions` / `defaultCoefOptions`), long-form table and dense-matrix
  ingestion (`networkFromTable`, `coefficientsFromTable`, `fromCoefficientMatrix`),
  and a tiny dependency-free CSV reader for the fixed `from,to[,coef]` schemas
  (`parseEdgeCsv`, `parseCoefCsv`, `readEdgeCsv`, `readCoefCsv`). Smart
  constructors reject self-loops, duplicate edges, out-of-network coefficients,
  negative coefficients, and duplicate coefficients with a `NetworkError`
  (nothing is silently merged or dropped). The network types carry `Show` / `Eq`
  / `NFData`. No `Updatable` instance is provided (the `Updatable` functional
  dependency makes one impossible for the library to supply); the Haddock shows
  a three-line `UpdatableSTRef` wrapper for the classic `Simulate` engine, and
  in `Simulate.Lite` a network is simply a `carry` field.

- `ExchangeAlgebra.Simulate.Lite` — a small, additive front-end for agent-based
  bookkeeping simulations with bulk-synchronous-parallel (BSP) semantics. It
  sits beside the classic `ExchangeAlgebra.Simulate` (unchanged) and removes
  most of its boilerplate: the world is a product-only higher-kinded record
  (`HK` role tags `InitT` / `RefT s` / `SnapT`; only `deriving Generic`
  needed — no per-field `Updatable` instances, no newtype wrappers), term
  boundaries are declared per field (`carry` / `resetEach` / `updateEach`),
  the term range and seed are runtime values (`SimSpec` via `mkSimSpec`), and
  stages are pure functions from a read-only world snapshot to a `Journal`
  "message" (`stage` / `stageFor`). `runLite` drives the BSP loop: per stage
  it freezes the world once, runs every agent against that same snapshot
  (sequentially or with fixed-chunk parallelism, `Par`), merges the messages
  in one pass (via `sigma`) and commits them to the ledger; per-field rules
  fire once per term (regression-tested with a multi-stage model).
  Determinism: per-agent generators derive purely from
  (seed, term, stage, agent); with the exact `MoneyDecimal` value type the
  parallel and sequential runs agree exactly (tested), and with `MoneyDouble`
  a fixed schedule is run-to-run reproducible (tested). Note the BSP semantic
  difference from the classic engine: within a stage, agents cannot observe
  each other's same-stage postings (covered by a sentinel test). A minimal
  model is ~20 lines versus ~90 with the classic instances.

- `instance NFData (Journal n v b)` (shallow-structural, mirroring the `Alg`
  instance): forces the base/delta map spines and each contained `Alg`,
  leaving the lazily built axis indices untouched. Used by `Simulate.Lite`'s
  parallel stage evaluation; generally useful for `parMap rdeepseq` over
  journals.

- `ExchangeAlgebra.Algebra.decBy :: Ord k => (b -> Maybe k) -> Alg v b ->
  Map k (Alg v b)` — quotient decomposition (dec_κ): one-pass partition of an
  algebra along the classes induced by a classifier on the full `HatBase`.
  Each class is the redundancy-preserving restriction of the input (no `bar`,
  no aggregation); the pieces reconstruct the input and `norm` is additive over
  classes. Generalizes the Deguchi-Nakano (1986) decomposition operators
  (`decR`/`decL`/`decP`/`decM` are two-class special cases). Replaces per-class
  projection loops (`O(classes * query)`) with a single `O(entries)` fold.
  `bar` commutes with `decBy` componentwise iff the classifier does not
  distinguish Hat/Not (side-sensitive classifiers encode a semantic choice;
  covered by sentinel tests).

- `ExchangeAlgebra.Algebra.postFromNetBy :: Ord k => (b -> Maybe k) ->
  (k -> v -> Alg v b) -> Alg v b -> Alg v b` — fused classify→net→post:
  `bar` (explicit in the name), classify the netted entries, sum per class, and
  bulk-merge the generated postings. The "shortage detection → purchase
  postings" pattern becomes one call running in a single pass (the naive
  all-pairs formulation costs `O(N^2)` per-pair queries).

- `ExchangeAlgebra.Journal.decTo :: Note n' => (b -> Maybe n') -> Alg v b ->
  Journal n' v b` — quotient decomposition landing on the `Journal` (the
  library's native keyed family of algebras, paper Definition 12), keeping the
  per-key result inside the algebra vocabulary (no external `Map` in the
  result). Same redundancy/norm guarantees as `decBy`; `plank` cannot carry a
  class (such entries join the residual).

- Quotient-decomposition axiom property tests (reconstruction, norm additivity
  over classes, componentwise `bar` commutation for base-part classifiers) plus
  fixed sentinels for the side-sensitive non-commutation cases (`isHat`,
  `whichSide`) and for `mapBasePart`'s coarsen-vs-net order sensitivity.

- `bench-core` gains a `dec/*` group: per-key reporting A/B between the naive
  per-key wildcard `balanceBy` loop, `balanceMapBy`, `decBy`+`norm`, and
  `postFromNetBy` at K=200/1000 keys.

- `projCapitalStock` (`ExchangeAlgebra.Algebra`): now implemented (previously an
  `undefined` placeholder that crashed when called, audit R3). It projects the
  credit-side entries classified under the `Equity` division — the equity
  counterpart of `projCurrentLiability` / `projFixedLiability`. Includes a Haddock
  doctest.

- `ExchangeAlgebra.Convert` — a new dependency-free (Text only) input-conversion
  core that turns external `(side, account-name, amount)` postings into exchange
  algebra `Alg` terms. `parseAccountTitle` matches a name (case-, whitespace- and
  symbol-insensitively via `norm`) against the canonical English constructor names
  plus a Japanese-label / abbreviation alias table built from the
  `ExchangeAlgebra.Algebra.Base.Element` bilingual Haddock; unknown names and the
  wildcard `AccountTitle` are rejected (`UnknownAccount`), and a label shared by
  several accounts (e.g. `準備預金` for both the asset and liability side of reserve
  deposits, or `通信費` for `CommunicationExpenses`/legacy `Commutation`) is
  rejected as `AmbiguousAccount` with the candidates listed — a correct-by-
  construction guard against hallucinated or under-specified accounts. `parseSide`
  parses debit/credit; `markerForSide` derives the `Hat`/`Not` marker from the
  library's own `whichSide` (so the debit/credit rule is never duplicated);
  `postingFromSide` / `journalFromSides` build the algebra terms through the
  non-negative smart constructor `.@`. Serialization glue (JSON/XML) deliberately
  stays out of the core. Haddock doctests assert the Debit/Credit ↔ Hat/Not
  mapping explicitly.

- `ExchangeAlgebra.Convert.Csv` — a fixed-schema, dependency-light
  (Text + scientific) reader for general journal CSV: a header
  `side,account,amount` with an optional trailing `note` column, one posting per
  row. `parseJournalCsv` folds the rows into a single `Alg` term;
  `parseJournalCsvWith` takes a caller-supplied amount parser (keeping the value
  type open); `parseNotedJournalCsv` returns `(side, account, value, note)` rows
  so a caller can key a `Journal` by the note. `scientificAmount` parses a
  non-negative decimal via `Data.Scientific` exactly through `toRational` (so
  exact-decimal value types keep precision). Blank lines and `#` comment lines
  are skipped and fields are trimmed; unknown/ambiguous accounts, bad sides,
  malformed headers/rows and negative or non-numeric amounts are rejected through
  the `ConvError` channel (now extended with `MalformedCsv` and `BadAmount`).
  This is the read counterpart of the `ExchangeAlgebra.Write` ledger/report CSV
  writers (writing is not handled here). The minimal CSV splitter intentionally
  mirrors the one in `ExchangeAlgebra.Simulate.Network` (`parseEdgeCsv` etc.); a
  future refactor could share it, but the two stay independent for now to avoid a
  cross-module dependency. A QuickCheck round-trip property (render → parse is
  exact for `MoneyDecimal`) and structural-rejection unit tests are included.

- `ExchangeAlgebra.Value` with `MoneyDecimal`, an exact non-negative decimal value type
  (wraps `Data.Decimal.Decimal`) usable as the `v` in `Alg v b` / `Journal n v b`.
  Numeric literals work directly (derived `Num`/`Fractional`). Because decimal addition
  is exact and associative, `norm` / `bar` results are independent of construction order
  (unlike `Double`). Ships `bankersRound` (round-half-to-even, the unbiased financial
  default) and `ceilingRound`. New dependency: `Decimal`.

- `ExchangeAlgebra.Value.MoneyDouble`, a zero-cost `newtype` over `Double` for a fast
  IEEE-754 value type that is *typed* as money (distinct from bare `Double`
  coefficients / random draws) yet has identical speed and precision. All its
  instances (`HatVal`/`Nearly`/`Binary`/`Hashable`/`NFData`, plus the numeric
  classes) are derived from the bare-`Double` instances via `deriving newtype`, so —
  like `MoneyDecimal` — there are no orphan instances. Its subtraction is signed, so
  the negative intermediates that arise inside `bar`/`(.-)` are fine (unlike
  `Number.NonNegative.Double`, whose `(-)` errors on a negative result, making it
  unusable as a value type). Measured: `MoneyDouble` matches `MoneyDecimal` exactly
  where a result is exactly representable but diverges in the last ULP at scale, and
  runs ~5–7× faster with ~15% less memory than `MoneyDecimal` in `sim2`.

- `ExchangeAlgebra.Algebra.mapBasePart :: (BasePart b -> BasePart b') -> Alg v b ->
  Alg v b'` — relabel the base part of every element while preserving the Hat/Not
  structure and the redundancy (ordered sequences); colliding targets are
  concatenated, so `norm` is preserved. (Hat is left untouched; the type expresses
  the Hat/Not-preserving intent, per the redundant-algebra design.)

- `ExchangeAlgebra.Algebra.balanceMapBy :: (BasePart b -> Maybe k) -> Alg v b ->
  Map k v` — the bucketed form of `balanceBy`: nets each entry by a key projected
  from its `BasePart` (Not adds, Hat subtracts) in a single fold, replacing one
  wildcard projection per key. For per-key reporting (e.g. per-company stock /
  profit) this turns `O(keys * entries)` into `O(entries)`; the result equals the
  per-key `balanceBy` up to floating-point reassociation. Returns *signed* net
  balances, so use a signed value type (`Double` / `MoneyDouble` / `MoneyDecimal`).

- README gains a "Choosing a value type" section (Double vs MoneyDecimal comparison
  table, the simulation boundary pattern, the large-scale precision×memory
  trade-off, and the `fromList` ordering contract).

### Changed
- Cabal flag `visualize` (manual, default on) now guards
  `ExchangeAlgebra.Simulate.Visualize` and the `Chart` / `Chart-cairo`
  dependencies. `stack build --flag exchangealgebra:-visualize` builds the
  accounting algebra without a cairo toolchain; the default build and the
  bundled examples are unchanged.
- Resolve Japanese presentation and LLM-facing names through the cleaned
  `asLabelJa` registry field, with the JCCI `AdvancesReceived` override kept as
  `契約負債`. Mark `EquityInEarningsOfInvestee` and
  `CumulativeTranslationAdjustment` as consolidation-only and contextual.
  Replace catch-all branches in all five account-semantics classifiers with
  exhaustive constructor cases.

- Clarify that the retained `GrossProfit` and `OrdinaryProfit` constructors and
  transfer functions are historical SNA/simulation coordinates, not complete
  JGAAP subtotal definitions. Their ordinals and Binary tags remain unchanged;
  see `docs/migration-0.5-derived-metrics.md`.

- Correct `NonControllingInterests` metadata to `ConsolidationOnly`,
  `ContextualPresentation`, and `AttributionAccount`, preventing the
  consolidated balance-sheet coordinate from being posted to an individual
  entity's ordinary journal.

- Correct `HeadOfficeCurrentAccount` (`本店`) from `Assets` to `Liability` to
  match its credit balance in branch books.

- The bar-netted projection read-outs are renamed so the netting is visible in
  the name (design-review C2): `projNorm` → `projNetNorm`
  (`ExchangeAlgebra.Algebra`), `projWithBaseNorm` → `projWithBaseNetNorm` and
  `projWithNoteNorm` → `projWithNoteBaseNetNorm` (`ExchangeAlgebra.Journal` —
  the last also gains the missing `Base` in its name: it takes note AND base
  queries). The old names remain as __deprecated aliases__ (removal planned
  for 0.6), so this is warning-only, not immediately breaking.

- `ExchangeAlgebra.Convert`: the account-name normaliser is renamed
  `norm` → `normalizeTitle` (the module has never been released, so no
  migration burden). The old name collided with the core value-domain
  homomorphism `ExchangeAlgebra.Algebra.norm` — a fundamental, entirely
  unrelated operation — and would have made `norm` ambiguous in any module
  importing both unqualified.

- `Liner` (`ExchangeAlgebra.Algebra`) and `Journal` (`ExchangeAlgebra.Journal`):
  added Haddock documenting the constructor invariants (the internal axis/index
  cache fields must stay consistent with `_realg` / `_jBase`/`_jDelta`, or the
  wildcard projection / `filterByAxis` paths return wrong answers silently). Build
  values via the smart constructors (`fromList`/`fromMap`/`(.@)`/`(.|)`), not by
  applying the data constructors directly (audit R11, doc only).

- `Updatable.copy` / `Updatable.modify` default methods
  (`ExchangeAlgebra.Simulate`): the unoverridden default now raises a diagnostic
  `error "Updatable.copy: default method not overridden"` (resp. `modify`) instead
  of bare `undefined` (audit R4). Behaviour-equivalent for any instance that
  overrides them.

- `Liner` `_bpToId` / `_nextBpId` fields (`ExchangeAlgebra.Algebra`): no longer
  built by `linerFromMap` (they were never read; reserved for a dormant
  incremental-id scheme). They are now lazy `error` poison — forcing either throws
  with an explanatory message — guarded by a regression test (audit R3/F6).
  Normal projection (concrete and wildcard) never forces them.

- Examples: `marketEx1`\/`marketEx1d` (`examples/market/MarketModel.hs`): the model note
  is now an ADT `MTag` (`PlankTag | Trade | Production | Report | Closing |
  Carryover`) instead of a `String` tag, so `MNote = (MTag, Int)`. The event tag
  is written (`.| (Trade, t)`) and read (`projWithNote [(Trade, t)]`) by the same
  constructor, so a typo is now a compile error rather than a projection that
  silently matches nothing. Behaviour and all numeric results are unchanged (the
  default N=20 run still reports `norm = 8587.1027`, shortage `200.0000`). The
  test suite's Market mirror gains the same-shape `MktTag`. The `Note` class
  Haddock now documents the "prefer an ADT note over `String`" guidance with the
  `MTag` sketch. No library API change.

- Performance: `Journal` append (`.+` / `addJournal`): two redundancies removed on the hot
  commit path (audit R5 = ROAD_MAP P1b). `toMap` no longer copies when either
  the base or the delta layer is empty, and appending to an *existing* note key
  no longer re-inserts the (unchanged) note-axis index entry. Values, sequence
  order (audit trail) and the public API are unchanged; the whole test suite
  passes unmodified. Measured: append micro-benches alloc -29%/-36%
  (base-only / same-note), end-to-end simulation alloc -4.5% with a small
  wall-clock improvement.

- Performance: `Write` trial-balance documents (`writeCompoundTrialBalance`,
  `worksheetRows` / `writeWorksheet`, `postClosingTrialBalanceRows` /
  `writePostClosingTrialBalance`): aggregation changed from O(a·s) (a full
  `projByAccountTitle` scan per distinct account title) to a single
  `foldEntries` pass O(s) (audit R6). Per-title gross debit/credit totals are
  accumulated **non-negatively** (preserving the value-domain invariant) and
  netted with the same `diffRL`/tolerance rule, so the CSV output is
  byte-identical (verified by the existing doctests/unit self-checks and an
  ebex6/7/9 byte-diff). Measured: trial-balance row build a=50/s=10⁴ wall
  13.4 ms → 1.3 ms (~90% reduction, ~10× speedup).

- Performance: Concrete (non-wildcard) `proj` / `projNorm` no longer force/build the lazy axis
  index. The module is compiled `Strict`, so passing the index to the shared
  projection helper previously forced its full construction even for an exact
  single-base lookup that only needs a `Map.lookup`. The helper is now split into
  `projExactMap` (index-free) and `projWildMap` (uses the index), and callers
  dispatch on `haveWildcard` with the index fields bound lazily — so an exact
  projection is a plain `Map.lookup` and a wildcard projection still uses the
  index. Measured ~4× faster for repeated concrete projections over a large
  ledger (more for workloads that rebuild the projected algebra per query, e.g.
  per-company stock reporting). Results are unchanged; guarded by a poison-index
  regression test.

- Examples: The bundled bookkeeping and simulation examples (`elementaryBookkeepingEx1–5`,
  `simulateEx1`, `simulateEx2`) and the test suite's simulation now use the exact
  `MoneyDecimal` ledger value type, following the boundary pattern (ABM
  parameters/coefficients/random draws stay `Double` and convert at the ledger
  boundary; reported stocks/profits convert back). The numeric-method examples
  (`ripple/*`, `CGE`) intentionally stay `Double`, demonstrating the Double side of
  the selectable value type.

### Deprecated
- `Journal.insert`: deprecated alias of `replaceNotes`. The name suggested a
  redundant addition, but it replaces whole notes (left-biased) and is not
  `(.+)`.
- `projNorm` / `projWithBaseNorm` / `projWithNoteNorm`: deprecated aliases of
  `projNetNorm` / `projWithBaseNetNorm` / `projWithNoteBaseNetNorm` (see
  Changed — the old names concealed the bar-netting). Removal planned for 0.6.

- The `HatVal NN.Double` instance (`Number.NonNegative.Double`): deprecated
  since 0.5.0.0, removal planned for 0.6 (design-review C3). Its `(-)` errors
  on the negative intermediates that the algebra's netting produces, and
  `MoneyDouble` covers the same use case safely. GHC cannot attach `DEPRECATED`
  to an instance, so the notice lives in the Haddock (class + instance), the
  README value-type section, and here. All library doctests were migrated from
  `NN.Double` to `Double`; the value-type guidance is unified across the
  umbrella Haddock, the `HatVal` class doc and the README (`Double` /
  `MoneyDouble` = fast, `MoneyDecimal` = exact\/audited).

- `rounding` (`ExchangeAlgebra.Algebra`): the `NN.Double`-only whole-unit
  ceiling helper is deprecated in favour of the explicit, value-type-appropriate
  `ExchangeAlgebra.Value.ceilingRound` / `bankersRound` (which take a
  decimal-places argument and work on `MoneyDecimal`). No internal callers; the
  function itself is unchanged.

### Fixed
- `ExchangeAlgebra.Bookkeeping.corporateTaxSettlementEntries` now rejects
  `interim > total` (a corporate-tax refund position, out of 日商簿記 3 級
  scope) with a clear error, mirroring the guard style of its sibling
  `consumptionTaxSettlementEntry`; previously the negative `unpaid` leg hit
  the generic `(.@)` error (design-review C5).

- `classifyAccountDivision` (`ExchangeAlgebra.Algebra.Base`) is now total by
  explicit enumeration: the trailing catch-all `_ = Assets` was replaced with
  explicit `Assets` cases for the 19 legacy SNA/macro asset titles (`Cash`,
  `Deposits`, …, `GovernmentService`). Previously any __future__
  `AccountTitles` constructor added without a classification would have been
  silently classified as `Assets`; now a missing case fails loudly (pattern-
  match error, caught by the Bounded/Enum exhaustiveness test). No behaviour
  change for existing titles.

- `ExchangeAlgebra.Journal`: removed two GHC `RULES` that rewrote
  `norm (projWithBase bs js)` to `projWithBaseNorm bs js` (and the
  note-base analogue). The equation is __false__ whenever a query selects both
  sides of one base (e.g. a `HatNot` wildcard, or a list containing both
  `Hat:<b` and `Not:<b`): the left-hand side is the gross norm (sums both
  sides), the right-hand side is the bar-netted read-out (verified 14.0 vs 6.0
  on a both-sided base). Had the rule fired under `-O`, optimized and
  unoptimized builds would silently disagree. The Haddock of
  `projWithBaseNorm`/`projWithNoteNorm` — which claimed the false equivalence —
  now states the correct identity
  `projWithBaseNorm bs js == norm (map bar (projWithBase bs js))`, and a
  regression test pins both the netted and the gross value.

- `incomeSummaryAccount` (both `ExchangeAlgebra.Algebra.Transfer` and
  `ExchangeAlgebra.Journal.Transfer`): no longer crashes with
  "Non-exhaustive patterns" on a balanced ledger (audit R1). When credit and
  debit totals are equal, `diffRL` reports the wildcard `Side` and net income is
  zero; the function now returns its input unchanged (balanced ledger = identity)
  instead of matching only `Credit`/`Debit`. No `NetIncome`/`NetLoss` posting is
  added in this case (appending a zero posting is not an identity for `Journal`,
  since `(.|)` builds a singleton that drives version/compaction). A
  balanced-ledger regression test now runs every closing transfer.

- `proj` and `projNorm` (`ExchangeAlgebra.Algebra`): the multi-pattern paths now
  use __set semantics__ — a query list is treated as a set, so duplicate queries
  or an exact base overlapping a wildcard query select each posting __at most
  once__ (audit R7). Previously the multi-pattern path merged per-query results
  with sequence concatenation, double counting any posting matched by more than
  one query (the single-pattern path already returned only the first match, so
  the two paths disagreed). __Results of multi-pattern `proj`/`projNorm` can now
  differ__ from prior releases when a query list contains overlapping or
  duplicate patterns. The Haddock now documents the set semantics and the
  `projNorm bs x == norm (bar (proj bs x))` identity (bar-netted norm).

- `Simulate.Lite`: under `ParChunk`, the first stage message is now forced to
  normal form in the calling thread before the remaining messages are sparked.
  Previously all sparks raced to force the shared snapshot's lazily-built index
  structures, which could abort a run with a spurious RTS `<<loop>>`
  (intermittent, scheduling-dependent — the thunk graph is acyclic and
  sequential runs are unaffected). Results are unchanged (pure values;
  determinism tests assert exact equality). The library and example executables
  are also compiled with `-feager-blackholing`, as recommended by GHC for
  programs using sparks.

### Documentation
- Document the precise validity layers of the category-theory phase 1 laws for
  `mapBasePart`, `foldEntries`, and `postFromNetBy`, and pin them with QuickCheck
  properties plus raw-order and `bar` non-commutation counterexamples. This is
  documentation/test coverage only; library behaviour and exports are unchanged.

- `plank` in the note-query lists of `projWithNote` /
  `projWithNoteBase` / `projWithNoteBaseNetNorm` is now documented as a
  note-wildcard (the projection widens to all notes) — previously an
  undocumented behaviour (design-review C5). The underscore-prefixed
  `UpdatableSTRef` methods are documented as instance wiring, not user API.

- Same-base sequence order documented as __construction-path dependent__: the
  pairwise-union path (`fromList`/`mconcat`) and the bulk-merge path
  (`sigma`/`unionsMerge`) arrange the same multiset of postings in different
  orders (verified: `[3,1,2]` vs `[3,2,1]` for three same-base postings), which
  `Eq`/`Binary` observe and `Double` observes through the last ULP of
  `norm`/`bar`. The `Redundant` class, `sigma` and `unionsMerge` Haddocks now
  warn against comparing algebras built by different routes with `==` (compare
  after `compress`/`bar`, or use `MoneyDecimal`), and a characterization test
  pins the current orders so any change to either path is deliberate. Path
  unification is deferred to the 0.5.0.0 cleanup plan.

- `projCredit` / `projDebit` Haddock: documented that for `Alg` they coincide
  with the `Exchange` methods `decR` / `decL` respectively, and removed the
  stale guidance "use this instead of decL/decR when the base contains non-Enum
  elements" (it referred to long-removed `Enum`-based class defaults — and even
  named the wrong counterpart). The dead commented-out `credit`/`debit` class
  members in `ExBaseClass` were removed.

- `Exchange` class Haddock corrected: the class-level docs of `decR`/`decL` were
  __inverted__ relative to both the implementation and the Deguchi & Nakano
  (1986, Definition 2.16) convention. `decR` extracts the __credit__ side
  (R = Right = Credit, 貸方) and `decL` the __debit__ side (L = Left = Debit,
  借方) — the instance code was always correct; only the class Haddock (and thus
  the rendered Hackage docs) said the opposite. The `decP`/`decM` glosses were
  also reworded neutrally as the Hat-side/Not-side projections. Likewise the
  `HatBaseClass` Haddock no longer equates Hat/Not with credit/debit: the side
  of a posting is determined by the account division together with the Hat/Not
  label (`whichSide`).

- Module-reachability policy made explicit (audit R10): `ExchangeAlgebra.Bookkeeping`,
  `ExchangeAlgebra.Simulate.Lite`, `ExchangeAlgebra.Simulate.Network` and
  `ExchangeAlgebra.Simulate.Policy` are __designed to be imported directly__ and
  are intentionally not re-exported from the `ExchangeAlgebra` umbrella (re-export
  would collide names with the Algebra layer or with each other). This is now
  stated in the umbrella module's Haddock and in the README's import-patterns
  section.

- `Simulate.Lite.specLedger` Haddock now warns that the committed-ledger role is
  a model declaration conferred by the selector alone, not inferred from the
  product type: with more than one `Journal` field a wrong selector type-checks
  and fails silently (commits, eviction and the final projection all hit the
  wrong ledger). Recommends exactly one `Journal` field per world.

- README module overview now lists all 31 modules in seven layers and states
  that `Simulate.Lite` is the canonical simulation front-end while `Simulate`'s
  `Updatable` front-end is kept frozen for published examples; the
  `Simulate.Lite` module header no longer claims spill policies are out of
  scope.

### Internal
- Drop `mtl` from the library dependencies (no module in `src/` imports it);
  the test suite keeps it as a test-only dependency.
- `-Wall` warning cleanup (audit R9): removed unused imports\/bindings, silenced
  unused-match and name-shadowing warnings (mechanical, behaviour-preserving), and
  documented the remaining audited non-exhaustive patterns in place (168 → 27
  `-Wall` warnings; residual are doctest-only imports and out-of-scope categories
  such as orphans\/x-partial\/type-defaults). No public API change beyond exporting
  the previously-unused `balanceOf` (`ExchangeAlgebra.Write`) and `createTransfer`
  (`ExchangeAlgebra.Journal.Transfer`).

- Added a QuickCheck property suite (test dep `QuickCheck`) encoding the Definition 6
  redundant-algebra axioms (Hat involution, scalar on element, scalar distribution,
  norm additivity, norm homogeneity) and derived lemmas (bar idempotent, zero
  identity, associativity), plus two regression generalizations: `union` preserves
  the per-base net even for zero-valued singletons (the 0.4.1.1 bug class), and
  `MoneyDecimal` `fromList` per-base nets are construction-order independent.
  Journal-level properties: `norm` additivity, Hat preserves the note set, and
  per-(note,base) net is construction-order independent.

- Documented the Definition 6 axioms on the `Redundant` class and `norm` (Haddock
  only), cross-referencing the property suite.

- Benchmark/CI scaffolding: `simulateEx2` agent count and horizon are now
  env-configurable (`EA_LASTC`, `EA_LASTTERM`; defaults 200 / 100) for end-to-end
  scale benchmarking; added a GitHub Actions CI workflow (build + test + doctest,
  bench build-only).

## 0.4.1.2 - 2026-06-11

### Fixed
- `incomeSummaryAccount` (both `ExchangeAlgebra.Algebra.Transfer` and
  `ExchangeAlgebra.Journal.Transfer`) crashed with `Non-exhaustive patterns in
  case` on a **balanced ledger** (credit == debit, i.e. zero net income). In that
  case `diffRL` reports the wildcard `Side` constructor, which the
  `case dc of { Credit -> …; Debit -> … }` did not handle. The fix adds a `Side`
  branch that returns the input ledger unchanged (no `NetIncome` / `NetLoss`
  posting is appended when net income is zero). Note that appending a `Zero`
  posting is **not** a correct alternative for the Journal version, since it is
  not an identity there. Covered by the new `testIncomeSummaryBalancedAlg` and
  `testIncomeSummaryBalancedJournal` regression tests.

## 0.4.1.1 - 2026-06-07

### Fixed
- `union` (and therefore `(.+)` / `mappend` / `fromList`) misassociated a value
  with the wrong base when one operand was a **zero-valued singleton**. For
  `(v1:@b1) .+ (v2:@b2)` with `isZeroValue v1`, the result was `v2:@b1` — the
  surviving nonzero value relabeled onto the *zero posting's* base (symmetrically
  `v1:@b2`). A zero contributes nothing, so the result must be `v2:@b2` / `v1:@b1`
  (the nonzero value on its **own** base). The bug preserved `norm` (the total was
  unchanged) but corrupted **per-base projection** (`proj` / `projWithBase` /
  `balanceBy` / stock & profit queries): a value silently moved to a neighboring
  base. It was construction-order sensitive — ledgers that build explicit
  `0:@base` singletons via the raw `(:@)` constructor (e.g. sparsified input
  coefficients in agent-based simulations) would, depending on accumulation order,
  invent a phantom posting on an adjacent base. In the bundled simulation example
  this shifted a company's reported stock by up to ~30% over 100 terms. One-line
  fix in `Algebra.hs union`, covered by the new `testUnionZeroSingletonBase` test.

## 0.4.1.0 - 2026-06-06

### Added
- `nearlyEqScaled` — scale-aware approximate equality
  (`|x - y| <= atol + rtol * max |x| |y|`, with `atol = 1e-13`, `rtol = 1e-12`).

### Fixed
- `bases` ignored the `_notSide` Seq and iterated `_hatSide` twice
  (`src/ExchangeAlgebra/Algebra.hs`, regression existed since the introduction of the
  HashMap-backed `Liner` representation). The previous implementation produced
  `length (bases x) != length (vals x)` whenever the Hat-side and Not-side Seqs of any
  base had different lengths, dropped entries whose Hat-side Seq was empty, and
  duplicated Hat-side entries with the wrong label. A 1-character fix
  (`hs` → `ns` in the outer fold) restores the intended behaviour, covered by a
  new `testBasesNotSideRegression` unit test.

### Changed
- Reconciliation comparators (`bar` / `(.-)`, `balance`, `diffRL`, `barNormPair`) now use a
  scale-aware tolerance instead of a fixed `1e-13` absolute tolerance. **Behaviour change:**
  near-balanced values at large magnitudes no longer retain floating-point rounding noise as a
  spurious residual, and `balance` / `diffRL` no longer use exact `==` / `>` comparisons.
- `isNearlyNum` returns `False` (instead of raising `error`) when a NaN makes every ordered
  comparison fail, so non-finite inputs can no longer crash the check.

### Internal
- `Journal.toAlg` avoids materializing an intermediate `Map.elems base` list.
- Removed an unused `Control.Parallel.Strategies` import from `ExchangeAlgebra.Algebra`.

### Documentation
- Documented the spill-to-disk path (`runSimulationWithSpill` / `runScenariosWithSpill` with
  `SpillDeletePolicy`) as the recommended approach for constant-memory large-scale simulations,
  in the README and the `ExchangeAlgebra.Simulate` module header (example: `sim2`).
- Added the original axiomatic source (Deguchi & Nakano, *Axiomatic Foundations of Vector
  Accounting*, Systems Research 3(1):31–39, 1986) to the README References section.

## 0.4.0.0 - 2026-05-18

First release prepared for Hackage publication.

### Highlights
- First Hackage-ready release with full metadata and dependency version bounds.
- LSM-style `Journal` with spill-to-disk support for large simulations.
- Significant performance improvements across `Algebra`, `Journal`, and the simulation engine.

### Added
- LSM-style `Journal` data structure with spill engine and binary spill restore.
- Boilerplate-reducing helpers for state-space simulation
  (`UpdatableSTRef`, `UpdatableSTArray`, generalized `Updatable` instances).
- Sparse `sigma` map APIs (`sigmaFromMap`, `sigma2When`, `sigmaOnFromMap`, etc.)
  and a map-based fold path for purchases.
- `filterByAxis` for `Journal` and matching tests.
- `finalStockTransfer` fast path for both `Algebra` and `Journal`.
- `restoreJournalFromBinarySpill` and related spill utilities in `ExchangeAlgebra.Write`.
- New examples covering ripple-effect and stock simulations.
- Self-contained `writeCSV` / `csvTranspose` in `ExchangeAlgebra.Write`
  (removes the previous Git-only `csv-parser` dependency).

### Changed
- Refactored Journal axis indexing for nested-`IntMap` storage.
- Refactored `ExchangeAlgebra.Algebra` and the simulation pipeline for sparse processing.
- Optimized projection paths (`proj`, `projNorm`, `projWithBaseNorm`, `projWithNoteNorm`).
- Optimized `Hashable` / `Binary` instances and `Element` equality.
- Optimized the transfer engine and `finalStockTransfer` path.
- Refined `sim2` readability and stabilized build warnings.

### Fixed
- Debit/credit side classification and related accounting outputs.
- Various ripple seed comparison output mismatches.

### Build / packaging
- Bumped Stackage resolver from `lts-22.6` (GHC 9.6.3) to `lts-24.4` (GHC 9.10.2).
- Added explicit version bounds for all library dependencies.
- Added `synopsis`, `category`, and corrected `description` URL in `package.yaml`.
- Removed Git-only `csv-parser` (CSVParserT) dependency, replaced with
  in-tree `writeCSV` / `csvTranspose` in `ExchangeAlgebra.Write`.
- Added CSV write tests (`testCsvWriteCSV`, `testCsvTranspose`, etc.).
- Removed unused `bifunctors` dependency (dead import in `ExchangeAlgebra.Algebra`).

### Breaking changes
- Removed the non-hierarchical top-level module `ExchangeAlgebraJournal`.
  Use `ExchangeAlgebra.Journal` (for the Journal data model) or the
  top-level `ExchangeAlgebra` (for the Algebra data model) instead.
  The `ExchangeAlgebra` top-level remains an Algebra-layer umbrella; Journal
  users should import `ExchangeAlgebra.Journal` as the unqualified umbrella
  and qualify `ExchangeAlgebra.Algebra` as needed.

### Documentation
- Added extension guidance and import guidance to the Haddock of
  `ExchangeAlgebra.Algebra.Base.Element`, clarifying that user code should
  import `Element` via the higher-level umbrella modules.

## 0.3.0.0

- Integrated the high-speed `ExchangeAlgebra.Map` library into the main `ExchangeAlgebra` module.
- Added basic ripple-effect modules and Leontief inverse computation.
- Switched the internal data structure to `HashMap` for faster lookups.
- Added `ExchangeAlgebra.Simulate` and parallelized ripple effect computation.
- Generalized simulation functions and adopted `ST s` for `StateSpace`.
- Added `sigma` / `sigmaM` helpers for summation over indices.

## 0.2.0.0

- Added `ExchangeAlgebra.Journal` (Journal with summary support).
- Added initial example programs and test infrastructure.

## 0.1.0.0

- Initial development release of the Exchange Algebra library
  (algebraic description of bookkeeping based on Hiroshi Deguchi's framework).