feat(audit): books.audit, the attestation tools and the CPA gate (P8)
The whole re-audit through the tools: books.audit previews its checks, then with the preview's digest runs them, files the workpaper and journals the run; the same books, day and scope return the run that exists. books.attest_receipt, books.review_entry and books.attest_period record a named client's claim with its self-reported method; books.attestations weighs each against policy.attestation_bar as it stands. Under policy.cpa_package_requires_audit = refuse, books that declared audits cannot export the CPA package without a counted audit for the handoff at the current head unless a reason is given, which is journaled as a decision (D-9). Needs attention asks for the month-end attestation, the annual audit and the audit before the handoff. Rules B-45, the handbook section, the interface, parity, receipt-store and testing records, and the As-built block. Merge needs no go-ahead: the live books refuse the new writes until the owner gives it. 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
d45e842873
commit
45bcce679b
23 files changed
+2128
-22
No files matched your search
+15
-2
@@ -33,7 +33,7 @@ the specification in `bookspec/` (which never depends on the engine).
|
||||
| `ledger-config` | the `wanderbooks.toml` codec (adoption in, `books.export_settings` out) and the receipt policy until P4 moves it into the core | `ledger-core` |
|
||||
| `ledger-store` | the source of truth: the hash-chained JSONL journal, its format gate, the SQLite projection (schema 18; a file per schema), the blob store, backups, the access log, `describe.rs` (the journal in words, for `books.journal_history`), `Snapshot` for readers | `ledger-core`, `ledger-reader` (P6, D-61) |
|
||||
| `ledger-reader` | the one reader: a PDF's text and pages, an XLSX's cells as exact decimal strings, plain text (P6; a plain library, in-process, D-61); `ledger-import` re-exports it as `extract` | none (`hayro`, `zip`, `quick-xml`) |
|
||||
| `ledger-import` | formats: QuickBooks CSV in; IIF, XLSX, Typst PDFs (statements, the invoice, labels) out | `ledger-core`, `ledger-reader` |
|
||||
| `ledger-import` | formats: QuickBooks CSV in; IIF, XLSX, Typst PDFs (statements, the invoice, labels, the audit workpaper) out | `ledger-core`, `ledger-reader` |
|
||||
| `ledger-package` | the shared read-only view over `Store` or `Snapshot` (`PackageBooks`): the CPA package, the 1099 worksheet, the invoice document, Needs attention | `ledger-core`, `ledger-store`, `ledger-config`, `ledger-import`, `ledger-vault` |
|
||||
| `ledger-mcp` | the books server: the MCP tools (122), resources, the handbook, scopes, the door and the access log, backups' scheduling | all of the above |
|
||||
| `ledger-host` | the host and its leases, the agent bridge (`wanderbooks mcp`), tokens in 0600 files under the data root (D-63), the owner's commands, uploads and downloads, `update` and `rollback` (P11a) | `ledger-store`, `ledger-mcp`, `ledger-config` |
|
||||
@@ -59,13 +59,26 @@ closure. The reader now lives in the small library crate `ledger-reader`;
|
||||
re-exports it as `extract`), the store no longer builds the typesetter,
|
||||
and `ledger-import` still never depends on the store.
|
||||
|
||||
Audits (P8, rules.md B-45) are split by what each layer can see. The pure
|
||||
checks over a ledger are `ledger_core::audit` (`statements`, with the facts
|
||||
a ledger cannot know handed in by the caller: the receipts filed, the
|
||||
statement of cash flows the role settings give, the settings problems, the
|
||||
undecided 1099 vendors); what only the store can see (the chain, the
|
||||
database against a replay, the stored files, the access log, duplicate
|
||||
files) and the audit and attestation events are `ledger_store::audit` (a
|
||||
child module of `store`, because it reads the store's private state); the
|
||||
workpaper's PDF is `ledger_import::workpaper` with its Typst template in
|
||||
`ledger-import`'s `templates/` beside the other documents; the backups'
|
||||
standing is read by the server, which alone knows the backups
|
||||
(`BackupStanding`), and the tools are `ledger-mcp`'s `tools/audit.rs`.
|
||||
|
||||
`ledger-core` itself (`crates/ledger-core/src/`): `money`, `account`,
|
||||
`journal`, `ledger` (the command surface and replay), `kernel` (every
|
||||
money arithmetic, generic over `Amount`) and `proofs` (its Kani
|
||||
harnesses), `reports`, `cashflow`, `analysis`, `periods`, `assets`,
|
||||
`schedules`, `recurring`, `payouts`, `payroll`, `form1099`, `tax`,
|
||||
`classes`, `parties`, `arap`, `settings`, `conventions`, `calendar`,
|
||||
`shares`, `tax_capital`, `rules`, `error`; its tests in `tests/`
|
||||
`shares`, `tax_capital`, `rules`, `audit` (the audit programme's pure checks, P8), `error`; its tests in `tests/`
|
||||
(`invariants.rs`, `properties.rs`, `spec_*.rs`, `kernel_bridge.rs`,
|
||||
`model.rs`, `bookspec.rs`, `golden/`).
|
||||
|
||||
|
||||
+71
-3
@@ -486,8 +486,8 @@ every tool over every book in ledger-store's `tests/fixtures/old-books`.
|
||||
`books.run_schedules`, `books.dispose_asset`, `books.reconcile`,
|
||||
`books.close_period`, `books.create_invoice`, `books.create_bill`,
|
||||
`books.receive_payment`, `books.pay_bill`, `books.write_off_invoice`,
|
||||
`books.purge_tin`, `books.consolidate_duplicates` and
|
||||
`books.discard_draft`. (`books.void_document`, `books.run_depreciation`
|
||||
`books.purge_tin`, `books.consolidate_duplicates`,
|
||||
`books.discard_draft` and `books.audit`. (`books.void_document`, `books.run_depreciation`
|
||||
and `books.run_recurring` post at once and have no `confirmed`.)
|
||||
- **The result envelope (P5, plan 4.6).** Every tool result, whatever the
|
||||
tool, is given the same fields in one place (`call_tool`,
|
||||
@@ -2554,7 +2554,7 @@ until the owner upgrades them.
|
||||
|
||||
## Tools — CPA handoff
|
||||
|
||||
- `books.export_cpa_package { as_of?, cash_accounts?, financing_accounts?,
|
||||
- `books.export_cpa_package { as_of?, without_audit_reason?, cash_accounts?, financing_accounts?,
|
||||
investing_accounts?, include_receipts?, include_tins?,
|
||||
allow_open_drafts?: { reason } }` → `{ file,
|
||||
tins_included, tin_gaps, warnings?, note }`: the zip,
|
||||
@@ -2733,3 +2733,71 @@ argument is refused.
|
||||
|
||||
`migrate`, `process_inbox` and `receipts_from_email` are not built (D-46,
|
||||
D-28, D-17).
|
||||
## Tools — audit and attestations (P8)
|
||||
|
||||
An audit is the books read as an auditor reads them, through a day, in one
|
||||
run: the same books give the same findings and the same workpaper. An
|
||||
attestation is a claim by a checker that it looked at something. The audit
|
||||
finds; the attestations stand behind it; the CPA package waits for both
|
||||
(rules.md B-45; decision D-9; the journal feature `audits`: the audit run
|
||||
and the attestations wait for the books' format upgrade, refused with
|
||||
`format_upgrade_pending` until then).
|
||||
|
||||
- `books.audit { scope, through?, confirmed?, preview? }` → `{ status:
|
||||
"preview" | "audited" | "already_run", preview, head, checks: [{ code,
|
||||
severity, predicate }], run?: { id, through, through_seq, scope,
|
||||
program_version, tb_hash, findings_sha256, workpaper_attachment,
|
||||
workpaper_pdf, at_current_head }, findings: [{ severity, code, subject,
|
||||
message }], summary }`. `scope` is `month`, `annual`, `cpa_handoff` or
|
||||
`full`; `through` defaults to today. Without `confirmed` it lists the
|
||||
checks and changes nothing; with `confirmed` and the `preview` digest it
|
||||
runs them, files the workpaper as two documents (category `workpaper`:
|
||||
JSON, and a PDF whose bytes depend only on the findings) and journals
|
||||
`audit.run`. The checks are the statements (trial balance, the
|
||||
accounting equation, the profit and loss against equity, the cash flow's
|
||||
footing), the A/R and A/P control accounts, closes, schedules and
|
||||
depreciation, the asset register, each posted entry against the receipt
|
||||
policy, open drafts, tax categories, 1099 decisions and the settings;
|
||||
then the journal's chain, the database against a replay, the stored
|
||||
files, the access log, duplicate files and the backups. The same books
|
||||
(the figure head), day, scope and programme return the run that exists
|
||||
(`already_run`) and file and journal nothing. "The same books" means no
|
||||
entry, document, close, settings or role change since: an audit, an
|
||||
attestation or a filed receipt does not change them. Needs books:write to
|
||||
preview, books:post to run.
|
||||
- `books.workpaper { id }` → `{ run, workpaper, pdf? }`: the workpaper as
|
||||
filed (what was checked, through which day and state, every finding) and
|
||||
its PDF handed over (`pdf` is a download command; kept 15 minutes).
|
||||
Read-only.
|
||||
- `books.attest_receipt { attachment_id, entry_id, amount, date, method?,
|
||||
note? }` → `{ attestation, bar, why_not_counted? }`. The checker's
|
||||
reading of the receipt's total and date, compared by the books with the
|
||||
posted entry's amounts (its debits, or any one line) and date; a
|
||||
difference is recorded with `disagrees: true` and never counts. The
|
||||
receipt must be filed on or linked to the entry.
|
||||
- `books.review_entry { entry_id, method?, note? }` → the same shape: a
|
||||
posted entry reviewed whole.
|
||||
- `books.attest_period { period, method?, note? }` → the same shape.
|
||||
`period` is an id or a name from `books.list_periods`. Refused unless an
|
||||
audit through the period's end stands at the books' current head; the
|
||||
attestation names that run.
|
||||
- `books.attestations { through?, kind? }` → `{ bar, attestations: [{ seq,
|
||||
kind, by, at, attachment_id?, entry_id?, period_id?, audit_run_id?,
|
||||
amount_checked?, date_checked?, disagrees, method, note?, counted }],
|
||||
counted }`. `kind` is `receipt`, `entry` or `period`. `counted` is read
|
||||
against `policy.attestation_bar` as it stands when asked and never
|
||||
stored: a bar change changes what counts, earlier claims too.
|
||||
|
||||
`method` is `{ model?, reasoning_effort?, adversarial?, verifier_agents? }`
|
||||
and is the client's own claim: the books record it and cannot verify it.
|
||||
`by` is the token's name. The bar (`policy.attestation_bar`, default
|
||||
`effort=high verifiers=2 adversarial=true`) holds every attestation to the
|
||||
effort, and a period attested on a year-level audit (`annual`,
|
||||
`cpa_handoff`, `full`) to the adversarial check and the verifier count too.
|
||||
|
||||
`books.export_cpa_package` gains `without_audit_reason?`: on books that
|
||||
declared `audits`, with `policy.cpa_package_requires_audit` at `refuse` (the
|
||||
default), the package is refused (`audit_required`) unless an audit with
|
||||
scope `cpa_handoff` or `full` stands at the current head with a period
|
||||
attested on it at the bar; a reason overrides the refusal and is journaled
|
||||
as a decision. Under `warn` the package is made and its `warnings` say so.
|
||||
@@ -238,3 +238,12 @@ golden covers it:
|
||||
| Area | Counterpart (a cross-check, not the spec) | Status | Notes |
|
||||
|---|---|---|---|
|
||||
| Audit trail in words (`books.journal_history`, the `describe` sentences) | QBO "Audit log", Xero "History and notes" | partial | tests `journal_history_traces_what_the_books_did`, `every_event_type_has_a_sentence`; the viewer keeps its own sentences (the shared describer is the server's) |
|
||||
### P8: audit and attestations (2026-10-29)
|
||||
|
||||
Three new rows, none above changed status, and the floor stands.
|
||||
|
||||
| Area | Counterpart (a cross-check, not the spec) | Status | Notes |
|
||||
|---|---|---|---|
|
||||
| Audit run: one programme of checks over the statements, the control accounts, closes, schedules, assets, evidence, drafts, tax categories, 1099 decisions, settings and the store's integrity (`books.audit`, `books.workpaper`) | An auditor's workpaper; QBO "Audit log"/"Review" and Xero's "Reports review" are a cross-check only | partial | rules.md B-45; `ledger_core::audit`, `ledger_store::audit`; tests `audit_detects_each_seeded_defect` (every code seeded), `audit_is_deterministic`, `workpaper_pdf_is_deterministic`; the fixture `p8_before` was written by the version before; `partial` until a hand-verified golden covers a workpaper |
|
||||
| Attestations of receipts, entries and periods, weighed against `policy.attestation_bar` when asked (`books.attest_receipt`, `books.review_entry`, `books.attest_period`, `books.attestations`) | An accountant's sign-off on a month | partial | `below_bar_not_counted`, `amount_mismatch_never_counts`, `stale_head_period_attestation_refused`; the method is the client's own claim, and the books say so |
|
||||
| The CPA package waits for a counted audit (`policy.cpa_package_requires_audit`) | A close checklist before handoff | partial | `cpa_package_refuses_without_a_counted_audit_unless_a_reason_is_given`; behind the feature `audits` |
|
||||
+21
-1
@@ -72,6 +72,8 @@ apply is safe — on startup the applier replays every journal line with
|
||||
an open item, when and on what, corrected without touching its words;
|
||||
replay sets the source and nothing else, and the projection updates the
|
||||
row's existing source columns, so no schema changed)
|
||||
`audit.run`, `receipt.attested`, `entry.reviewed` and `period.attested`
|
||||
(P8, feature `audits`: claims about the books, no figure)
|
||||
(plus the A/R, A/P, asset,
|
||||
period, payroll, and class events listed on `JournalLine`).
|
||||
- `payload`: the full domain facts (account fields, entry with lines, blob
|
||||
@@ -174,6 +176,20 @@ a backup is then proven where it lands, by a drill (docs/mcp-interface.md,
|
||||
read off a file (the closed field list; a later annotation replaces the
|
||||
earlier record), and `entry.settles {entry_id, settles[]}` says which
|
||||
entries a payment pays back (the only source of "reimbursed").
|
||||
- **Audits and attestations are records, not figures** (P8, rules.md B-45,
|
||||
feature `audits`): `audit.run {id, through, through_seq, scope,
|
||||
program_version, tb_hash, findings_sha256, workpaper_attachment?,
|
||||
workpaper_pdf?}` says a programme of checks was run through a day at the
|
||||
books' figure head `through_seq` (the last line that bears on a figure;
|
||||
audits, attestations and filings of evidence do not move it), and which
|
||||
two filed documents (category `workpaper`) hold its findings;
|
||||
`receipt.attested {attachment_id, entry_id, by, at, method,
|
||||
amount_checked, date_checked, disagrees, note?}`, `entry.reviewed
|
||||
{entry_id, by, at, method, note?}` and `period.attested {period_id, by,
|
||||
at, method, audit_run_id}` are a named client's claim that it checked.
|
||||
`method` ({model?, reasoning_effort?, adversarial?, verifier_agents?}) is
|
||||
that client's own word. Whether a claim counts is never journaled: it is
|
||||
derived against `policy.attestation_bar` when asked.
|
||||
- The store is policy-free: it records attachments faithfully. Whether a
|
||||
posting *requires* a receipt is decided by the MCP layer's receipt policy
|
||||
(`docs/mcp-interface.md`), which reads the `attachments` table.
|
||||
@@ -199,7 +215,11 @@ Suspected corruption is fixed by rebuild, never by forensics.
|
||||
as above; `extractions(attachment_id, extractor, version, text_sha256,
|
||||
pages, status, seq)` and `annotations(attachment_id, receipt_number,
|
||||
payee, amount, date, instrument, category, source, reimbursable_to,
|
||||
note, seq)` (P6; amounts TEXT, never REAL); `events(seq, type, payload,
|
||||
note, seq)` (P6; amounts TEXT, never REAL); `audits(id, through,
|
||||
through_seq, scope, program_version, tb_hash, findings_sha256,
|
||||
workpaper_attachment, workpaper_pdf, seq)` and `attestations(seq, kind,
|
||||
attachment_id, entry_id, period_id, audit_run_id, by_who, at_ts, method,
|
||||
amount_checked, date_checked, disagrees, note)` (P8, schema 20); `events(seq, type, payload,
|
||||
created_at)` — the applier's output,
|
||||
a queryable mirror of the journal stream and the feed the future GUI
|
||||
tails. (Poll `WHERE seq > ?`; later SSE over the HTTP transport. This is
|
||||
|
||||
@@ -1765,6 +1765,11 @@ being built, B-43). P5's is `source_revisions` (a
|
||||
`convention.source_revised`, `decision.source_revised` or
|
||||
`open_item.source_revised`, new event types: an older version would
|
||||
refuse them, or show the old source as the record's authority). A command asks for
|
||||
being built, B-43). P8's is `audits` (an `audit.run`, `receipt.attested`,
|
||||
`entry.reviewed` or `period.attested`, all new event types, and the
|
||||
settings `policy.attestation_bar` and `policy.cpa_package_requires_audit`:
|
||||
an older version would refuse the types and the keys, or drop the claims a
|
||||
handoff rests on, B-45). A command asks for
|
||||
the feature it needs (`Store::ensure_feature`) before its first journaled
|
||||
line, and only when the line it is about to write uses it, so a write
|
||||
refused for waiting on the upgrade journals nothing, never an entry
|
||||
@@ -3585,3 +3590,92 @@ withdraw_attachment_duplicate}` and `Store::attach`'s dedup; feature
|
||||
`page_image_is_a_png_of_the_page`,
|
||||
`consolidation_never_removes_an_entrys_only_evidence`); fuzz targets
|
||||
`fuzz_extract_pdf` and `fuzz_extract_xlsx`.
|
||||
|
||||
## B-45 An audit is deterministic over the books; an attestation is a claim by a named client
|
||||
|
||||
**bookspec:** `BS-ledger-13`
|
||||
|
||||
**Status:** CONVENTION (the SOURCE block below; Pub. 583 and Rev. Proc. 98-25
|
||||
for the audit trail); DECISION D-9 (owner-adopted recommendation,
|
||||
2026-10-16: the attestation bar, and the CPA package waits for a counted
|
||||
audit unless given a reason).
|
||||
|
||||
```text
|
||||
GOAL: the books can be audited by a programme that gives the same
|
||||
findings for the same books, and a claim that someone checked rests
|
||||
on the books as they were when the audit ran, says how it was made,
|
||||
and is weighed against the owner's bar when asked.
|
||||
SOURCE: IRS Pub. 583 (records that support the entries); Rev. Proc. 98-25
|
||||
§5.01 (the relationship between the records and the books must be
|
||||
demonstrable: an audit trail); DECISION D-9 (the bar: reasoning
|
||||
effort at least high; for a year, adversarial verification by at
|
||||
least two independent agents; no model allow-list; the CPA package
|
||||
refuses without a counted audit unless given a reason); DECISION
|
||||
D-53 (an audit is a run, not a job); CONVENTION (the figure head,
|
||||
below; a client's method is its own claim).
|
||||
INVARIANTS:
|
||||
1. An audit is a pure function of the journal's figures: its findings
|
||||
(`ledger_core::audit::statements`, the store's integrity checks) are
|
||||
a list in a fixed order, and the same books, day, scope and
|
||||
programme give the same findings, the same trial balance hash and
|
||||
the same workpaper bytes. A check that cannot be made is itself a
|
||||
finding, never a silent pass.
|
||||
2. The figure head is the seq of the last journal line that bears on a
|
||||
figure. Audit runs, attestations, filings of evidence (receipts,
|
||||
documents, statements, reconciliations, extraction, annotations,
|
||||
links), decisions and open items, and the format declaration do not
|
||||
move it; an entry, a draft, a document, a close, a schedule, an
|
||||
asset, a settings change or a role change does. A run is idempotent
|
||||
on (through, head, scope, programme): asking again returns it and
|
||||
journals nothing.
|
||||
3. A period is attested only on a run at the current head whose day is
|
||||
on or after the period's end.
|
||||
4. An attestation is a claim by the token that made it (`by`); its
|
||||
method (model, reasoning effort, adversarial, verifier agents) is
|
||||
the client's own, recorded and never verified. A receipt attestation
|
||||
whose amount or date differs from the entry's is recorded with
|
||||
`disagrees` and never counts.
|
||||
5. `counted` is derived against `policy.attestation_bar` as it stands
|
||||
when asked and never stored: a bar change changes what counts, past
|
||||
claims too. Every attestation needs the reasoning effort; one on a
|
||||
year-level run (annual, cpa_handoff, full) needs the adversarial
|
||||
check and the verifier count too.
|
||||
6. The CPA package, on books that declared `audits` and under
|
||||
`policy.cpa_package_requires_audit = refuse`, needs a run of scope
|
||||
cpa_handoff or full at the current head with a period attested on it
|
||||
that counts; otherwise it is refused, unless a reason is given,
|
||||
which is journaled as a decision.
|
||||
7. Nothing here moves a figure. Every refusal leaves the journal
|
||||
unchanged; every write waits for the feature `audits`.
|
||||
SCENARIOS:
|
||||
1. The same books audited twice through one day: one run, one
|
||||
workpaper; the second call files and journals nothing.
|
||||
2. An entry posted after the audit: the period cannot be attested until
|
||||
the audit is run again.
|
||||
3. A receipt read as 41.00 against a 40.00 entry: recorded, `disagrees`,
|
||||
not counted, however hard the checker says it thought.
|
||||
4. The bar lowered afterwards: earlier attestations that now meet it
|
||||
count.
|
||||
5. A CPA package with no counted audit: refused (`audit_required`);
|
||||
with a reason, made, and the reason is a decision in the journal.
|
||||
6. Books that never declared `audits`: the package is as it was; the
|
||||
audit run and the attestations are refused with
|
||||
`format_upgrade_pending`.
|
||||
```
|
||||
|
||||
**Enforced:** `ledger_core::audit` (`statements`, `Finding`, `CODES`,
|
||||
`AttestationBar::counts`, `Scope`, `Method`), `ledger_store::audit`
|
||||
(`Store::figure_head`, `integrity_findings`, `record_audit_run`,
|
||||
`attest_receipt`, `review_entry`, `attest_period`, `run_for_period`,
|
||||
`attestations`, `PROGRAM_VERSION`), `ledger_import::workpaper_pdf`,
|
||||
ledger-mcp `tools/audit.rs` and the gate in `books.export_cpa_package`,
|
||||
journal feature `audits`.
|
||||
**Checked:** `ledger-core` `tests/audit.rs`
|
||||
(`audit_detects_each_seeded_defect`, `below_bar_not_counted`,
|
||||
`amount_mismatch_never_counts`); `ledger-store` `tests/audit.rs`
|
||||
(`audit_writes_wait_for_audits`, `a_run_is_idempotent_on_the_figure_head`,
|
||||
`stale_head_period_attestation_refused`, `integrity_detects_each_seeded_defect`,
|
||||
`books_the_version_before_p8_wrote_wait_for_the_upgrade`); `ledger-import`
|
||||
`workpaper_pdf_is_deterministic`; `ledger-cli` `tests/audit.rs`
|
||||
(`audit_is_deterministic`, `cpa_package_refuses_without_a_counted_audit_unless_a_reason_is_given`,
|
||||
`audits_wait_for_the_upgrade`).
|
||||
@@ -3831,3 +3831,94 @@ equal-source refusals and the empty-reason refusals; the three
|
||||
`apply_*_source` arms (a mutant that also bumps `revision` or `seq` shows
|
||||
in `a_source_only_revision_is_journaled`); `books.start`'s fit order and
|
||||
`reconciliation` split (`reconciled_through.is_some()`).
|
||||
## P8: audit and attestations (2026-10-29)
|
||||
|
||||
An audit run is a deterministic programme of checks over the books through
|
||||
a day, filed as a JSON and a PDF workpaper; attestations are claims by a
|
||||
named client that it checked a receipt, an entry or a period, weighed
|
||||
against `policy.attestation_bar` when asked. Journal feature `audits`;
|
||||
events `audit.run`, `receipt.attested`, `entry.reviewed`, `period.attested`
|
||||
(no figure moves); schema 20 (taken as the next after the last, renumbered
|
||||
at merge): the `audits` and `attestations` tables; settings
|
||||
`policy.attestation_bar` (a new `Kind::AttestationBar`) and
|
||||
`policy.cpa_package_requires_audit`. No kernel change, no Kani harness, no
|
||||
Lean theorem: the audit calls kernel functions and adds none, and the laws
|
||||
it checks are already theorems.
|
||||
|
||||
- **`ledger-core` `tests/audit.rs`:** `audit_detects_each_seeded_defect`
|
||||
(the code table `audit::CODES` has a row per check and the test iterates
|
||||
it: a seeding fixture for each, exactly that code found, its severity the
|
||||
row's; the checks a correct engine never lets happen are seeded through
|
||||
the predicate each check is built on, `check_trial_balance`,
|
||||
`check_equation`, `check_articulation`, `check_cash_flow`,
|
||||
`check_control`, `check_split`, `check_register`),
|
||||
`a_whole_book_gives_no_failure_or_warning`,
|
||||
`findings_come_in_one_order`, `below_bar_not_counted` (the bar's effort,
|
||||
the year-level adversarial check and verifier count, a lowered bar, the
|
||||
parse), `amount_mismatch_never_counts`.
|
||||
- **`ledger-store` `tests/audit.rs`:** `audit_writes_wait_for_audits`
|
||||
(R-A: every write refused with `FormatUpgradePending`, nothing
|
||||
journaled, taken after `upgrade_format`, replay equal to live),
|
||||
`a_run_is_idempotent_on_the_figure_head` (a filing and a run do not move
|
||||
the head, an entry does, asking again journals nothing),
|
||||
`amount_mismatch_never_counts` (a wrong amount and a wrong date are
|
||||
recorded as disagreeing; a receipt not on the entry, a draft and an
|
||||
unknown entry are refused), `stale_head_period_attestation_refused`
|
||||
(no audit, an audit that stops short of the period, a standing one, an
|
||||
entry since), `integrity_detects_each_seeded_defect` (every code of
|
||||
`ledger_store::audit::CODES`: a missing and a damaged stored file, a
|
||||
missing extraction text, a duplicate file written by an older version,
|
||||
a damaged access log, a database that differs from a replay, a damaged
|
||||
journal, a stale backup, a failed drill),
|
||||
`books_the_version_before_p8_wrote_wait_for_the_upgrade` (8.0.6 item 2).
|
||||
`tests/store.rs::books_written_under_older_rules_still_open` hand-writes
|
||||
the four events (8.0.6 item 1); `tests/format.rs` and
|
||||
`format.rs::audits_is_its_own_feature` (8.0.6 item 4). The four event
|
||||
names are now this version's, so the tests that need an event type no
|
||||
version has written use `ledger.not_yet_written` instead of
|
||||
`period.attested` (`tests/format.rs`, `ledger-gui/tests/newer_journal.rs`).
|
||||
- **8.0.6:** the fixture `old-books/p8_before` (writer
|
||||
`old-books-writer/src/bin/p8_before.rs`, run against b97234ac) holds
|
||||
receipted entries, a 40.00 purchase with no receipt, a small one, a
|
||||
reversal, an invoice part paid, an open draft and a closed month;
|
||||
`books_an_earlier_version_wrote_open_to_its_figures` opens it to that
|
||||
version's figures, so no figure moved and no golden changed;
|
||||
`books_p2_served_cut_over_whole` refuses `books.audit` and
|
||||
`books.review_entry` before consent and takes them after.
|
||||
- **`ledger-import` `workpaper.rs`:** `workpaper_pdf_is_deterministic`,
|
||||
`a_different_finding_is_a_different_document`.
|
||||
- **`ledger-cli` `tests/audit.rs`:** `audit_is_deterministic` (preview,
|
||||
run, the same run and findings again with nothing journaled, the
|
||||
workpaper and its PDF hash equal twice, a new entry makes a new audit),
|
||||
`attestations_count_against_the_bar_when_asked` (a disagreeing reading,
|
||||
a medium effort, no claim, a lowered bar read retroactively),
|
||||
`a_period_is_attested_on_a_standing_audit`,
|
||||
`cpa_package_refuses_without_a_counted_audit_unless_a_reason_is_given`
|
||||
(refused, a reason journaled as a decision, an audit alone not enough, a
|
||||
year attested below the whole bar not enough, the whole bar, an entry
|
||||
since, `warn`), `audits_wait_for_the_upgrade` (the fixture over the
|
||||
wire; the package is not held up by an audit it cannot ask for).
|
||||
- **`ledger-cli` `tests/attention_parity.rs`:**
|
||||
`audit_items_are_on_both_lists_once_audits_are_declared`.
|
||||
|
||||
**For P12 (mutation targets):** `audit::statements`' order of checks and
|
||||
`sort` (severity, then code, subject, message); each `check_*` predicate's
|
||||
comparison (`check_trial_balance`'s `balanced`, `check_articulation`'s
|
||||
`!=`, `check_split`'s `> unit`, `check_register`'s two conditions,
|
||||
`check_cash_flow`'s three arms, `check_control`'s `difference`, unattached
|
||||
and `Overpaid` arms); `evidence`'s three arms (Required, the reversal
|
||||
exemption and the policy test that lists it, the plain exemption) and its
|
||||
receipt-set lookup; `closed_net`'s sign for revenue and expense;
|
||||
`AttestationBar::counts` (each of the four conditions, `>=`, the `full`
|
||||
branch, the `disagrees` early return) and `parse`; `Scope::full_bar` and
|
||||
`serves_handoff`; `Store::figure_head` (the `NOT_FIGURES` list: a type
|
||||
wrongly in it lets a stale audit stand, a type wrongly out of it makes an
|
||||
audit stale at its own filing), `find_audit_run`'s four equalities,
|
||||
`record_audit_run`'s idempotence return, `attest_receipt`'s amount rule
|
||||
(the debit total or any one line) and date equality, `run_for_period`'s
|
||||
`through_seq == head` and `through >= period.end`;
|
||||
`integrity_findings`'s eight arms; `backup_findings`' three conditions; the
|
||||
export gate (`cpa_audit_standing`'s four conditions and its feature test,
|
||||
the `refuse`/`warn` split, the reason's trim); `audit_items` in Needs
|
||||
attention (the declared test, the attested set, the last-ended fiscal
|
||||
year, the three year conditions).
|
||||
Reference in new issue
Block a user