merge: P4b S7, bad debts (branch S7, 4b4fecb9)
The fourth of the paused branches: Ledger::write_off and the bad_debts control role, invoice.written_off with its evidence filed in the same store call, books.write_off_invoice, the write-off on the timeline and in Needs attention, Lean writeOff_within_bounds, rules.md B-41 and the bookspec examples. Twenty-eight files conflicted with the S4.4, S5 and S6 merges; resolved as plan 8.0.2 says, keeping both sides' appends with their seams restored, and: the scope table at 125; S7's law numbered 37; B-41 placed before B-42; the handbook's step 4 and recovery procedures folded into the one invoices-and-bills section; S7's wire tests in their own module with the confirm S4.4's contract needs; S7's copy of the payment steps dropped (S6 replaced them with Ledger::settle) and its write-off journaled through S6's journal_auto_lines; in the old-books fixture S7's hand-written write-off moved to a second invoice, since S6's hand-written payment settles invoice 1 in full. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HS8WZziDnyxunC23MUxrLp
This commit is contained in:
commit
335a3eaa7e
47 files changed
+2883
-74
No files matched your search
@@ -184,6 +184,9 @@ groups are:
|
||||
- `parties` — parties, vendors, customers, roles, W-9s, the TIN vault,
|
||||
1099s, entry parties;
|
||||
- `attachments` — receipts, filed documents, and their links;
|
||||
- `write_offs` — `books.write_off_invoice`, the bad debt (P4b S7; rules.md
|
||||
B-41), kept apart from `documents` so S4.4's document tools and this one
|
||||
land in different files;
|
||||
- `settings` — the handbook, `books.settings` and the recorded FX rates
|
||||
(the module is `settings_tools`, since `crate::settings` is the live
|
||||
settings);
|
||||
|
||||
+25
-3
@@ -354,7 +354,7 @@ Tool descriptions are at most 700 characters; eight longer ones are listed
|
||||
in `tool_descriptions_fit_700_characters`, to be shortened in P5.
|
||||
|
||||
**Annotations.** Every tool has a `title` and a `readOnlyHint`; every tool
|
||||
that changes anything also has a `destructiveHint`, true for these 29:
|
||||
that changes anything also has a `destructiveHint`, true for these 30:
|
||||
`books.post_entry`, `books.reverse_entry`, `books.set_setting`, `books.retire_convention`, `books.unlink_receipt`,
|
||||
`books.unlink_attachment`, `books.withdraw_attachment`,
|
||||
`books.correct_asset`, `books.dispose_asset`, `books.run_depreciation`,
|
||||
@@ -364,8 +364,8 @@ that changes anything also has a `destructiveHint`, true for these 29:
|
||||
`books.void_statement`, `books.void_reconciliation`, `books.set_w9`,
|
||||
`books.set_tin` (both overwrite a vault record), `books.purge_tin`,
|
||||
`books.create_invoice`, `books.create_bill`, `books.receive_payment`,
|
||||
`books.pay_bill`, `books.void_document`, `books.run_payroll`,
|
||||
`books.remit_payroll_taxes`; and an
|
||||
`books.pay_bill`, `books.void_document`, `books.write_off_invoice`,
|
||||
`books.run_payroll`, `books.remit_payroll_taxes`; and an
|
||||
`idempotentHint` on the ten that a repeat with the same arguments leaves
|
||||
the journal and the vault as they were: `books.verify`,
|
||||
`books.run_depreciation`, `books.run_schedules`, `books.run_recurring`,
|
||||
@@ -2142,6 +2142,28 @@ snapshots; see plan 8.2 S4.
|
||||
recipients, or while the books wait for `documents_v2`
|
||||
(`format_upgrade_pending`). `sends` is every send on the invoice, in
|
||||
order, the new one last.
|
||||
- `books.write_off_invoice { invoice, date, amount?, reason, upload_id |
|
||||
existing_attachment_id, confirmed? }` → `{ entry_id, document: { ref,
|
||||
status, paid, written_off, outstanding } }`. Writes off an invoice that
|
||||
will not be collected (a bad debt, P4b S7; rules.md B-41): posts Dr
|
||||
`6990` Bad Debt Expense / Cr `1200` Accounts Receivable, the receivable
|
||||
line tagged with the invoice (`WriteOff`), so the invoice reads
|
||||
`written_off` and its figures stay derived (B-38). `amount` (a decimal
|
||||
string, default all it owes) is at most what is owed and may be partial
|
||||
(§1.166-3(a)). Its evidence of worthlessness (collection
|
||||
correspondence, a bankruptcy notice: §1.166-2(a)) is filed in the same
|
||||
call, as `upload_id` (books.begin_upload, purpose `document` or
|
||||
`receipt`, then `wanderbooks upload`) or as an
|
||||
`existing_attachment_id` already filed and not linked; it becomes a
|
||||
receipt on the write-off's entry and a link to the invoice. Refused on
|
||||
cash-basis books (§1.166-1(e)), above what it owes, before the
|
||||
invoice's date or in a closed period. Without `confirmed: true` it
|
||||
answers `entry_id` 0 and the figures the write-off would leave, writing
|
||||
nothing. A recovery is not a new command (D-49): the same tax year,
|
||||
reverse the write-off (`books.reverse_entry`, the invoice reopens) and
|
||||
record the payment; a later year, a plain entry Dr the deposit account /
|
||||
Cr a "Bad debt recoveries" revenue account, the invoice staying written
|
||||
off (§111).
|
||||
- `books.documents { kind, status?, party?, due_by?, as_of? }` → `{ as_of,
|
||||
kind, documents: [{ ref, party, date, due_date, total, outstanding,
|
||||
status, overdue_days, last_sent? }], outstanding_total }`. Invoices (`kind`
|
||||
|
||||
@@ -163,3 +163,13 @@ posted gross (A-4), and the bills-due list with the agings' detail,
|
||||
tie-out and exports. The pre-S6 fixture's figures still hold (no figure
|
||||
moves), and every new write needs the journal feature `documents_v2`,
|
||||
which the owner's books declare at their next upgrade (D-52).
|
||||
## P4b S7: bad debts (write-offs), 2026-10-27
|
||||
|
||||
A/R gained the direct write-off the owner chose (A-5; plan 8.2 S7): an
|
||||
invoice that will not be collected comes off 1200 with Dr 6990 Bad Debt
|
||||
Expense, its receivable line tagged `WriteOff` so the receipt's figures
|
||||
stay derived, and its evidence of worthlessness filed in the same call
|
||||
(rules.md B-41; IRC §166, §111; Treas. Reg. §1.166-1(e), (f), -2(a),
|
||||
-3(a)). A same-year recovery is the reversal D-49 records, not a new
|
||||
movement; bills are never written off. No row above changed status (the
|
||||
A/R and A/P rows already say `done`), so the floor stands (10 done).
|
||||
+10
-1
@@ -62,6 +62,9 @@ apply is safe — on startup the applier replays every journal line with
|
||||
send: a document's record, never a ledger line or a figure; P4b S5)
|
||||
(plus the A/R, A/P, asset, period, payroll, and class events listed on
|
||||
`JournalLine`).
|
||||
`invoice.written_off`, `bill.created`, `receipt.attached`, `receipt.linked`, `receipt.unlinked`,
|
||||
`document.filed`, `attachment.withdrawn` (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
|
||||
sha, ...). Everything the applier needs; nothing it must look up elsewhere.
|
||||
An `invoice.created` or `bill.created` written after the `documents_v2`
|
||||
@@ -76,7 +79,13 @@ apply is safe — on startup the applier replays every journal line with
|
||||
entry exists): it is a `receipt.attached` on the invoice's own entry
|
||||
(`INV-0007.pdf`, `application/pdf`, "Issued invoice"), its SHA-256 the
|
||||
`blob_sha`, linked to the invoice with `attachment.linked` and found
|
||||
through that link (plan 8.3.11).
|
||||
through that link (plan 8.3.11). An `invoice.written_off` (plan 8.3.6,
|
||||
P4b S7) carries `{invoice_id, entry_id, date, amount, reason}`; replay
|
||||
tags the entry's receivables line `WriteOff`, and the projection keeps
|
||||
no written-off figure either: it is the tagged lines' sum (rules.md
|
||||
B-38, B-41). Its evidence of worthlessness rides beside it, as a
|
||||
`receipt.attached` on the write-off's entry and an `attachment.linked`
|
||||
to the invoice, filed in the same call.
|
||||
- `prev`: hex SHA-256 of the previous line's canonical JSON (keys sorted, no
|
||||
whitespace). The genesis line uses `"prev": "000...0"` (64 zeros).
|
||||
|
||||
|
||||
@@ -3120,6 +3120,108 @@ coding of `DocRef`), and an account becoming a control account by its
|
||||
first document, holding lines from before, is outside it (those lines are
|
||||
listed as unattached).
|
||||
|
||||
## B-41 A debt that will not be collected is written off, and a recovery is income
|
||||
|
||||
**bookspec:** `BS-arap-5`
|
||||
|
||||
**Status:** CHOICE (the owner, 2026-10-23, plan 8.3.1 A-5: bad debts by
|
||||
the **direct write-off** method, and 8.3.2: for a small company's
|
||||
receivables a CPA accepts the direct method and notes it, where GAAP
|
||||
prefers an allowance under ASC 326-20). AUTHORITY for what the rule
|
||||
rests on: IRC §166(a) (a debt that becomes worthless is deductible in
|
||||
that year), Treas. Reg. §1.166-1(e) (a debt never counted as income has
|
||||
no basis to deduct), §1.166-2(a) (worthlessness on all the pertinent
|
||||
evidence), §1.166-3(a) (a partial write-off, to the extent charged off),
|
||||
and IRC §111 (a recovery of an amount deducted is income in the year
|
||||
received). ASC 405-20-40-1 for a bill's release.
|
||||
|
||||
1. **The write-off.** Writing off an invoice posts one balanced entry:
|
||||
Dr the bad-debt expense role (`bad_debts`, 6990) and Cr receivables
|
||||
for the amount, the receivable line carrying the invoice with the
|
||||
movement `WriteOff`, so what the invoice owes falls by the amount from
|
||||
the write-off's day and what was written off rises by it. The amount
|
||||
is above zero and at most what the invoice owes, and at most the least
|
||||
it owes on any day from the write-off's on (so no later day, a payment
|
||||
after it included, takes the document below nothing: B-38 INVARIANT 2).
|
||||
A partial write-off is allowed (§1.166-3(a)); the rest stays owed and
|
||||
aged.
|
||||
2. **The day.** The write-off's day is in the calendar, in an open period
|
||||
(B-12), and not before the invoice's. A document's entry is reversed,
|
||||
never edited (B-8, B-9): a write-off is not a void and a void is not a
|
||||
write-off.
|
||||
3. **Cash basis refused.** Books on the cash basis never counted the
|
||||
invoice as income, so the debt has no basis to deduct (§1.166-1(e)):
|
||||
the command refuses, changing nothing.
|
||||
4. **Bills are never written off** (ASC 405-20-40-1): a liability leaves
|
||||
the books only when paid or when the creditor releases it, which is a
|
||||
vendor credit (not scheduled). The command takes an invoice.
|
||||
5. **A recovery is not a new movement** (plan D-49). In the same tax year,
|
||||
reverse the write-off: the invoice reopens and owes what the write-off
|
||||
took off, and the payment is recorded as any payment. In a later year,
|
||||
record a plain entry Dr the deposit account / Cr a "Bad debt
|
||||
recoveries" revenue account (tax category other income), its memo
|
||||
naming the invoice: the recovery is income (§111) and the invoice stays
|
||||
written off. There is no `Movement::Recovery` and no bad-debt-recoveries
|
||||
role.
|
||||
6. **Evidence.** The write-off's evidence of worthlessness — collection
|
||||
correspondence, a bankruptcy or liquidation notice (§1.166-2(a)) — is
|
||||
filed in the same call: a `receipt.attached` on the write-off's entry,
|
||||
linked to the invoice. A write-off with no evidence is refused. The tax
|
||||
judgments (whether the debt is worthless, and in which year) stay with
|
||||
the CPA: the books flag each write-off made this year for the CPA's
|
||||
note.
|
||||
7. **Journal.** `invoice.written_off {invoice_id, entry_id, date, amount,
|
||||
reason}` is a new event type and needs journal feature
|
||||
`documents_v2` (B-27, D-52): an older version refuses it rather than
|
||||
misreading a document as still owed. Replay tags the receivable line
|
||||
`WriteOff`; the projection keeps no document figure (B-38).
|
||||
|
||||
```text
|
||||
GOAL: write off what will not be collected, as the tax rules require.
|
||||
SOURCE: IRC §166(a), §111; Treas. Reg. §1.166-1(e), (f), -2(a), -3(a);
|
||||
ASC 326-20 and ASC 405-20-40-1 noted; CHOICE: the direct
|
||||
write-off method (plan 8.3.1 A-5).
|
||||
INVARIANTS:
|
||||
1. amount <= outstanding on the write-off's day and on every day from
|
||||
it; Dr bad_debts / Cr receivables [d, WriteOff]; the evidence of
|
||||
worthlessness filed in the same call.
|
||||
2. Its reversal re-instates the debt; bills are never written off.
|
||||
3. Refused on cash-basis books.
|
||||
4. A refusal leaves the books and the journal unchanged; NEVER panics.
|
||||
SCENARIOS:
|
||||
1. Half paid, the rest written off: Written off, with 50 paid / 50
|
||||
written off.
|
||||
2. A write-off of 0, a negative amount, or more than is owed: SHOULD
|
||||
refuse, naming what is owed.
|
||||
3. Cash-basis books: SHOULD refuse (no basis to deduct).
|
||||
4. The write-off reversed in the same year and the payment recorded:
|
||||
Paid; receivables back to zero.
|
||||
5. A later year's recovery: a plain entry to a bad-debt-recoveries
|
||||
revenue account; the invoice stays written off.
|
||||
```
|
||||
|
||||
**Enforced:** `ledger_core::Ledger::write_off` (and its replay
|
||||
`replay_invoice_write_off`), `LedgerError::{WriteOffOnCashBasis,
|
||||
InvalidWriteOff}`, the `bad_debts` control role (`BAD_DEBTS`, 6990);
|
||||
`ledger_store::Store::write_off_invoice` (feature `documents_v2`; the
|
||||
evidence filed and linked in the same call), `WriteOffEvidence`,
|
||||
`StoreError::WriteOffNeedsEvidence`; `books.write_off_invoice`
|
||||
(`crates/ledger-mcp/src/tools/write_offs.rs`); the viewer's timeline
|
||||
(`Movement::WriteOff`); Needs attention's write-off item.
|
||||
**Checked:** `ledger-core` `tests/spec_documents.rs`
|
||||
(`half_paid_rest_written_off_is_written_off`,
|
||||
`write_off_refused_on_cash_basis`, `write_off_above_outstanding_refused`,
|
||||
`write_off_then_recovery_same_year`); `ledger-store`
|
||||
`tests/arap_standing.rs` (`write_off_waits_for_documents_v2`,
|
||||
`write_off_replays_and_projects`, `write_off_without_evidence_is_refused`),
|
||||
`tests/arap_props.rs` (`status_is_a_function_of_journal_and_date` with
|
||||
write-offs); over the wire `crates/ledger-cli/tests/documents.rs`
|
||||
(`write_off_then_recovery`, `write_off_needs_evidence`); bookspec
|
||||
`bad-debt-direct-write-off`; Lean `Documents.Step.writeOff_unattached`,
|
||||
`Documents.writeOff_within_bounds`; the viewer
|
||||
`a_write_off_shows_on_the_timeline`; the item
|
||||
`a_write_off_is_flagged_for_the_cpa`.
|
||||
|
||||
## B-42 A settlement is exact and names its lines
|
||||
|
||||
**bookspec:** `BS-arap-6`
|
||||
|
||||
+80
-3
@@ -2674,7 +2674,7 @@ it calls what part A proved and tested.
|
||||
check, so both output schemas are exercised on every run.
|
||||
- **The tool surface, `crates/ledger-mcp/src/server.rs`'s tests:**
|
||||
`annotations_complete` pins `books.void_document` destructive and
|
||||
posting, `books.control_check` read-only, and counts the 29
|
||||
posting, `books.control_check` read-only, and counts the 30
|
||||
destructive tools the doc names; `period_tools_describe_the_one_default`
|
||||
holds `books.control_check` to the one `as_of` sentence. The generic
|
||||
lints cover the rest without a change of their own:
|
||||
@@ -2725,11 +2725,11 @@ strikethrough, and the test asserts the labels.
|
||||
The happy-path journey lists and reads one, so both output schemas are
|
||||
exercised on every run.
|
||||
- **The tool surface:** `annotations_complete` pins both read-only
|
||||
(table, now 122 tools); `period_tools_describe_the_one_default` holds
|
||||
(table, now 123 tools); `period_tools_describe_the_one_default` holds
|
||||
both to the `as_of` sentence;
|
||||
`every_tool_is_documented_and_every_documented_tool_exists` and the
|
||||
text lints cover the doc; `scopes.rs`'s table and
|
||||
`mcp_journeys.rs::mcp_end_to_end` count 122.
|
||||
`mcp_journeys.rs::mcp_end_to_end` count 123.
|
||||
- **The viewer, `crates/ledger-gui/tests/invoices.rs`:**
|
||||
`the_list_shows_the_ledgers_figures` (the reversed payment no longer
|
||||
counts: $580 owed, $500 of it late; "Invoice 1, Harbor Client, 14 days
|
||||
@@ -3191,3 +3191,80 @@ arithmetic; `bills_due`'s `through` filter, the discount-window test and
|
||||
the running-total grouping; `aging_documents`'s outstanding filter and
|
||||
bucket; `aging_csv`'s tie-out columns and `aging_statement`'s totals; the
|
||||
viewer's `discount_by` and `days_overdue` flags.
|
||||
|
||||
## P4b S7: bad debts (write-offs), 2026-10-27
|
||||
|
||||
The write-off (plan 8.2 S7; rules.md B-41): an invoice that will not be
|
||||
collected leaves the receivables as a deduction, with its evidence filed
|
||||
in the same call.
|
||||
|
||||
- **ledger-core, `tests/spec_documents.rs`:**
|
||||
`half_paid_rest_written_off_is_written_off` (B-38 SCENARIO 7: 50 paid,
|
||||
50 written off, one balanced entry Dr 6990 / Cr 1200, the receivable
|
||||
line tagged `WriteOff`, receivables down by exactly the write-off);
|
||||
`write_off_refused_on_cash_basis` (B-41 INVARIANT 3: refused, the
|
||||
snapshot unchanged, no draft left); `write_off_above_outstanding_refused`
|
||||
(the bound at the day, a zero and a negative amount, then the exact
|
||||
amount owed taken); `write_off_then_recovery_same_year` (D-49: the
|
||||
reversal re-instates the debt, the payment settles it, the invoice reads
|
||||
Paid and the write-off entry no longer stands). The first test's book
|
||||
is also the identity's: `control_check` agrees after the write-off.
|
||||
- **ledger-store, `tests/arap_standing.rs`:**
|
||||
`write_off_waits_for_documents_v2` (R-A: refused with
|
||||
`FormatUpgradePending`, journal and head unchanged, in the old-books
|
||||
fixture; taken after the upgrade; the evidence filed on the entry and
|
||||
linked to the invoice; replay equals live);
|
||||
`write_off_replays_and_projects` (the journal holds one
|
||||
`invoice.written_off` with its five facts, `receipt.attached` then
|
||||
`attachment.linked`; 6990 carries the expense, 1200 is zero, the
|
||||
control check agrees, `verify` passes and a reopened store has the same
|
||||
books and the same figures); `write_off_without_evidence_is_refused`
|
||||
(no evidence, and an attachment that isn't there, journal nothing; one
|
||||
already filed is linked to the entry and the invoice).
|
||||
`tests/arap_props.rs` gains `Op::WriteOff`: random write-offs (partial
|
||||
and over-large, refused ones included) run through the store, which is
|
||||
then reopened and read by a `Snapshot`; `status_is_a_function_of_journal_and_date`
|
||||
still holds at every date.
|
||||
- **Over the wire, `crates/ledger-cli/tests/documents.rs`:**
|
||||
`write_off_then_recovery` (an upload as the evidence, `confirmed`, the
|
||||
invoice reading written_off with its figures and its timeline, the
|
||||
receipt on the entry, the reversal and the payment, the control check
|
||||
agreeing) and `write_off_needs_evidence` (neither or both evidence
|
||||
arguments refused; an already-filed attachment linked to the entry and
|
||||
the invoice).
|
||||
- **The viewer, `crates/ledger-gui/tests/invoices.rs`:**
|
||||
`a_write_off_shows_on_the_timeline` (the shipped screenshot
|
||||
`invoice-written-off`: status Written off, still owed $0.00, the
|
||||
timeline's "Written off" row opening its entry).
|
||||
`crates/ledger-gui/tests/view_model.rs`: `a_write_off_is_flagged_for_the_cpa`
|
||||
(one item, "Write-off awaiting the CPA's note", the same through the
|
||||
server's read of the store and the viewer's snapshot).
|
||||
- **Lean, `Wanderbooks/Documents.lean`:** `Step.writeOff` (a tagged
|
||||
control line and an untagged expense line: a `Step.document` in shape),
|
||||
`Step.writeOff_unattached` (it moves nothing unattached, so
|
||||
`control_agrees` and `Reachable.control_is_documents` still hold),
|
||||
`through_append`, `docSum_writeOffLines`, and `writeOff_within_bounds`
|
||||
(a write-off of at most what is owed leaves nothing owed below zero over
|
||||
the date-sum). Both theorems are in `Audit.lean`. No kernel function
|
||||
was added, so no Kani harness.
|
||||
- **bookspec:** `bad-debt-direct-write-off` (B-41, CHOICE: invoice 100,
|
||||
two partial write-offs, the balances and the trial balance) and
|
||||
`arap-hand-control-posting-refused` (B-38: an entry an earlier version
|
||||
wrote on receivables replays, attempts the control guard now refuses,
|
||||
and the books still tie out). The example schema gained the `write_off`
|
||||
event and lets a refused `lines` event say so (an entry posts whole or
|
||||
not at all); the refusal vocabulary gained `untagged_control_line`,
|
||||
which belongs to B-38.
|
||||
|
||||
**For P12 (mutation targets, none run, D-33):** `Ledger::write_off_steps`'
|
||||
cash-basis comparison (the `eq_ignore_ascii_case`, the early return), its
|
||||
order of checks (amount before the day, the day before the room), the
|
||||
`amount > room` bound and its `room < owed` message arm, the `WriteOff`
|
||||
tag, `least_owed_from`'s `max` and its `min` over later days (the refactor
|
||||
`payment_room` now shares), `replay_invoice_write_off`'s movement, and
|
||||
`doc_state`'s `written_off` arm; `Store::write_off_invoice`'s evidence
|
||||
arms (the `check_linkable` call, the already-linked-to-the-invoice check,
|
||||
the blob-before-journal order, the `File`/`Existing` link steps) and the
|
||||
feature gate; the MCP handler's amount default, the exactly-one evidence
|
||||
check, and the preview's clone; attention's year comparison and its
|
||||
`stands_on` filter; the bookspec loader's `may_refuse` arm.
|
||||
+30
-1
@@ -579,6 +579,35 @@ come from the kernel:
|
||||
`Documents.settle_posts_a_document_step`,
|
||||
`Documents.settle_unattached`.
|
||||
|
||||
### Bad debts (P4b S7)
|
||||
|
||||
A write-off (rules.md B-41) is `Ledger::write_off`: a new command, so a new
|
||||
Lean step, and no new kernel function (its two lines are one debit and one
|
||||
credit, and the bounds are the existing date-sum's).
|
||||
|
||||
37. **A write-off of at most what is owed leaves nothing owed below
|
||||
zero.** The step posts the document's control line credited (tagged
|
||||
with it, so it is the same sum B-38 fixed) and the amount of
|
||||
bad-debt expense debited (untagged, off the control accounts).
|
||||
`through_append` reads the write-off's own two lines through the day
|
||||
separately; `docSum_writeOffLines` gives the control line's −amount;
|
||||
`writeOff_within_bounds` then follows by arithmetic from the command's
|
||||
own premise (the amount is at most the date-sum through the day).
|
||||
`Step.writeOff_unattached` shows the step moves nothing unattached, so
|
||||
`control_agrees` and `Reachable.control_is_documents` hold for it with
|
||||
no new proof. A reversal re-instates: the same `reverse_twice` that
|
||||
covers payments (`Step.reverse` mirrors every tagged line).
|
||||
- Lean `Documents.Step.writeOff`, `Documents.Step.writeOff_unattached`,
|
||||
`Documents.through_append`, `Documents.docSum_writeOffLines`,
|
||||
`Documents.writeOff_within_bounds` (in `Audit.lean`) · tests
|
||||
`half_paid_rest_written_off_is_written_off`,
|
||||
`write_off_above_outstanding_refused`,
|
||||
`write_off_then_recovery_same_year`, and the store's
|
||||
`write_off_replays_and_projects` (live, replay and snapshot agree).
|
||||
The model's limits are the documents model's (one `Nat` id space,
|
||||
books built from empty); the cash-basis refusal is a policy on the
|
||||
books' settings, not arithmetic, and is tested, not modelled.
|
||||
|
||||
## What the proofs found
|
||||
|
||||
The engine already had 190+ tests, property tests, mutation testing,
|
||||
@@ -667,7 +696,7 @@ Be precise about the claims:
|
||||
`tests/properties.rs` (trial balance, balance sheet, reversals,
|
||||
immutability) and the golden files.
|
||||
- **Out of scope:** currency (the ledger is single-currency, enforced
|
||||
structurally), A/R and A/P documents, payroll, the calendar walk around
|
||||
structurally), payroll, the calendar walk around
|
||||
the proration kernel (`calendar::month_parts`, `assets::depreciation_schedule`,
|
||||
`schedules::daily_plan`: property tests, `tests/properties.rs`, P3), and
|
||||
persistence (the journal store's hash chain is tested in `ledger-store`).
|
||||
|
||||
Reference in new issue
Block a user