feat(bookspec): GnuCash as the second engine, its differences settled (P13 step 5)
bookspec-gnucash implements the Engine trait over the oracle container (oracle/gnucash/books.py) and claims the rules whose examples ask only for balances. It passes BS-entry-3, BS-ledger-3, BS-statement-1 and BS-statement-2 and differs from three examples, each adjudicated from the sources and pinned by tests: GnuCash accepts an unbalanced entry and parks the difference in an Imbalance account (BS-entry-1 refuses it); it reads a credit of minus 100 as a debit (BS-entry-2 is a convention that removes the ambiguity); it rounds 10.005 to 10.01 silently (BS-ledger-1 is the owner's choice not to). The example stands in each case: GnuCash is a cross-check, not the authority. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HS8WZziDnyxunC23MUxrLp
This commit is contained in:
1 parent
40eb606bf3
commit
f8cd4abbce
6 files changed
+488
-1
No files matched your search
@@ -421,6 +421,16 @@ the 1st, among others) and `untagged_control_line` (a hand line on a
|
||||
receivables or payables control account, which only a document may post
|
||||
to: rules.md B-38's control guard).
|
||||
|
||||
The refusals of the ledger's own laws (BS-entry, BS-ledger, BS-period)
|
||||
are spelled `unbalanced` (debits differ from credits), `too_few_lines`,
|
||||
`negative_amount` and `zero_amount` (BS-entry-2), `finer_than_minor_unit`
|
||||
(an amount finer than the currency's smallest unit, BS-ledger-1),
|
||||
`parent_type_mismatch` (a child account of another type than its parent,
|
||||
BS-ledger-2), `already_reversed` (BS-ledger-6) and `period_closed` (an
|
||||
entry dated inside a closed period, BS-period-2). A refused entry may
|
||||
carry the amount the books refuse (zero or negative, in the amount's
|
||||
exact decimal spelling); an accepted one carries a positive amount.
|
||||
|
||||
`cash_flow` (rules.md B-14): the statement of cash flows for `[from, to]`.
|
||||
|
||||
| key | the value |
|
||||
@@ -453,6 +463,68 @@ event taken or refused as it says, on the books' own store. Each query is
|
||||
then checked by the crate that answers it (the table above), so the shape
|
||||
never rots either.
|
||||
|
||||
## The specification, the laws, the checks (P13 steps 4 and 5)
|
||||
|
||||
- `spec/` is the specification text: `00-model.md` (definitions, the
|
||||
model, the five laws, how an example is checked) and one file per area
|
||||
(`entry.md`, `ledger.md`, ... `format.md`), each rule a section with its
|
||||
status, its MUST/MUST NOT/MAY statement, its sources (a vendored source
|
||||
with a verbatim pin, or an exact external reference), its symbolic form,
|
||||
its examples by id and its applicability. `spec/rules-index.md` is the
|
||||
table from `docs/spec/rules.md`'s B-1 to B-45. The checker's
|
||||
`tests/spec.rs` fails the build when a rule lacks its section, a
|
||||
statement lacks MUST/SHOULD/MAY, a pin is not verbatim in its vendored
|
||||
source, a rule's examples differ from the catalogue's, or the edition
|
||||
passes 60 pages.
|
||||
- `lean/` is the five laws as Lean theorems (`Bookspec.law_*`), ported
|
||||
from `verify/lean`; `lake build` in that directory builds them and
|
||||
`lake env lean Audit.lean` prints their axioms, which the checker's
|
||||
`tests/lean.rs` requires to be only `propext`, `Quot.sound` and
|
||||
`Classical.choice`.
|
||||
- The checker derives expected figures itself (`checker/src/derive.rs`):
|
||||
an engine-free reference model with exact decimals replays an example's
|
||||
entries, reversals, close, bills and invoices and computes its
|
||||
`trial_balance`, `balances`, `profit_and_loss` and `entry` figures from
|
||||
the rules' symbolic forms, and checks that each refusal the example
|
||||
expects is justified by its rule. An example whose figure disagrees
|
||||
fails `checker/tests/derive.rs`, before any engine is consulted. What
|
||||
the model does not cover is reported as skipped, never passed.
|
||||
- `gnucash/` is the second engine: GnuCash 5.10 in the oracle container
|
||||
(`just oracle` builds it), driven through `oracle/gnucash/books.py`.
|
||||
`cargo test -p bookspec-gnucash -- --ignored` runs it (it needs
|
||||
Docker). It claims the rules whose examples ask only for balances and
|
||||
passes `BS-entry-3`, `BS-ledger-3`, `BS-statement-1` and
|
||||
`BS-statement-2`.
|
||||
|
||||
### GnuCash, the second engine: where it differs
|
||||
|
||||
GnuCash is a cross-check, never the authority (`docs/oracle.md`, "Who is
|
||||
right"). It differs from three examples, each settled from the sources
|
||||
and pinned by `gnucash/tests/gnucash.rs`:
|
||||
|
||||
- **`entry-an-unbalanced-entry-is-refused`.** GnuCash accepts debits of
|
||||
100.00 against credits of 90.00 and parks the ten dollars in an
|
||||
`Imbalance-USD` account of its own making; the accounts it lists no
|
||||
longer net to zero. BS-entry-1 (Pacioli ch. 36; IRS Pub. 583: "the
|
||||
total debits must equal the total credits") says such an entry is
|
||||
refused. The example stands; GnuCash records a difference, flagged for
|
||||
the user to repair, instead of refusing it.
|
||||
- **`entry-a-line-amount-is-positive`.** GnuCash takes a credit of
|
||||
minus 100.00 as a debit of 100.00, both lines debits, and parks 200.00
|
||||
in the Imbalance account. BS-entry-2 is a CONVENTION (no authority
|
||||
forbids a negative amount); the example stands as the convention the
|
||||
specification chose, and GnuCash's reading is the very ambiguity the
|
||||
convention removes.
|
||||
- **`ledger-a-fraction-of-a-cent-is-refused`.** GnuCash rounds 10.005 to
|
||||
10.01 silently. BS-ledger-1 is a CHOICE (the owner, 2026-10-13, found
|
||||
by the first GnuCash cross-check): the books never round silently. An
|
||||
engine's pick is its own; GnuCash's is the other option, recorded.
|
||||
|
||||
The example `ledger-a-mistake-is-reversed-never-erased` and the others
|
||||
that need an engine's own reversal link or entry query are not claimed by
|
||||
the GnuCash adapter: GnuCash has no reversal link, so it cannot answer
|
||||
`already_reversed`.
|
||||
|
||||
## Licence and sources
|
||||
|
||||
The examples state rules in their own words with the paragraph cited
|
||||
|
||||
Reference in new issue
Block a user