Fixed assets carry federal tax basis beside book value; tests sweep stale temp dirs

- 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:
swaitsandClaude Opus 5.5 committed 2026-10-15 13:30:09 -06:00
1 parent 6adc7b34c7
commit ba7373bdb8
30 files changed
+3240 -93

No files matched your search

+30 -1
View File
@@ -1556,6 +1556,15 @@ pub struct AssetRegisterRow {
pub book_value: Decimal,
/// Disposal date and proceeds, if disposed by the date.
pub disposed: Option<(NaiveDate, Decimal)>,
/// The federal tax basis rule, if recorded.
pub tax_rule: Option<crate::TaxBasisRule>,
/// The contributing member's adjusted basis (a contribution only).
pub contributor_basis: Option<Decimal>,
/// The depreciable federal tax basis (`Asset::tax_basis`), if recorded.
pub tax_basis: Option<Decimal>,
/// Built-in gain (+) or loss (−) at contribution, IRC §704(c)
/// (`Asset::built_in_gain`).
pub built_in_gain: Option<Decimal>,
}
/// The fixed asset register as of a date, reconciled to the general ledger.
@@ -1572,6 +1581,11 @@ pub struct AssetRegister {
pub total_accumulated: Decimal,
/// Their book value.
pub total_book_value: Decimal,
/// The total depreciable tax basis of the assets still held that have
/// one recorded.
pub total_tax_basis: Decimal,
/// How many assets still held have no tax basis recorded.
pub missing_tax_basis: usize,
/// The general ledger's balance (debit positive) of the assets' cost
/// accounts on the date.
pub ledger_cost: Decimal,
@@ -1611,7 +1625,11 @@ impl AssetRegister {
/// 2. accumulated is the asset's schedule through as_of
/// (assets::accumulated_depreciation); book_value = cost −
/// accumulated.
/// 3. Totals are the sums over the held assets, exactly.
/// 3. Totals are the sums over the held assets, exactly; tax basis
/// totals over those with one recorded, and missing_tax_basis counts
/// the rest.
/// 5. Each row's tax fields are the asset's (Asset::tax_basis,
/// Asset::built_in_gain), never re-derived here.
/// 4. ledger_cost and ledger_accumulated are the general ledger's
/// balances on as_of of the distinct cost and accumulated
/// depreciation accounts of the registered assets, so
@@ -1622,6 +1640,7 @@ pub fn fixed_asset_register(ledger: &Ledger, as_of: NaiveDate) -> AssetRegister
use crate::AssetStatus;
let mut rows = Vec::new();
let (mut cost, mut accumulated) = (Decimal::ZERO, Decimal::ZERO);
let (mut tax_total, mut tax_missing) = (Decimal::ZERO, 0usize);
let mut cost_accounts = std::collections::BTreeSet::new();
let mut accum_accounts = std::collections::BTreeSet::new();
for a in ledger
@@ -1644,6 +1663,10 @@ pub fn fixed_asset_register(ledger: &Ledger, as_of: NaiveDate) -> AssetRegister
if disposed.is_none() {
cost += a.cost.amount;
accumulated += acc;
match a.tax_basis() {
Some(t) => tax_total += t,
None => tax_missing += 1,
}
}
rows.push(AssetRegisterRow {
asset_id: a.id,
@@ -1661,6 +1684,10 @@ pub fn fixed_asset_register(ledger: &Ledger, as_of: NaiveDate) -> AssetRegister
a.cost.amount - acc
},
disposed,
tax_rule: a.tax.map(|t| t.rule),
contributor_basis: a.tax.and_then(|t| t.contributor_basis),
tax_basis: a.tax_basis(),
built_in_gain: a.built_in_gain(),
});
}
let tb = trial_balance_as_of(ledger, as_of);
@@ -1681,6 +1708,8 @@ pub fn fixed_asset_register(ledger: &Ledger, as_of: NaiveDate) -> AssetRegister
total_cost: cost,
total_accumulated: accumulated,
total_book_value: cost - accumulated,
total_tax_basis: tax_total,
missing_tax_basis: tax_missing,
ledger_cost: cost_accounts.iter().map(|&id| net(id)).sum(),
ledger_accumulated: -accum_accounts.iter().map(|&id| net(id)).sum::<Decimal>(),
}