P3: depreciation straight-line by days through the final month, schedules by day (defects 22, 9, D-37)

The final month takes what the months before leave, spread over its days;
a disposed asset stops on its disposal day. A skipped month is caught up
in the month the run is made; a reversed run un-posts its month. New
schedules spread by day; equal-months schedules must start on the 1st.
Amounts round to the currency's own minor unit. Kani and Lean proofs; an
exhaustive search over runs, reversals and disposals.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T3gXMVt7XJPi6ens1or9Dj
This commit is contained in:
swaitsandClaude Opus 5.5 committed 2026-10-21 14:04:11 -06:00
1 parent 249e216fc0
commit aa884d35d1
14 files changed
+1573 -22

No files matched your search

+94 -22
View File
@@ -39,7 +39,7 @@ code = "1000"
name = "Cash"
type = "asset" # asset | liability | equity | revenue | expense
[[events]] # in order; event N is entry #N
[[events]] # in order, counting from 1
date = "2026-01-10"
description = "Property contributed"
lines = [
@@ -50,8 +50,9 @@ lines = [
[[events]]
date = "2026-01-10"
description = "Reverse entry 1"
reverses = 1 # the event (1-based) this one reverses:
# its lines, sides flipped; no `lines` here
reverses = 1 # the event (1-based) whose entry this
# one reverses: its lines, sides flipped;
# no `lines` here
[[expect]]
query = "cash_flow" # what is asked of the books (see below)
@@ -62,14 +63,29 @@ to = "2026-12-31" # inclusive (a query as of a day: as_of)
operating = "0.00"
```
Events count from 1, as entries do: the first `[[events]]` is event 1
(entry #1), and `reverses = N` reverses the Nth event, one before it;
`reverses = 0` names no event and is refused. An event is an entry
(`lines`), a reversal (`reverses`), a close (`close`, below) or a bill
(`bill`, below), exactly one of them, and posts entry #N. A change that
posts no entry (a rename, a policy) is a `[[changes]]` entry instead
(below), so the numbering holds. A key the shape doesn't have is refused
too, never ignored.
Events count from 1: the first `[[events]]` is event 1. An event is an
entry (`lines`), a reversal (`reverses`), a close (`close`, below) or a
bill (`bill`, below), each posting one entry; or one of the books'
commands that post what is due (`run_depreciation`, `dispose_asset`,
`run_schedules`, below), which post as many entries as are due, none
included; or a schedule's registration (`register_schedule`), which
posts none: exactly one of them. A key that names an event (`reverses =
N`, `entry = N`, a cash flow's `<N>`) names the entry event N posted, one
before it: an event that posted none, or several, can't be named that
way, and `reverses = 0` names no event and is refused. While every event
posts one entry, event N's is entry #N. A change that posts no entry (a
rename, a policy) is a `[[changes]]` entry instead (below). A key the
shape doesn't have is refused too, never ignored.
An entry, a reversal, a close, a bill and a disposal are dated (`date`);
the other commands date their own entries (a run its month's end) and
take no date. An entry, a reversal, a close and a bill are described
(`description`); a command describes its own entries and takes none.
The books are the engine's own (`ledger_store::Store`, in a directory of
their own): each event is the command the books take it by, journaled as
they journal it, and after every expectation is checked the books must
replay to what they kept (`Store::verify`).
`rounding` names the rule the example's figures are rounded by where one
rounds: `half-even` or `half-away-from-zero` to the currency's minor unit,
@@ -113,6 +129,34 @@ the side gives the direction.
expense_account }`: accounts that hold property and equipment (their
cost and accumulated depreciation are investing; ASC 230-10-45-12(c),
45-13(c)).
- `[[setup.assets]]`: fixed assets registered before the first event,
each named by its `id` in the events and queries that ask about it
(rules.md B-15):
```toml
[[setup.assets]]
id = "X" # its name in this example
description = "Asset X"
cost = "12000.00"
salvage = "0.00"
life_months = 12
in_service = "2026-01-01" # depreciation starts here
method = "straight_line" # the one method the books have
cost_account = "1500"
accumulated_account = "1510"
expense_account = "6200"
```
Registering an asset posts nothing: the entry that buys it is an event
of its own.
- `[[setup.schedules]]`, and `register_schedule = { ... }` as an event: a
prepaid expense or deferred revenue recognized over its months (rules.md
B-16), named by its `id`:
`{ id, kind, description, total, start, months, convention,
balance_account, pl_account }`, `kind` `"prepaid_expense"` or
`"deferred_revenue"`, `convention` `"daily"` (by the day, the last month
taking what the others leave) or `"monthly_even"` (equal months from
the 1st). Registering one posts nothing.
- `[[setup.parties]]` `{ name, roles, creditor_of?, tin_last4?,
w9_tin_last4?, tin_purged? }`: the company's directory (B-26). `roles`
are role keys (`member`, `vendor`, `customer`, `contractor`,
@@ -153,8 +197,8 @@ the side gives the direction.
liability is a card account (B-35 item 5): while none is recorded, a
liability whose name says "card", not "gift card", is.
- `payee` on an event: the payee (by name, one of `setup.payees`) the
entry paid. Not on a reversal, which takes its original's, nor on a
close.
entry paid. Only on an entry (`lines`): a reversal takes its
original's, a bill names its vendor, a close and a command have none.
- `parties = [{ party, amount? }, { party, percent? }, ...]` on an event:
the parties (by name, in `setup.parties`) the entry is with, each with
its share: an `amount` (an exact decimal string), a `percent`, or
@@ -164,7 +208,7 @@ the side gives the direction.
`payee` as well, the payee's party is one of the parties.
- `instrument` on an event: the payment method (a `setup.instruments`
label) the entry was paid with. Neither `parties` nor `instrument` on a
reversal, which takes its original's.
reversal, which takes its original's, nor on a command.
- `close = { start, to, rounding? }` as an event: closes the period from
`start` through the event's `date` (rules.md B-11, B-13), `to`
`"members"` (split by share, in the order listed) or
@@ -173,13 +217,28 @@ the side gives the direction.
have closed less what earlier closes gave them; `rounding = "per-close"`
splits that close's net on its own instead (books from an engine that
rounded each close by itself). A close must have something to close: it
posts entry #N like any other event.
posts one entry like any other event.
- `bill = { vendor, amount }` as an event: a bill from `vendor` (a name;
a payee's record if one has it) for `amount`, dated and due on the
event's date. It posts entry #N: General Expenses (6999) debited and
event's date. It posts one entry: General Expenses (6999) debited and
Accounts Payable (2000) credited, each account created with that fixed
name when first needed, as the books create a control role's account
(B-32).
- `run_depreciation = { asset, period }` as an event: the asset's run for
`period` (`"YYYY-MM"`), which posts what the schedule says is due
through the month's end and the books don't carry, dated then: a
skipped month caught up, nothing when nothing is due (rules.md B-15).
- `dispose_asset = { asset, proceeds, proceeds_account, gain_loss_account
}` as an event, dated: the asset's disposal for `proceeds` (an exact
decimal, zero allowed), received into `proceeds_account`, its gain or
loss to `gain_loss_account` (B-15). It posts the depreciation still due
through its day in an entry of its own when the month has no run, then
the disposal entry.
- `run_schedules = { through }` as an event: every schedule's months due
through `through` posted (B-16).
- `refused = "<reason>"` on a reversal or a command: the books refuse it,
for that reason (below); it changes nothing, posts nothing, and the
example goes on without it.
- `[[changes]]` `{ after, rename?, require_tax_category? }`: a change
that posts no entry, exactly one of `rename = { code, name }` (rename
the account `code`, B-31) and `require_tax_category = "warn"` or
@@ -213,7 +272,7 @@ answers is refused, never skipped.
| `cash_flow` | `from`, `to` | figures (below) | `ledger-core` `tests/bookspec.rs` |
| `trial_balance` | `as_of` | each account's balance by code, debits less credits (a credit balance negative), every account listed | `ledger-core` `tests/bookspec.rs` |
| `profit_and_loss` | `from`, `to` | each revenue and expense account's activity by code, on its normal side, closing entries left out, every one listed; `net_income`, revenue less expenses | `ledger-core` `tests/bookspec.rs` |
| `entry` | `entry = N`, no dates | entry N's lines, `"<code>.debit"` and `"<code>.credit"` each the sum of that account's lines on that side, every line of the entry named | `ledger-core` `tests/bookspec.rs` |
| `entry` | `entry = N`, no dates | the lines of event N's entry, `"<code>.debit"` and `"<code>.credit"` each the sum of that account's lines on that side, every line of the entry named | `ledger-core` `tests/bookspec.rs` |
| `balances` | `as_of` | each account named by code, its balance on its normal side (a member's capital after a loss is negative); the example names the accounts it shows | `ledger-core` `tests/bookspec.rs` |
| `members_equity` | `from`, `to` | the statement of changes in members' equity (rules.md B-13): `"<member>.beginning"`, `.contributions`, `.net_income`, `.distributions`, `.other`, `.ending`; the example names the figures it shows | `ledger-core` `tests/bookspec.rs` |
| `k1` | `from`, `to` | the K-1 worksheet (B-13; Schedule K-1 Item L): `"<member>.beginning"`, `.contributions_cash`, `.contributions_property`, `.net_income`, `.distributions`, `.other`, `.ending`; the example names the figures it shows (`cash_accounts` required) | `ledger-core` `tests/bookspec.rs` |
@@ -227,6 +286,10 @@ answers is refused, never skipped.
| `calendar_year` | none | the year a calendar-year count (1099s, party totals) asked without one counts: `year` | `ledger-core` `tests/bookspec.rs` |
| `account_names` | none | each account's name by code, as the chart holds it and every report prints it, past periods included (B-31); every account listed, those the books created included | `ledger-core` `tests/bookspec.rs` |
| `uncategorized_accounts` | none | a list: every account that needs a tax category (revenue or expense, not a header) and has none, with activity or not, `"<code> <name>"`, by code (B-32) | `ledger-core` `tests/bookspec.rs` |
| `run` | `event = N`, no dates | what the `run_depreciation` event N posted: `amount` (zero when nothing was due, or the month had its run already), and `caught_up`, what of it is beyond the month's own depreciation (B-15); both listed | `ledger-core` `tests/bookspec.rs` |
| `disposal` | `asset`, no dates | what the asset's disposal took (B-15), every figure listed: `final_depreciation` (posted in its own entry), `catch_up_depreciation` and `excess_depreciation` (charged, and credited back, in the disposal entry), `accumulated` (cleared), `book_value`, `gain_loss` (a gain positive) | `ledger-core` `tests/bookspec.rs` |
| `depreciation_schedule` | `asset`, `as_of` | the asset's schedule through the day (B-15): each month named (`"YYYY-MM"`) its depreciation, `"0.00"` for a month it doesn't reach; `accumulated` and `book_value` through the day; the example names the figures it shows | `ledger-core` `tests/bookspec.rs` |
| `schedule_plan` | `schedule`, no dates | the schedule's plan (B-16): what it recognizes at each month end named (`"YYYY-MM-DD"`), `"0.00"` at one it doesn't post; `total`, all it recognizes; the example names the figures it shows | `ledger-core` `tests/bookspec.rs` |
| `iif_lines` | `as_of` | formats appendix: the file's lines in order, each its fields joined by tabs, without the CR LF that ends each | `ledger-package` `the_bookspec_iif_example_matches_the_engine` |
| `iif_changes` | `as_of` | formats appendix: each text the file writes differently from the books, in file order, as `[what, books' text, file's text]` (the example's header gives `what`) | `ledger-package` `the_bookspec_iif_example_matches_the_engine` |
@@ -255,7 +318,15 @@ name, ignoring capitals and surrounding space), `holds_a_tin` (a run of
nine digits), `not_one_line` (a line break, tab or other control
character, or past 200 characters), `code_taken`, and
`tax_category_required` (an account that needs a category left without
one under `refuse`).
one under `refuse`). A refused event's: `depreciation_past_disposal` (a
disposal dated before depreciation a run carries: a later month's run
stands, or a run's change dated after the disposal's month isn't undone),
`entry_irreversible` (an asset's entry that can't be reversed: its
disposal, a disposed asset's depreciation, a run re-instated twice or past
its schedule, or a reversal dated before its run), `already_disposed`,
`invalid_depreciation_period` (a month that ends before the asset is in
service) and `invalid_schedule` (an equal-months schedule not starting on
the 1st, among others).
`cash_flow` (rules.md B-14): the statement of cash flows for `[from, to]`.
@@ -265,10 +336,10 @@ one under `refuse`).
| `net_change`, `cash_beginning`, `cash_ending` | the cash accounts' change and balances |
| `difference` | sections less the change in cash: always `"0.00"` |
| `net_income` | revenue less expenses, closing entries excluded |
| `<section>.<N>` | entry N's cash in that section (`financing.4`) |
| `<section>.<N>` | event N's entry's cash in that section (`financing.4`) |
| `<section>.<N>.on_behalf` | of it, what a member or a lender paid or received for the company, no cash account moving (constructive receipt and disbursement) |
| `<section>.count` | how many entries the section lists |
| `noncash.<N>` | entry N's noncash investing and financing disclosure |
| `noncash.<N>` | event N's entry's noncash investing and financing disclosure |
| `noncash.count` | how many entries are disclosed |
| `reconciliation.depreciation` | depreciation added back |
| `reconciliation.investing_gain_loss` | gains and losses whose cash is investing, taken out |
@@ -284,8 +355,9 @@ reconciliation key not given must be zero or absent.
Every example, in any appendix, is loaded by
`crates/ledger-core/tests/bookspec.rs` (`every_bookspec_example_holds`):
its shape (a key the shape doesn't have is refused), its setup, and every
event posted. Each query is then checked by the crate that answers it (the
table above), so the shape never rots either.
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.
## Licence and sources
+112
View File
@@ -0,0 +1,112 @@
id = "depreciation-catch-up-month"
title = "A month of depreciation skipped is caught up in the month the run is made"
rule = "A depreciation run for a month posts everything the schedule says is due through that month's end that the books don't carry, so a skipped month is caught up in it, and a later run for the skipped month posts nothing."
status = "CHOICE"
sources = ["ASC 360-10-35-4", "DECISION: plan/served.md P3, Settled in design (2026-10-20)"]
tags = ["depreciation", "catch-up", "skipped-month", "p3"]
[setup]
currency = "USD"
fiscal_year_start = "01-01"
basis = "accrual"
rounding = "half-away-from-zero"
[[setup.accounts]]
code = "1000"
name = "Bank"
type = "asset"
[[setup.accounts]]
code = "1500"
name = "Equipment"
type = "asset"
[[setup.accounts]]
code = "1510"
name = "Accumulated Depreciation"
type = "asset"
[[setup.accounts]]
code = "3000"
name = "Capital"
type = "equity"
[[setup.accounts]]
code = "6200"
name = "Depreciation Expense"
type = "expense"
[[setup.accounts]]
code = "7100"
name = "Gain or Loss on Disposal"
type = "revenue"
# Asset X: 12,000.00, no salvage, 12 months from 2026-01-01 (1,000.00 a
# month; December the final month).
[[setup.assets]]
id = "X"
description = "Asset X"
cost = "12000.00"
salvage = "0.00"
life_months = 12
in_service = "2026-01-01"
method = "straight_line"
cost_account = "1500"
accumulated_account = "1510"
expense_account = "6200"
[[events]]
date = "2026-01-01"
description = "Capital"
lines = [
{ account = "1000", side = "debit", amount = "12000.00" },
{ account = "3000", side = "credit", amount = "12000.00" },
]
[[events]]
date = "2026-01-01"
description = "Bought asset X"
lines = [
{ account = "1500", side = "debit", amount = "12000.00" },
{ account = "1000", side = "credit", amount = "12000.00" },
]
[[events]]
run_depreciation = { asset = "X", period = "2026-01" }
# February is skipped; March is run.
[[events]]
run_depreciation = { asset = "X", period = "2026-03" }
# February run afterwards: nothing is due (March caught it up).
[[events]]
run_depreciation = { asset = "X", period = "2026-02" }
# Hand check (worked without the code): the schedule through Mar 31 is
# 3 x 1,000.00 = 3,000.00; January's run carried 1,000.00, so March's run
# posts 2,000.00 (its own 1,000.00 and February's, caught up). February's
# run then posts 0.00: the books already carry the schedule through
# February's end and beyond.
[[expect]]
query = "run"
event = 4
[expect.values]
amount = "2000.00"
caught_up = "1000.00"
[[expect]]
query = "run"
event = 5
[expect.values]
amount = "0.00"
caught_up = "0.00"
[[expect]]
query = "balances"
as_of = "2026-03-31"
[expect.values]
"1510" = "-3000.00"
"6200" = "3000.00"
@@ -0,0 +1,158 @@
id = "depreciation-disposal-after-a-late-change-undone"
title = "A disposal is taken once a late change to an earlier run is undone, on any later day"
rule = "A disposal clears what the asset's runs carry now, so it waits until each run carries at the end of the disposal's month what it carries now. A reversal of an earlier run dated after that month is undone by reversing it, on any open day: the disposal month and the end are then right, and a later month end keeps the change and its correction as they were made."
status = "CONVENTION"
sources = ["ASC 360-10-35-4", "Pacioli 1494, ch. 31"]
tags = ["depreciation", "disposal", "refusal", "reversal", "p3-defect-22"]
[setup]
currency = "USD"
fiscal_year_start = "01-01"
basis = "accrual"
rounding = "half-away-from-zero"
[[setup.accounts]]
code = "1000"
name = "Bank"
type = "asset"
[[setup.accounts]]
code = "1500"
name = "Equipment"
type = "asset"
[[setup.accounts]]
code = "1510"
name = "Accumulated Depreciation"
type = "asset"
[[setup.accounts]]
code = "3000"
name = "Capital"
type = "equity"
[[setup.accounts]]
code = "6200"
name = "Depreciation Expense"
type = "expense"
[[setup.accounts]]
code = "7100"
name = "Gain or Loss on Disposal"
type = "revenue"
# Asset X: 12,000.00, no salvage, 12 months from 2026-01-01 (1,000.00 a
# month; December the final month).
[[setup.assets]]
id = "X"
description = "Asset X"
cost = "12000.00"
salvage = "0.00"
life_months = 12
in_service = "2026-01-01"
method = "straight_line"
cost_account = "1500"
accumulated_account = "1510"
expense_account = "6200"
[[events]]
date = "2026-01-01"
description = "Capital"
lines = [
{ account = "1000", side = "debit", amount = "12000.00" },
{ account = "3000", side = "credit", amount = "12000.00" },
]
[[events]]
date = "2026-01-01"
description = "Bought asset X"
lines = [
{ account = "1500", side = "debit", amount = "12000.00" },
{ account = "1000", side = "credit", amount = "12000.00" },
]
[[events]]
run_depreciation = { asset = "X", period = "2026-01" }
[[events]]
run_depreciation = { asset = "X", period = "2026-02" }
[[events]]
run_depreciation = { asset = "X", period = "2026-03" }
[[events]]
run_depreciation = { asset = "X", period = "2026-04" }
[[events]]
run_depreciation = { asset = "X", period = "2026-05" }
# May's run reversed on Aug 1 (doubted). Its month, and July's, still
# carried it at their ends.
[[events]]
date = "2026-08-01"
description = "Reverse event 7"
reverses = 7
# Disposed of 2026-06-15 for 7,000.00: refused. The disposal clears what
# the runs carry now (January to April, 4,000.00) and would charge May
# again at Jun 15, so June would end carrying 6,500.00 against a
# schedule of 5,500.00. The refusal names May's run and the reversal.
[[events]]
date = "2026-06-15"
dispose_asset = { asset = "X", proceeds = "7000.00", proceeds_account = "1000", gain_loss_account = "7100" }
refused = "depreciation_past_disposal"
# May was right: its reversal reversed on Sep 2 (August may be closed by
# then; any open day undoes it).
[[events]]
date = "2026-09-02"
description = "Reverse event 8"
reverses = 8
[[events]]
date = "2026-06-15"
dispose_asset = { asset = "X", proceeds = "7000.00", proceeds_account = "1000", gain_loss_account = "7100" }
# Hand check (worked without the code): the runs carry 5,000.00 at Jun 30
# and now. Held through Jun 15: 5,000.00 + 1,000.00 x 15/30 = 5,500.00, so
# the final depreciation is 500.00 and the disposal clears 5,500.00. Book
# value 6,500.00; gain 7,000.00 - 6,500.00 = 500.00. August's end carries
# May's reversal (accumulated depreciation a 1,000.00 debit, the expense
# 4,500.00) and September's its correction, as they would without the
# disposal.
[[expect]]
query = "disposal"
asset = "X"
[expect.values]
final_depreciation = "500.00"
catch_up_depreciation = "0.00"
excess_depreciation = "0.00"
accumulated = "5500.00"
book_value = "6500.00"
gain_loss = "500.00"
[[expect]]
query = "balances"
as_of = "2026-06-30"
[expect.values]
"1510" = "0.00"
"6200" = "5500.00"
"7100" = "500.00"
[[expect]]
query = "balances"
as_of = "2026-08-31"
[expect.values]
"1510" = "1000.00"
"6200" = "4500.00"
[[expect]]
query = "balances"
as_of = "2026-09-30"
[expect.values]
"1510" = "0.00"
"6200" = "5500.00"
@@ -0,0 +1,146 @@
id = "depreciation-disposal-before-a-later-run"
title = "A disposal dated before a later month's run is refused until that run is reversed"
rule = "A disposal is refused while a run of a month after the disposal's stands: crediting it back at the disposal day would leave the disposal month's accumulated depreciation a debit and its expense short at the month's end. Once that run is reversed, the disposal takes the depreciation of the days held."
status = "CONVENTION"
sources = ["ASC 360-10-35-4"]
tags = ["depreciation", "disposal", "refusal", "later-run", "p3-defect-22"]
[setup]
currency = "USD"
fiscal_year_start = "01-01"
basis = "accrual"
rounding = "half-away-from-zero"
[[setup.accounts]]
code = "1000"
name = "Bank"
type = "asset"
[[setup.accounts]]
code = "1500"
name = "Equipment"
type = "asset"
[[setup.accounts]]
code = "1510"
name = "Accumulated Depreciation"
type = "asset"
[[setup.accounts]]
code = "3000"
name = "Capital"
type = "equity"
[[setup.accounts]]
code = "6200"
name = "Depreciation Expense"
type = "expense"
[[setup.accounts]]
code = "7100"
name = "Gain or Loss on Disposal"
type = "revenue"
# Asset X: 12,000.00, no salvage, 12 months from 2026-01-01 (1,000.00 a
# month; December the final month).
[[setup.assets]]
id = "X"
description = "Asset X"
cost = "12000.00"
salvage = "0.00"
life_months = 12
in_service = "2026-01-01"
method = "straight_line"
cost_account = "1500"
accumulated_account = "1510"
expense_account = "6200"
[[events]]
date = "2026-01-01"
description = "Capital"
lines = [
{ account = "1000", side = "debit", amount = "12000.00" },
{ account = "3000", side = "credit", amount = "12000.00" },
]
[[events]]
date = "2026-01-01"
description = "Bought asset X"
lines = [
{ account = "1500", side = "debit", amount = "12000.00" },
{ account = "1000", side = "credit", amount = "12000.00" },
]
[[events]]
run_depreciation = { asset = "X", period = "2026-01" }
[[events]]
run_depreciation = { asset = "X", period = "2026-02" }
[[events]]
run_depreciation = { asset = "X", period = "2026-03" }
[[events]]
run_depreciation = { asset = "X", period = "2026-04" }
[[events]]
run_depreciation = { asset = "X", period = "2026-05" }
[[events]]
run_depreciation = { asset = "X", period = "2026-06" }
[[events]]
run_depreciation = { asset = "X", period = "2026-07" }
# Disposed of 2026-06-15 for 7,000.00, after July's run: refused, naming
# July's run.
[[events]]
date = "2026-06-15"
dispose_asset = { asset = "X", proceeds = "7000.00", proceeds_account = "1000", gain_loss_account = "7100" }
refused = "depreciation_past_disposal"
# July's run reversed, dated in July.
[[events]]
date = "2026-07-31"
description = "Reverse event 9"
reverses = 9
[[events]]
date = "2026-06-15"
dispose_asset = { asset = "X", proceeds = "7000.00", proceeds_account = "1000", gain_loss_account = "7100" }
# Hand check (worked without the code): January through June carry
# 6,000.00 once July's run is reversed. Held through Jun 15: 5,000.00 +
# 1,000.00 x 15/30 = 5,500.00, so June's run posted 500.00 past the
# disposal day. Book value 6,500.00; gain 7,000.00 - 6,500.00 = 500.00.
# Had the disposal taken July's run back at Jun 15 (1,500.00 credited),
# June would end with accumulated depreciation a 1,000.00 debit and
# 4,500.00 of expense.
[[expect]]
query = "disposal"
asset = "X"
[expect.values]
final_depreciation = "0.00"
catch_up_depreciation = "0.00"
excess_depreciation = "500.00"
accumulated = "6000.00"
book_value = "6500.00"
gain_loss = "500.00"
[[expect]]
query = "balances"
as_of = "2026-06-30"
[expect.values]
"1510" = "0.00"
"6200" = "5500.00"
"7100" = "500.00"
[[expect]]
query = "balances"
as_of = "2026-07-31"
[expect.values]
"1510" = "0.00"
"6200" = "5500.00"
@@ -0,0 +1,136 @@
id = "depreciation-disposal-in-final-month"
title = "A disposal in the life's final month depreciates that month by its days held"
rule = "A disposal dated inside an asset's final month takes depreciation for the days held in that month, not the month's whole charge."
status = "CONVENTION"
sources = ["ASC 360-10-35-4"]
tags = ["depreciation", "disposal", "final-month", "p3-defect-22"]
[setup]
currency = "USD"
fiscal_year_start = "01-01"
basis = "accrual"
rounding = "half-away-from-zero"
[[setup.accounts]]
code = "1000"
name = "Bank"
type = "asset"
[[setup.accounts]]
code = "1500"
name = "Equipment"
type = "asset"
[[setup.accounts]]
code = "1510"
name = "Accumulated Depreciation"
type = "asset"
[[setup.accounts]]
code = "3000"
name = "Capital"
type = "equity"
[[setup.accounts]]
code = "6200"
name = "Depreciation Expense"
type = "expense"
[[setup.accounts]]
code = "7100"
name = "Gain or Loss on Disposal"
type = "revenue"
# Asset X: 12,000.00, no salvage, 12 months from 2026-01-01 (1,000.00 a
# month; December the final month).
[[setup.assets]]
id = "X"
description = "Asset X"
cost = "12000.00"
salvage = "0.00"
life_months = 12
in_service = "2026-01-01"
method = "straight_line"
cost_account = "1500"
accumulated_account = "1510"
expense_account = "6200"
[[events]]
date = "2026-01-01"
description = "Capital"
lines = [
{ account = "1000", side = "debit", amount = "12000.00" },
{ account = "3000", side = "credit", amount = "12000.00" },
]
[[events]]
date = "2026-01-01"
description = "Bought asset X"
lines = [
{ account = "1500", side = "debit", amount = "12000.00" },
{ account = "1000", side = "credit", amount = "12000.00" },
]
[[events]]
run_depreciation = { asset = "X", period = "2026-01" }
[[events]]
run_depreciation = { asset = "X", period = "2026-02" }
[[events]]
run_depreciation = { asset = "X", period = "2026-03" }
[[events]]
run_depreciation = { asset = "X", period = "2026-04" }
[[events]]
run_depreciation = { asset = "X", period = "2026-05" }
[[events]]
run_depreciation = { asset = "X", period = "2026-06" }
[[events]]
run_depreciation = { asset = "X", period = "2026-07" }
[[events]]
run_depreciation = { asset = "X", period = "2026-08" }
[[events]]
run_depreciation = { asset = "X", period = "2026-09" }
[[events]]
run_depreciation = { asset = "X", period = "2026-10" }
[[events]]
run_depreciation = { asset = "X", period = "2026-11" }
# Disposed of 2026-12-10 for 1,000.00.
[[events]]
date = "2026-12-10"
dispose_asset = { asset = "X", proceeds = "1000.00", proceeds_account = "1000", gain_loss_account = "7100" }
# Hand check (worked without the code): January..November run, 11,000.00.
# December held through the 10th: 1,000.00 x 10/31 = 322.580... -> 322.58.
# Accumulated 11,322.58; book value 677.42; gain 1,000.00 - 677.42 =
# 322.58. (Before P3: 1,000.00 of depreciation and a 1,000.00 gain.)
[[expect]]
query = "disposal"
asset = "X"
[expect.values]
final_depreciation = "322.58"
catch_up_depreciation = "0.00"
excess_depreciation = "0.00"
accumulated = "11322.58"
book_value = "677.42"
gain_loss = "322.58"
[[expect]]
query = "balances"
as_of = "2026-12-31"
[expect.values]
"1000" = "1000.00"
"1510" = "0.00"
"6200" = "11322.58"
"7100" = "322.58"
@@ -0,0 +1,122 @@
id = "depreciation-disposal-inside-a-posted-month"
title = "A disposal inside a month already run takes back the days after it"
rule = "When a month's depreciation was posted through its end and the asset is disposed of inside that month, the disposal credits back the depreciation for the days after the disposal day, so book value and gain are of the days held."
status = "CONVENTION"
sources = ["ASC 360-10-35-4"]
tags = ["depreciation", "disposal", "mid-month", "excess-depreciation", "p3-defect-22"]
[setup]
currency = "USD"
fiscal_year_start = "01-01"
basis = "accrual"
rounding = "half-away-from-zero"
[[setup.accounts]]
code = "1000"
name = "Bank"
type = "asset"
[[setup.accounts]]
code = "1500"
name = "Equipment"
type = "asset"
[[setup.accounts]]
code = "1510"
name = "Accumulated Depreciation"
type = "asset"
[[setup.accounts]]
code = "3000"
name = "Capital"
type = "equity"
[[setup.accounts]]
code = "6200"
name = "Depreciation Expense"
type = "expense"
[[setup.accounts]]
code = "7100"
name = "Gain or Loss on Disposal"
type = "revenue"
# Asset X: 12,000.00, no salvage, 12 months from 2026-01-01 (1,000.00 a
# month; December the final month).
[[setup.assets]]
id = "X"
description = "Asset X"
cost = "12000.00"
salvage = "0.00"
life_months = 12
in_service = "2026-01-01"
method = "straight_line"
cost_account = "1500"
accumulated_account = "1510"
expense_account = "6200"
[[events]]
date = "2026-01-01"
description = "Capital"
lines = [
{ account = "1000", side = "debit", amount = "12000.00" },
{ account = "3000", side = "credit", amount = "12000.00" },
]
[[events]]
date = "2026-01-01"
description = "Bought asset X"
lines = [
{ account = "1500", side = "debit", amount = "12000.00" },
{ account = "1000", side = "credit", amount = "12000.00" },
]
[[events]]
run_depreciation = { asset = "X", period = "2026-01" }
[[events]]
run_depreciation = { asset = "X", period = "2026-02" }
[[events]]
run_depreciation = { asset = "X", period = "2026-03" }
[[events]]
run_depreciation = { asset = "X", period = "2026-04" }
[[events]]
run_depreciation = { asset = "X", period = "2026-05" }
[[events]]
run_depreciation = { asset = "X", period = "2026-06" }
# Disposed of 2026-06-15 for 7,000.00, after June's run (dated Jun 30).
[[events]]
date = "2026-06-15"
dispose_asset = { asset = "X", proceeds = "7000.00", proceeds_account = "1000", gain_loss_account = "7100" }
# Hand check (worked without the code): the runs carried 6,000.00. Held
# through Jun 15: 5,000.00 + 1,000.00 x 15/30 = 5,500.00, so 500.00 was
# posted past the disposal day. The disposal entry: Dr accumulated
# depreciation 6,000.00, Dr bank 7,000.00 / Cr equipment 12,000.00, Cr
# depreciation expense 500.00, Cr gain 500.00 (13,000.00 a side). Book
# value 6,500.00; gain 7,000.00 - 6,500.00 = 500.00.
[[expect]]
query = "disposal"
asset = "X"
[expect.values]
final_depreciation = "0.00"
catch_up_depreciation = "0.00"
excess_depreciation = "500.00"
accumulated = "6000.00"
book_value = "6500.00"
gain_loss = "500.00"
[[expect]]
query = "balances"
as_of = "2026-06-30"
[expect.values]
"1510" = "0.00"
"6200" = "5500.00"
"7100" = "500.00"
@@ -0,0 +1,134 @@
id = "depreciation-disposal-mid-month"
title = "A disposed asset depreciates through its disposal day, and its schedule stops there"
rule = "An asset disposed of mid-month is depreciated through the disposal day, held, and its schedule, accumulated depreciation and book value afterwards are what the disposal took."
status = "CONVENTION"
sources = ["ASC 360-10-35-4"]
tags = ["depreciation", "disposal", "mid-month", "p3-defect-22"]
[setup]
currency = "USD"
fiscal_year_start = "01-01"
basis = "accrual"
rounding = "half-away-from-zero"
[[setup.accounts]]
code = "1000"
name = "Bank"
type = "asset"
[[setup.accounts]]
code = "1500"
name = "Equipment"
type = "asset"
[[setup.accounts]]
code = "1510"
name = "Accumulated Depreciation"
type = "asset"
[[setup.accounts]]
code = "3000"
name = "Capital"
type = "equity"
[[setup.accounts]]
code = "6200"
name = "Depreciation Expense"
type = "expense"
[[setup.accounts]]
code = "7100"
name = "Gain or Loss on Disposal"
type = "revenue"
# Asset X: 12,000.00, no salvage, 12 months from 2026-01-01 (1,000.00 a
# month; December the final month).
[[setup.assets]]
id = "X"
description = "Asset X"
cost = "12000.00"
salvage = "0.00"
life_months = 12
in_service = "2026-01-01"
method = "straight_line"
cost_account = "1500"
accumulated_account = "1510"
expense_account = "6200"
[[events]]
date = "2026-01-01"
description = "Capital"
lines = [
{ account = "1000", side = "debit", amount = "12000.00" },
{ account = "3000", side = "credit", amount = "12000.00" },
]
[[events]]
date = "2026-01-01"
description = "Bought asset X"
lines = [
{ account = "1500", side = "debit", amount = "12000.00" },
{ account = "1000", side = "credit", amount = "12000.00" },
]
[[events]]
run_depreciation = { asset = "X", period = "2026-01" }
[[events]]
run_depreciation = { asset = "X", period = "2026-02" }
[[events]]
run_depreciation = { asset = "X", period = "2026-03" }
[[events]]
run_depreciation = { asset = "X", period = "2026-04" }
[[events]]
run_depreciation = { asset = "X", period = "2026-05" }
# Disposed of 2026-06-15 for 7,000.00.
[[events]]
date = "2026-06-15"
dispose_asset = { asset = "X", proceeds = "7000.00", proceeds_account = "1000", gain_loss_account = "7100" }
# Hand check (worked without the code): January..May run, 5 x 1,000.00 =
# 5,000.00. June held through the 15th: 1,000.00 x 15/30 = 500.00, the
# final depreciation. Accumulated 5,500.00; book value 12,000.00 -
# 5,500.00 = 6,500.00; gain 7,000.00 - 6,500.00 = 500.00.
[[expect]]
query = "disposal"
asset = "X"
[expect.values]
final_depreciation = "500.00"
catch_up_depreciation = "0.00"
excess_depreciation = "0.00"
accumulated = "5500.00"
book_value = "6500.00"
gain_loss = "500.00"
# The disposed asset's schedule ends on the disposal day, whatever date it
# is asked through.
[[expect]]
query = "depreciation_schedule"
asset = "X"
as_of = "2030-12-31"
[expect.values]
"2026-06" = "500.00"
accumulated = "5500.00"
book_value = "6500.00"
# The books: depreciation expense 5,500.00 (debit), the gain 500.00
# (credit), accumulated depreciation and equipment cleared, the bank
# 7,000.00 (debit).
[[expect]]
query = "balances"
as_of = "2026-06-30"
[expect.values]
"1000" = "7000.00"
"1500" = "0.00"
"1510" = "0.00"
"6200" = "5500.00"
"7100" = "500.00"
@@ -0,0 +1,93 @@
id = "depreciation-final-month-by-days"
title = "Straight-line depreciation by the day through the life's final month"
rule = "Depreciation through a day of an asset's final month is the depreciation before that month plus the final month's share for the days held, never the whole remaining cost."
status = "CONVENTION"
sources = ["ASC 360-10-35-4"]
tags = ["depreciation", "straight-line", "final-month", "p3-defect-22"]
[setup]
currency = "USD"
fiscal_year_start = "01-01"
basis = "accrual"
rounding = "half-away-from-zero"
[[setup.accounts]]
code = "1000"
name = "Bank"
type = "asset"
[[setup.accounts]]
code = "1500"
name = "Equipment"
type = "asset"
[[setup.accounts]]
code = "1510"
name = "Accumulated Depreciation"
type = "asset"
[[setup.accounts]]
code = "3000"
name = "Capital"
type = "equity"
[[setup.accounts]]
code = "6200"
name = "Depreciation Expense"
type = "expense"
# Asset X: 12,000.00, no salvage, 12 months from 2026-01-01. Its life is
# 2026-01-01 through 2026-12-31; December is its final month.
[[setup.assets]]
id = "X"
description = "Asset X"
cost = "12000.00"
salvage = "0.00"
life_months = 12
in_service = "2026-01-01"
method = "straight_line"
cost_account = "1500"
accumulated_account = "1510"
expense_account = "6200"
[[events]]
date = "2026-01-01"
description = "Capital"
lines = [
{ account = "1000", side = "debit", amount = "12000.00" },
{ account = "3000", side = "credit", amount = "12000.00" },
]
[[events]]
date = "2026-01-01"
description = "Bought asset X"
lines = [
{ account = "1500", side = "debit", amount = "12000.00" },
{ account = "1000", side = "credit", amount = "12000.00" },
]
# Hand check (worked without the code): 12,000.00 / 12 = 1,000.00 a month.
# Through Dec 15: January..November, 11 x 1,000.00 = 11,000.00, plus
# December's 1,000.00 x 15/31 = 483.870... -> 483.87 (half away from zero).
# Accumulated 11,483.87; book value 12,000.00 - 11,483.87 = 516.13.
[[expect]]
query = "depreciation_schedule"
asset = "X"
as_of = "2026-12-15"
[expect.values]
"2026-11" = "1000.00"
"2026-12" = "483.87"
accumulated = "11483.87"
book_value = "516.13"
# Hand check: through the life's last day, the whole of it.
[[expect]]
query = "depreciation_schedule"
asset = "X"
as_of = "2026-12-31"
[expect.values]
"2026-12" = "1000.00"
accumulated = "12000.00"
book_value = "0.00"
@@ -0,0 +1,98 @@
id = "depreciation-final-month-drift"
title = "The final month of a mid-month life takes what the months before it leave, evenly over its days"
rule = "When a life does not start on the 1st, its final month is charged the depreciable amount less what the months before it took, spread evenly over the final month's days."
status = "CONVENTION"
sources = ["ASC 360-10-35-4"]
tags = ["depreciation", "straight-line", "final-month", "month-length-drift", "p3-defect-22"]
[setup]
currency = "USD"
fiscal_year_start = "01-01"
basis = "accrual"
rounding = "half-away-from-zero"
[[setup.accounts]]
code = "1000"
name = "Bank"
type = "asset"
[[setup.accounts]]
code = "1500"
name = "Equipment"
type = "asset"
[[setup.accounts]]
code = "1510"
name = "Accumulated Depreciation"
type = "asset"
[[setup.accounts]]
code = "3000"
name = "Capital"
type = "equity"
[[setup.accounts]]
code = "6200"
name = "Depreciation Expense"
type = "expense"
# Cost 1,030.00, salvage 100.00 (930.00 to depreciate), 3 months from
# 2026-01-15: the life is 2026-01-15 through 2026-04-14.
[[setup.assets]]
id = "D"
description = "Asset D"
cost = "1030.00"
salvage = "100.00"
life_months = 3
in_service = "2026-01-15"
method = "straight_line"
cost_account = "1500"
accumulated_account = "1510"
expense_account = "6200"
[[events]]
date = "2026-01-15"
description = "Capital"
lines = [
{ account = "1000", side = "debit", amount = "1030.00" },
{ account = "3000", side = "credit", amount = "1030.00" },
]
[[events]]
date = "2026-01-15"
description = "Bought asset D"
lines = [
{ account = "1500", side = "debit", amount = "1030.00" },
{ account = "1000", side = "credit", amount = "1030.00" },
]
# Hand check (worked without the code): 930.00 / 3 = 310.00 a month.
# January holds 17 of its 31 days: 310.00 x 17/31 = 170.00. February and
# March are whole: 310.00 each. Before April: 790.00. April holds 14 days
# (1-14) and is charged what is left, 930.00 - 790.00 = 140.00, evenly:
# 10.00 a day (January's own daily rate, 310.00/31). Through Apr 13:
# 130.00; accumulated 920.00; book value 1,030.00 - 920.00 = 110.00.
[[expect]]
query = "depreciation_schedule"
asset = "D"
as_of = "2026-04-13"
[expect.values]
"2026-01" = "170.00"
"2026-02" = "310.00"
"2026-03" = "310.00"
"2026-04" = "130.00"
accumulated = "920.00"
book_value = "110.00"
# Through Apr 14, the life's last day: April 140.00, accumulated 930.00,
# book value 100.00 (the salvage, never depreciated).
[[expect]]
query = "depreciation_schedule"
asset = "D"
as_of = "2026-04-14"
[expect.values]
"2026-04" = "140.00"
accumulated = "930.00"
book_value = "100.00"
@@ -0,0 +1,114 @@
id = "depreciation-reversal-before-its-run-is-refused"
title = "A depreciation run can't be reversed on a day before its own"
rule = "A correction comes after what it corrects: a depreciation run, or a reversal of one, can't be reversed on a day before its own. A run of March reversed on Jan 31 would leave January and February with negative depreciation."
status = "AUTHORITY"
sources = ["Pacioli 1494, ch. 31"]
tags = ["depreciation", "reversal", "refusal", "p3-defect-22"]
[setup]
currency = "USD"
fiscal_year_start = "01-01"
basis = "accrual"
rounding = "half-away-from-zero"
[[setup.accounts]]
code = "1000"
name = "Bank"
type = "asset"
[[setup.accounts]]
code = "1500"
name = "Equipment"
type = "asset"
[[setup.accounts]]
code = "1510"
name = "Accumulated Depreciation"
type = "asset"
[[setup.accounts]]
code = "3000"
name = "Capital"
type = "equity"
[[setup.accounts]]
code = "6200"
name = "Depreciation Expense"
type = "expense"
[[setup.accounts]]
code = "7100"
name = "Gain or Loss on Disposal"
type = "revenue"
# Asset X: 12,000.00, no salvage, 12 months from 2026-01-01 (1,000.00 a
# month; December the final month).
[[setup.assets]]
id = "X"
description = "Asset X"
cost = "12000.00"
salvage = "0.00"
life_months = 12
in_service = "2026-01-01"
method = "straight_line"
cost_account = "1500"
accumulated_account = "1510"
expense_account = "6200"
[[events]]
date = "2026-01-01"
description = "Capital"
lines = [
{ account = "1000", side = "debit", amount = "12000.00" },
{ account = "3000", side = "credit", amount = "12000.00" },
]
[[events]]
date = "2026-01-01"
description = "Bought asset X"
lines = [
{ account = "1500", side = "debit", amount = "12000.00" },
{ account = "1000", side = "credit", amount = "12000.00" },
]
[[events]]
run_depreciation = { asset = "X", period = "2026-01" }
[[events]]
run_depreciation = { asset = "X", period = "2026-02" }
[[events]]
run_depreciation = { asset = "X", period = "2026-03" }
# March's run (dated Mar 31) reversed on Feb 10: refused, naming its date.
[[events]]
date = "2026-02-10"
description = "Reverse event 5"
reverses = 5
refused = "entry_irreversible"
# On its own day it is taken.
[[events]]
date = "2026-03-31"
description = "Reverse event 5"
reverses = 5
# Hand check (worked without the code): January and February carry
# 2,000.00 at February's end, never 1,000.00 (with March's 1,000.00 taken
# away on Feb 10); March's end carries 2,000.00 (its run and its reversal
# both dated Mar 31).
[[expect]]
query = "balances"
as_of = "2026-02-28"
[expect.values]
"1510" = "-2000.00"
"6200" = "2000.00"
[[expect]]
query = "balances"
as_of = "2026-03-31"
[expect.values]
"1510" = "-2000.00"
"6200" = "2000.00"
@@ -0,0 +1,121 @@
id = "depreciation-run-reversed-after-its-month"
title = "A run reversed after its month ended is caught up in the reversal's month, never posted twice"
rule = "What the books carry is read entry by entry, each in its own month: a run reversed after its month ended still carried that month at its end, so running the month again posts nothing, and the run of the reversal's month catches the month up."
status = "CHOICE"
sources = ["ASC 360-10-35-4", "DECISION: plan/served.md P3, Settled in design (2026-10-20)", "docs/spec/rules.md B-9"]
tags = ["depreciation", "catch-up", "reversal", "p3"]
[setup]
currency = "USD"
fiscal_year_start = "01-01"
basis = "accrual"
rounding = "half-away-from-zero"
[[setup.accounts]]
code = "1000"
name = "Bank"
type = "asset"
[[setup.accounts]]
code = "1500"
name = "Equipment"
type = "asset"
[[setup.accounts]]
code = "1510"
name = "Accumulated Depreciation"
type = "asset"
[[setup.accounts]]
code = "3000"
name = "Capital"
type = "equity"
[[setup.accounts]]
code = "6200"
name = "Depreciation Expense"
type = "expense"
# Asset X: 12,000.00, no salvage, 12 months from 2026-01-01 (1,000.00 a
# month; December the final month).
[[setup.assets]]
id = "X"
description = "Asset X"
cost = "12000.00"
salvage = "0.00"
life_months = 12
in_service = "2026-01-01"
method = "straight_line"
cost_account = "1500"
accumulated_account = "1510"
expense_account = "6200"
[[events]]
date = "2026-01-01"
description = "Capital"
lines = [
{ account = "1000", side = "debit", amount = "12000.00" },
{ account = "3000", side = "credit", amount = "12000.00" },
]
[[events]]
date = "2026-01-01"
description = "Bought asset X"
lines = [
{ account = "1500", side = "debit", amount = "12000.00" },
{ account = "1000", side = "credit", amount = "12000.00" },
]
[[events]]
run_depreciation = { asset = "X", period = "2026-01" }
# January's run reversed on 2026-02-02, after January ended.
[[events]]
date = "2026-02-02"
description = "Reverse event 3"
reverses = 3
# January run again: nothing is due (Jan 31 carried January).
[[events]]
run_depreciation = { asset = "X", period = "2026-01" }
[[events]]
run_depreciation = { asset = "X", period = "2026-02" }
# Hand check (worked without the code): January's run (1,000.00, dated Jan
# 31) stood on Jan 31, so the books carried the schedule there, 1,000.00;
# running January again posts 0.00 (were it to post, Jan 31 would carry
# 2,000.00). The reversal took 1,000.00 away on Feb 2, so February's run
# posts the schedule through Feb 28, 2,000.00, less the 0.00 then carried:
# 2,000.00, of which 1,000.00 is January caught up.
[[expect]]
query = "run"
event = 5
[expect.values]
amount = "0.00"
caught_up = "0.00"
[[expect]]
query = "run"
event = 6
[expect.values]
amount = "2000.00"
caught_up = "1000.00"
[[expect]]
query = "balances"
as_of = "2026-01-31"
[expect.values]
"1510" = "-1000.00"
"6200" = "1000.00"
[[expect]]
query = "balances"
as_of = "2026-02-28"
[expect.values]
"1510" = "-2000.00"
"6200" = "2000.00"
@@ -0,0 +1,75 @@
id = "schedule-daily-deferred-revenue"
title = "Deferred revenue is earned by the day, to the cent"
rule = "Revenue collected in advance for a service over time is recognized as each day of the service passes, one posting per calendar month, the last month taking what the others leave."
status = "CHOICE"
sources = ["ASC 606-10-25-23", "DECISION: plan/served.md D-11, D-37 (owner, 2026-10-20)"]
tags = ["schedules", "deferred-revenue", "daily", "p3-defect-9"]
[setup]
currency = "USD"
fiscal_year_start = "01-01"
basis = "accrual"
rounding = "half-away-from-zero"
[[setup.accounts]]
code = "1000"
name = "Bank"
type = "asset"
[[setup.accounts]]
code = "2400"
name = "Deferred Revenue"
type = "liability"
[[setup.accounts]]
code = "4000"
name = "Subscription Revenue"
type = "revenue"
# 1,000.00 collected for service 2026-01-05 through 2026-04-04.
[[setup.schedules]]
id = "SUB"
kind = "deferred_revenue"
description = "Quarterly plan, a customer"
total = "1000.00"
start = "2026-01-05"
months = 3
convention = "daily"
balance_account = "2400"
pl_account = "4000"
[[events]]
date = "2026-01-05"
description = "Collected a quarter up front"
lines = [
{ account = "1000", side = "debit", amount = "1000.00" },
{ account = "2400", side = "credit", amount = "1000.00" },
]
[[events]]
run_schedules = { through = "2026-04-30" }
# Hand check (worked without the code): January holds 27 of its 31 days
# (5-31); February and March are whole; April holds days 1-4 and takes the
# rest. Cumulative at each month end: 1,000 x (27/31)/3 = 290.3226 ->
# 290.32; 1,000 x (27/31 + 1)/3 = 623.6559 -> 623.66; 1,000 x (27/31 +
# 2)/3 = 956.9892 -> 956.99; then 1,000.00. Months: 290.32, 333.34,
# 333.33, 43.01.
[[expect]]
query = "schedule_plan"
schedule = "SUB"
[expect.values]
"2026-01-31" = "290.32"
"2026-02-28" = "333.34"
"2026-03-31" = "333.33"
"2026-04-30" = "43.01"
# Earned through March: 956.99; still owed for April 1-4: 43.01.
[[expect]]
query = "balances"
as_of = "2026-03-31"
[expect.values]
"2400" = "43.01"
"4000" = "956.99"
@@ -0,0 +1,107 @@
id = "schedule-daily-small-first-and-last-month"
title = "A prepaid expense spread by the day: a small first and last month around full ones"
rule = "A prepaid expense covering whole months from a mid-month start is expensed by the day: each full month an equal share, the first month its days' share, and the last month what the others leave, one posting per calendar month touched."
status = "CHOICE"
sources = ["ASC 340-10-05-4", "ASC 210-10-45-1(g)", "DECISION: plan/served.md D-11, D-37 (owner, 2026-10-20)"]
tags = ["schedules", "prepaid-expense", "daily", "p3-defect-9"]
[setup]
currency = "USD"
fiscal_year_start = "01-01"
basis = "accrual"
rounding = "half-away-from-zero"
[[setup.accounts]]
code = "1000"
name = "Bank"
type = "asset"
[[setup.accounts]]
code = "1300"
name = "Prepaid Expenses"
type = "asset"
[[setup.accounts]]
code = "3000"
name = "Capital"
type = "equity"
[[setup.accounts]]
code = "6300"
name = "Insurance"
type = "expense"
# 1,200.00 of insurance covering 2026-03-15 through 2027-03-14.
[[setup.schedules]]
id = "INS"
kind = "prepaid_expense"
description = "Liability insurance"
total = "1200.00"
start = "2026-03-15"
months = 12
convention = "daily"
balance_account = "1300"
pl_account = "6300"
[[events]]
date = "2026-03-15"
description = "Capital"
lines = [
{ account = "1000", side = "debit", amount = "1200.00" },
{ account = "3000", side = "credit", amount = "1200.00" },
]
[[events]]
date = "2026-03-15"
description = "Paid a year of insurance"
lines = [
{ account = "1300", side = "debit", amount = "1200.00" },
{ account = "1000", side = "credit", amount = "1200.00" },
]
[[events]]
run_schedules = { through = "2027-03-31" }
# Hand check (worked without the code): 1,200.00 / 12 = 100.00 a month.
# March 2026 holds 17 of its 31 days (15-31): 100.00 x 17/31 = 54.838...
# -> 54.84. April 2026 through February 2027 are whole: 100.00 each, 11 of
# them (cumulatives 154.84 ... 1,154.84). March 2027 holds days 1-14 and
# takes what is left: 1,200.00 - 1,154.84 = 45.16 (= 100.00 x 14/31 to the
# cent). Thirteen month ends for a twelve-month policy.
[[expect]]
query = "schedule_plan"
schedule = "INS"
[expect.values]
"2026-03-31" = "54.84"
"2026-04-30" = "100.00"
"2026-05-31" = "100.00"
"2026-06-30" = "100.00"
"2026-07-31" = "100.00"
"2026-08-31" = "100.00"
"2026-09-30" = "100.00"
"2026-10-31" = "100.00"
"2026-11-30" = "100.00"
"2026-12-31" = "100.00"
"2027-01-31" = "100.00"
"2027-02-28" = "100.00"
"2027-03-31" = "45.16"
# Through June 2026 the books have expensed 54.84 + 3 x 100.00 = 354.84,
# and 845.16 is still prepaid.
[[expect]]
query = "balances"
as_of = "2026-06-30"
[expect.values]
"1300" = "845.16"
"6300" = "354.84"
# Through March 2027, all of it.
[[expect]]
query = "balances"
as_of = "2027-03-31"
[expect.values]
"1300" = "0.00"
"6300" = "1200.00"
@@ -0,0 +1,63 @@
id = "schedule-equal-months-start-on-the-first"
title = "An equal-months schedule starts on the 1st of a month"
rule = "A schedule that spreads its total in equal months must start on the 1st of a month, for prepaid expenses and deferred revenue alike, so it never recognizes days it does not cover."
status = "CHOICE"
sources = ["ASC 606-10-25-23", "DECISION: plan/served.md D-37 (owner, 2026-10-20)"]
tags = ["schedules", "monthly-even", "refusal", "p3-defect-9"]
[setup]
currency = "USD"
fiscal_year_start = "01-01"
basis = "accrual"
# Equal months keep the rounding schedules had before P3 (each month the
# total over the months to the cent, ties to even; the last month takes
# what the others leave): a posted month's replay re-derives its plan.
rounding = "half-even"
[[setup.accounts]]
code = "1300"
name = "Prepaid Expenses"
type = "asset"
[[setup.accounts]]
code = "2400"
name = "Deferred Revenue"
type = "liability"
[[setup.accounts]]
code = "4000"
name = "Subscription Revenue"
type = "revenue"
[[setup.accounts]]
code = "6300"
name = "Insurance"
type = "expense"
# Equal months from March 15: refused (it would recognize all of March's
# 100.00, 45.16 of it, March 1 to 14 at 100.00 × 14/31, before the service
# began). The refusal names the 1st.
[[events]]
register_schedule = { id = "MID", kind = "deferred_revenue", description = "Annual plan", total = "1200.00", start = "2026-03-15", months = 12, convention = "monthly_even", balance_account = "2400", pl_account = "4000" }
refused = "invalid_schedule"
# The same for a prepaid expense: one rule for both.
[[events]]
register_schedule = { id = "MIDP", kind = "prepaid_expense", description = "Insurance", total = "1200.00", start = "2026-03-15", months = 12, convention = "monthly_even", balance_account = "1300", pl_account = "6300" }
refused = "invalid_schedule"
# From the 1st it is taken: twelve equal months.
[[events]]
register_schedule = { id = "FIRST", kind = "deferred_revenue", description = "Annual plan", total = "1200.00", start = "2026-03-01", months = 12, convention = "monthly_even", balance_account = "2400", pl_account = "4000" }
# Hand check (worked without the code): 1,200.00 / 12 = 100.00, every
# month, the last absorbing no rounding.
[[expect]]
query = "schedule_plan"
schedule = "FIRST"
[expect.values]
"2026-03-31" = "100.00"
"2026-09-30" = "100.00"
"2027-02-28" = "100.00"
total = "1200.00"