Fixed assets carry federal tax basis beside book value; tests sweep stale temp dirs
check / check (push) Canceled after 0s
check / check (push) Canceled after 0s
- core: TaxBasisRule (cost IRC 1012, carryover IRC 723, personal-use conversion Treas. Reg. 1.168(i)-4(b)), TaxBasis with the contributor's adjusted basis, Asset::tax_basis and ::built_in_gain (IRC 704(c)); the register gains tax rule, contributor basis, tax basis, built-in gain, total tax basis, missing count (rules.md B-25; sources vendored in docs/spec/sources/irs-partnership-basis.md) - store: asset.tax_basis_set journaled, replayed, projected (schema v10) - mcp: books.set_asset_tax_basis; register_asset takes tax_basis_rule and contributor_basis, checked before anything registers (found by the spec-blind suite); list_assets and the register export (json, csv) carry tax basis; instructions say to record it for every asset - import: the register's XLSX and PDF gain the federal tax basis table with citations - viewer: tax basis on the Assets page, the asset page (a Tax basis card), the report, the journal, and Needs attention for assets without one - just: check and the mutation recipes sweep this user's test book dirs older than an hour (killed runs had left 23 GB in RAM-backed /tmp) - docs: the parties, attachments, TIN vault, completeness engine, and updates designs (docs/parties-and-attachments.md) - tests: spec-blind tax basis suites in core, store, MCP; register PDF/XLSX and viewer tests Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GWVo7x3UHw5kwCUaWxiejX
This commit is contained in:
1 parent
49c49aef33
commit
6e6f9d65b2
30 files changed
+3240
-93
No files matched your search
@@ -0,0 +1,229 @@
|
||||
# Parties and attachments
|
||||
|
||||
Design for two features built together (Stephen, 2026-10-15): a directory
|
||||
of the parties the company deals with, and attachments that link to any
|
||||
subject. Status: design; built after asset tax basis.
|
||||
|
||||
## Why together
|
||||
|
||||
Both answer "what is this connected to?" A W-9 note, a contract, a bank
|
||||
statement, a photo of a laptop: each is a file about a party, an account, a
|
||||
reconciliation, an asset, a period. One subject model serves both.
|
||||
|
||||
## Parties
|
||||
|
||||
A party is anyone the company deals with. Today's vendors and customers
|
||||
become parties; employees stop being name strings on payroll lines; the
|
||||
Apple, Google, Anthropic, IRS, and Utah that live only in entry
|
||||
descriptions get records.
|
||||
|
||||
### Model (ledger-core, `parties.rs`)
|
||||
|
||||
```text
|
||||
Party {
|
||||
id: PartyId, // vendors and customers keep their ids (see Migration)
|
||||
name: String, // legal or trade name, as on documents
|
||||
display_name: Option<String>,
|
||||
roles: BTreeSet<Role>, // vendor, contractor, customer, employee, member,
|
||||
// payout_platform, tax_agency, financial_institution, landlord
|
||||
website: Option<String>,
|
||||
address: Option<String>, // business address; no personal PII beyond it
|
||||
w9: Option<W9Facts>, // contractor/landlord: the TIN itself is in the vault
|
||||
w4: Option<W4Facts>, // employee: never the SSN
|
||||
form_1099: Option<Form1099>, // carried over from Vendor
|
||||
member: Option<String>, // a member's name in wanderbooks.toml, when role member
|
||||
notes: Option<String>,
|
||||
archived: bool, // no longer dealt with; history stays
|
||||
}
|
||||
W9Facts { received: NaiveDate, entity_type: String, exempt_payee_code: Option<String>,
|
||||
fatca_code: Option<String>, tin_last4: String, kept_at: String }
|
||||
W4Facts { received: NaiveDate, state: String, kept_at: String }
|
||||
```
|
||||
|
||||
Rules (to vendor as B-26 with sources):
|
||||
|
||||
- A full TIN or SSN is never in the journal: `tin_last4` is exactly four
|
||||
digits, and any nine-digit run in any party field is refused (the engine
|
||||
checks, not the agent). Full TINs live only in the vault (below).
|
||||
Source: IRS truncated-TIN rules (Treas. Reg. §301.6109-4, to vendor) for
|
||||
what may appear; DECISION (Stephen, 2026-10-15) for the vault.
|
||||
- Roles are a set; each role's facts are only allowed with the role
|
||||
(W-9 facts need contractor or landlord; W-4 facts need employee).
|
||||
- Names are unique ignoring case and surrounding space among
|
||||
non-archived parties.
|
||||
- A 1099 needs a contractor or landlord role; 1099 totals come from the
|
||||
entries tagged with the party, as today's vendor 1099 report does.
|
||||
|
||||
### Links
|
||||
|
||||
- Entries: `entry.party_set {entry_id, party_id|null}` generalizes
|
||||
`entry.vendor_set`; an entry has one counterparty.
|
||||
- Invoices and bills already name a customer or vendor id: those are
|
||||
party ids after migration.
|
||||
- Payroll lines name an employee party id (old runs keep their name
|
||||
strings; new runs must name a party with the employee role).
|
||||
|
||||
### Journal events
|
||||
|
||||
`party.added {id, name, roles}`, `party.updated {id, field, value}` (one
|
||||
field per event: name, display_name, website, address, notes, archived),
|
||||
`party.role_added {id, role}`, `party.role_removed {id, role}`,
|
||||
`party.w9_set {id, facts|null}`, `party.w4_set {id, facts|null}`,
|
||||
`entry.party_set`. Replayed and projected like the rest; every event gets
|
||||
viewer journal text (the GUI test enforces it).
|
||||
|
||||
### Migration
|
||||
|
||||
Old journals replay unchanged. `vendor.added` and `customer.added` keep
|
||||
their meaning and create parties with the vendor or customer role; the
|
||||
party id space starts above the highest vendor and customer ids, and a
|
||||
vendor and a customer with the same name stay two parties until the
|
||||
human merges them (`books.merge_parties`, journaled, re-pointing links).
|
||||
`entry.vendor_set` replays as `entry.party_set`. `vendor.1099_set` sets
|
||||
the party's `form_1099` and the contractor role.
|
||||
|
||||
### Tools
|
||||
|
||||
`books.add_party`, `books.update_party`, `books.party_roles`,
|
||||
`books.set_w9`, `books.set_w4`, `books.parties` (list, filter by role),
|
||||
`books.party` (one: facts, roles, totals this year, documents, links),
|
||||
`books.merge_parties`, `books.set_entry_party`. `books.add_vendor` and
|
||||
`books.add_customer` stay as shortcuts.
|
||||
|
||||
### Viewer
|
||||
|
||||
A Parties page (by role, searchable) and a page per party: facts, roles,
|
||||
year-to-date paid / owed / invoiced / 1099 amount, every entry, invoice,
|
||||
bill, payroll run, documents, and history. Members link to their capital
|
||||
accounts. Global search finds parties. Needs-attention: a contractor
|
||||
paid without W-9 facts; a 1099 party paid over the threshold.
|
||||
|
||||
## The TIN vault
|
||||
|
||||
Decision (Stephen, 2026-10-15): wanderbooks holds full TINs, so the 1099
|
||||
worksheet it hands the CPA is complete, but never in the journal.
|
||||
|
||||
- **Where:** `vault/` in the books dir, listed in `.gitignore`. Never in
|
||||
the hash-chained journal, the SQLite projection, git, an export other
|
||||
than the 1099 worksheet, or the viewer. Nothing outside the vault holds
|
||||
more than the last four digits.
|
||||
- **What:** per party, the full TIN, its type (SSN, EIN, ITIN), and the
|
||||
W-9 file itself, each encrypted at rest (XChaCha20-Poly1305, one random
|
||||
nonce per record; the file format carries a version and the party id as
|
||||
associated data, so a record can't be moved to another party).
|
||||
- **Key:** a random 256-bit key in the OS keyring (Secret Service on Linux,
|
||||
Keychain on macOS), created on first use; never on disk in the books dir.
|
||||
A recovery copy is the human's job: `just vault-export` writes the key
|
||||
and records as one passphrase-encrypted file for a password manager.
|
||||
- **Journal:** `party.w9_set` records that a W-9 was received, its date,
|
||||
entity type, codes, and last four, plus a hash of the vault record, so
|
||||
the books prove a W-9 existed without holding it.
|
||||
- **Purge:** `books.purge_tin {party, reason}` deletes the vault record
|
||||
(after the retention period, or on request) and journals that it was
|
||||
purged; the journal's facts stay.
|
||||
- **Use:** only `books.vendor_1099` with `include_tins: true` (and the CPA
|
||||
package, when asked) decrypts them. The MCP server never returns a TIN
|
||||
in any other tool, log, or error. Tests check that no other output
|
||||
contains a nine-digit run.
|
||||
- **Books without a vault** (another machine, a restored backup) still
|
||||
open and verify; the 1099 worksheet then says which TINs are missing.
|
||||
|
||||
## Attachments
|
||||
|
||||
### Subjects
|
||||
|
||||
An attachment links to any number of subjects:
|
||||
|
||||
```text
|
||||
Subject = Entry(id) | Account(id) | Reconciliation(id) | Asset(id) | Party(id)
|
||||
| Invoice(id) | Bill(id) | Period(id) | PayrollRun(id) | Schedule(id)
|
||||
| Company
|
||||
```
|
||||
|
||||
`attachment.linked {attachment_id, subject}` and `attachment.unlinked
|
||||
{attachment_id, subject, reason}` replace the single `entry_id` link (old
|
||||
`receipt.attached` with an entry and `receipt.linked` replay as links to
|
||||
that entry). A receipt is an attachment linked to an entry; the receipt
|
||||
policy counts links to the entry, as now. A file stored once can be
|
||||
linked to many subjects (no more refiling).
|
||||
|
||||
### Kinds
|
||||
|
||||
`receipt`, `statement`, `contract`, `formation`, `legal`, `tax`,
|
||||
`accounting`, `photo`, `warranty`, `import_source`, `other`. A statement
|
||||
carries `{account_id, period_start, period_end, opening_balance,
|
||||
closing_balance}`, checked against the account's currency.
|
||||
|
||||
### Reconciliations
|
||||
|
||||
`books.reconcile` with `confirmed: true` records a reconciliation:
|
||||
`reconciliation.completed {id, account_id, statement_date,
|
||||
statement_balance, cleared: [(entry_id, line)], attachment_id}`. It
|
||||
refuses unless the difference is exactly zero and a statement for that
|
||||
account and date is attached (the receipt rule's twin). A reconciliation
|
||||
is never edited; a later one supersedes it; `reconciliation.voided
|
||||
{id, reason}` exists for mistakes. Viewer: per-account reconciliation
|
||||
history with its statement; Needs-attention: an account with activity not
|
||||
reconciled through last month's end.
|
||||
|
||||
### Import sources
|
||||
|
||||
`books.import_bank_csv` files the CSV (kind `import_source`), links it to
|
||||
every entry it created, and records the row each came from, so every
|
||||
imported line traces to its source row.
|
||||
|
||||
### Projection
|
||||
|
||||
SQLite: `attachment_links(attachment_id, subject_kind, subject_id)`,
|
||||
`statements(attachment_id, account_id, period_start, period_end, opening,
|
||||
closing)`, `reconciliations(...)`, `reconciliation_lines(...)`; the old
|
||||
`attachments.entry_id` column is kept and filled for entry links during
|
||||
the migration so older readers still work.
|
||||
|
||||
## Testing
|
||||
|
||||
Spec blocks on every command; spec-blind suites per crate; the
|
||||
refusal-leaves-books-unchanged property; replay and migration from v10
|
||||
books; the GUI's every-event-has-text test; mutation on the new modules.
|
||||
|
||||
## After this: the completeness engine
|
||||
|
||||
Decided (Stephen, 2026-10-15), built after parties and attachments: one
|
||||
set of completeness rules in the core (asset: tag, serial, tax basis,
|
||||
acquisition link, label; entry: receipt, 1099 vendor tag; account:
|
||||
reconciled through last month; month: depreciation, amortization, close;
|
||||
party: W-9 before paying a contractor; settings: no problems; and the
|
||||
rules this design adds), `next_steps` on every tool response naming the
|
||||
exact call that completes each, `books.todo` as the one punch list behind
|
||||
the digest, the viewer's Needs attention, and the session-start hook, and
|
||||
enforcement where a rule is a rule (tax basis at registration). The
|
||||
standard: do it now, completely.
|
||||
|
||||
## After that: updates (check and seamless upgrade)
|
||||
|
||||
Decided (Stephen, 2026-10-15), after the completeness engine. New versions
|
||||
fix accounting, tax, and legal rules, so books running an old version may
|
||||
be wrong; staying current is part of keeping correct books.
|
||||
|
||||
- **Check:** the MCP server checks for a newer release when it starts and
|
||||
once a day while running (and the viewer and `just session-start` ask
|
||||
it). Releases carry notes and a severity: a fix to an accounting, tax, or
|
||||
legal rule (a 1099 threshold, a depreciation rule, a refusal that was
|
||||
wrong) is marked so, and says which books it may affect. `[updates]
|
||||
check = "daily" | "never"` in wanderbooks.toml; the check contacts only
|
||||
the release host and sends nothing about the books.
|
||||
- **Surface:** the update is a completeness item (`books.todo`), in
|
||||
`books.digest`, a banner in the viewer, and the session-start hook; the
|
||||
MCP instructions tell the agent to raise it with the human at once, with
|
||||
the release notes, and to treat a rules fix as urgent.
|
||||
- **Upgrade:** one step (`wanderbooks update`, or the agent offers it):
|
||||
download the release, verify its signature against a key pinned in the
|
||||
installed build, then rehearse: open the books read-only with the new
|
||||
build and run the full verify (replay, projection, migrations) before
|
||||
switching. Swap binaries atomically, keep the previous build for
|
||||
rollback, restart the viewer, and have the MCP server exit cleanly so the
|
||||
client reconnects to the new one. Never downgrade; never touch the
|
||||
journal except through the new build's ordinary migrations.
|
||||
- **After:** the agent re-runs whatever the fix affects (for example,
|
||||
`books.vendor_1099` for the year, or the register) and tells the human
|
||||
what changed in their books, if anything.
|
||||
+1
-1
@@ -13,7 +13,7 @@ layers differ in what they cover and in whether we may copy them:
|
||||
| Layer | What it governs | Copyright | Here |
|
||||
|---|---|---|---|
|
||||
| **Pacioli (1494), Geijsbeek translation (1914)** | The mechanics of double entry: debits equal credits, the trial balance, one money, writing only forward, correcting by opposite entry, closing into capital. No modern standard restates these; they predate every regulator. | Public domain | Vendored verbatim: `sources/pacioli-1494.md` |
|
||||
| **IRS: Internal Revenue Code, Treasury Regulations, publications, form instructions** | Records and supporting documents, retention, accounting periods and methods, information returns (1099), capitalization (de minimis, 12-month rule), partners' capital, payroll taxes, rounding on returns, return line items for tax categories (`sources/irs-tax-lines.md`) | Public domain (17 U.S.C. §105; IRS.gov's content policy) | Vendored verbatim: `sources/irs-*.md`, `sources/us-public-domain-status.md` |
|
||||
| **IRS: Internal Revenue Code, Treasury Regulations, publications, form instructions** | Records and supporting documents, retention, accounting periods and methods, information returns (1099), capitalization (de minimis, 12-month rule), partners' capital, tax basis of purchased and contributed property (`sources/irs-partnership-basis.md`), payroll taxes, rounding on returns, return line items for tax categories (`sources/irs-tax-lines.md`) | Public domain (17 U.S.C. §105; IRS.gov's content policy) | Vendored verbatim: `sources/irs-*.md`, `sources/us-public-domain-status.md` |
|
||||
| **File formats: Intuit (QuickBooks Online bank CSV, QuickBooks Desktop IIF), ECMA-376 Office Open XML, Microsoft Excel limits, Avery label sheets** | What `ledger-import` reads and writes: bank/card CSV layouts and signs, IIF journal entries, how XLSX stores numbers and Excel's 15-digit precision, asset-label sheet geometry (Avery 5160) | © Intuit Inc.; © Ecma International; © Microsoft; © Avery Products Corporation | Cited with short quotes, URLs, and hashes: `sources/intuit-bank-csv.md`, `sources/intuit-iif.md`, `sources/xlsx-numbers.md`, `sources/avery-5160.md` |
|
||||
| **FASB Accounting Standards Codification (ASC)** | Authoritative US GAAP: cash flows (ASC 230), revenue and principal vs agent (ASC 606), foreign currency (ASC 830), credit losses and aging (ASC 326), property and depreciation (ASC 360) | © Financial Accounting Foundation | Cited by paragraph with short quotes only (in `rules.md`) |
|
||||
| **FASB Concepts Statement No. 8, Chapter 4 (2021)** | Definitions of the five elements (it replaced Concepts Statement 6) | © Financial Accounting Foundation; non-authoritative | Cited with short quotes only |
|
||||
|
||||
@@ -464,3 +464,33 @@ accounts.
|
||||
`assets::check_asset_tag`, `assets::check_serial`. **Checked:**
|
||||
`ledger-core` `tests/spec_asset_tags.rs`; `ledger-store`
|
||||
`tests/asset_tags.rs`; `ledger-mcp` `tests/spec_assets.rs`.
|
||||
|
||||
## B-25 Tax basis beside book value
|
||||
|
||||
**Status:** AUTHORITY (`sources/irs-partnership-basis.md`); DECISION
|
||||
(Stephen, 2026-10-15: the register carries tax basis)
|
||||
|
||||
Book value and tax basis are different numbers for the same asset. The
|
||||
book value of a member's contribution is its fair market value (Treas.
|
||||
Reg. §1.704-1(b)(2)(iv)(d)(1), cited). Its federal tax basis follows the
|
||||
rule that applies: property the company buys has a cost basis ("The basis
|
||||
of property shall be the cost of such property", IRC §1012(a)); property a
|
||||
member contributes keeps "the adjusted basis of such property to the
|
||||
contributing partner at the time of the contribution" (IRC §723,
|
||||
carryover); property a member converts from personal use depreciates from
|
||||
"the lesser of its fair market value or its adjusted depreciable basis"
|
||||
(Treas. Reg. §1.168(i)-4(b)(1)). The difference between fair market value
|
||||
and the contributor's adjusted basis is the built-in gain (positive) or
|
||||
loss (negative) that IRC §704(c) makes the partnership account for; a
|
||||
built-in loss counts only for the contributing member (§704(c)(1)(C)).
|
||||
wanderbooks records the rule, the contributor's adjusted basis, the
|
||||
resulting tax basis, and the built-in gain or loss; tax depreciation
|
||||
(MACRS, conventions, elections) stays with the CPA (`sources/irs-depreciation.md`).
|
||||
|
||||
**Enforced:** `Ledger::set_asset_tax_basis` / `check_asset_tax_basis`
|
||||
(cost takes no contributor basis, a contribution requires one,
|
||||
non-negative, in cents), `Asset::tax_basis`, `Asset::built_in_gain`,
|
||||
`reports::fixed_asset_register` (per-row tax fields, `total_tax_basis`,
|
||||
`missing_tax_basis`). **Checked:** `ledger-core` `tests/spec_tax_basis.rs`;
|
||||
`ledger-store` `tests/asset_tags.rs` (`asset.tax_basis_set` journaling,
|
||||
replay, v9 migration, corrupt payloads); `ledger-mcp` `tests/spec_assets.rs`.
|
||||
@@ -0,0 +1,40 @@
|
||||
# Tax basis of fixed assets: cost, contributed property, and personal-use conversion
|
||||
Governs the tax basis the fixed asset register carries beside book value (rules.md B-25). Property the partnership buys has a cost basis (IRC §1012); property a member contributes keeps the member's adjusted basis (IRC §723), and the difference from its fair market value is the built-in gain or loss that §704(c) makes the partnership account for; property a member converts from personal use has a depreciable basis of the lesser of fair market value and adjusted basis (Treas. Reg. §1.168(i)-4(b)(1)). wanderbooks records the basis; tax depreciation (MACRS, conventions, elections) stays with the CPA.
|
||||
|
||||
## 26 U.S.C. §1012(a): basis is cost
|
||||
Source: <https://www.law.cornell.edu/uscode/text/26/1012>
|
||||
Retrieved: 2026-10-15
|
||||
SHA-256 of the retrieved file (`usc1012.html`): `831c9a6a91fceb2f78968520b6f7811b0975bdc170538fa333baa072b799990b`
|
||||
|
||||
> The basis of property shall be the cost of such property, except as otherwise provided in this subchapter and subchapters C (relating to corporate distributions and adjustments), K (relating to partners and partnerships), and P (relating to capital gains and losses).
|
||||
|
||||
## 26 U.S.C. §723: basis of property contributed to a partnership
|
||||
Source: <https://www.law.cornell.edu/uscode/text/26/723>
|
||||
Retrieved: 2026-10-15
|
||||
SHA-256 of the retrieved file (`usc723.html`): `bfc8c78b5ef5e230f8df1c76d8ab3020ea4a515d987576bba37e740bb5c8c4c7`
|
||||
|
||||
> The basis of property contributed to a partnership by a partner shall be the adjusted basis of such property to the contributing partner at the time of the contribution increased by the amount (if any) of gain recognized under section 721(b) to the contributing partner at such time.
|
||||
|
||||
## 26 U.S.C. §704(c)(1): built-in gain and loss on contributed property
|
||||
Source: <https://www.law.cornell.edu/uscode/text/26/704>
|
||||
Retrieved: 2026-10-15
|
||||
SHA-256 of the retrieved file (`usc704.html`): `03a2c2fd087cc5e849f3755417e34bf8d869afc67e4650f5473a4e73b7cec099`
|
||||
|
||||
**§704(c)(1)(A): the variation between basis and fair market value**
|
||||
|
||||
> income, gain, loss, and deduction with respect to property contributed to the partnership by a partner shall be shared among the partners so as to take account of the variation between the basis of the property to the partnership and its fair market value at the time of contribution,
|
||||
|
||||
**§704(c)(1)(C)**
|
||||
|
||||
> if any property so contributed has a built-in loss — (i) such built-in loss shall be taken into account only in determining the amount of items allocated to the contributing partner, and (ii) except as provided in regulations, in determining the amount of items allocated to other partners, the basis of the contributed property in the hands of the partnership shall be treated as being equal to its fair market value at the time of contribution.
|
||||
|
||||
**Built-in loss, defined**
|
||||
|
||||
> For purposes of subparagraph (C), the term “built-in loss” means the excess of the adjusted basis of the property (determined without regard to subparagraph (C)(ii)) over its fair market value at the time of contribution.
|
||||
|
||||
## Treas. Reg. §1.168(i)-4(b)(1): conversion from personal to business use
|
||||
Source: <https://www.ecfr.gov/api/renderer/v1/content/enhanced/current/title-26?part=1§ion=1.168(i)-4>
|
||||
Retrieved: 2026-10-15
|
||||
SHA-256 of the retrieved file (`ecfr168i4.html`): `284efb83eeb11442ab86e050f6d630bd468fd75463e27e3ec81dbc8de455e9be`
|
||||
|
||||
> Depreciation deduction allowable. This paragraph (b) applies to property that is converted from personal use to use in a taxpayer's trade or business, or for the production of income, during a taxable year. This conversion includes property that was previously used by the taxpayer for personal purposes, including real property (other than land) that is acquired before 1987 and converted from personal use to business or income-producing use after 1986, and depreciable property that was previously used by a tax-exempt entity before the entity changed to a taxable entity. Except as otherwise provided by the Internal Revenue Code or regulations under the Internal Revenue Code, upon a conversion to business or income-producing use, the depreciation allowance for the year of change and any subsequent taxable year is determined as though the property is placed in service by the taxpayer on the date on which the conversion occurs. Thus, except as otherwise provided by the Internal Revenue Code or regulations under the Internal Revenue Code, the taxpayer must use any applicable depreciation method, recovery period, and convention prescribed under section 168 for the property in the year of change, consistent with any election made under section 168 by the taxpayer for that year (see, for example, section 168(b)(5)). See §§ 1.168(k)-1(f)(6)(iii) or 1.168(k)-2(g)(6)(iii), as applicable, and 1.1400L(b)-1(f)(6) for the additional first year depreciation deduction rules applicable to a conversion to business or income-producing use. The depreciable basis of the property for the year of change is the lesser of its fair market value or its adjusted depreciable basis (as defined in § 1.168(b)-1T(a)(4)), as applicable, at the time of the conversion to business or income-producing use.
|
||||
Reference in new issue
Block a user