P3: rename accounts, one set of period defaults, tax categories warn or refuse (defects 15, 16, 8)
check / check (push) Canceled after 0s

books.rename_account; account names trimmed, bounded, refused when a
sibling's or TIN-shaped; books.show refuses what its target ignores. A
report asked for without dates covers this fiscal year so far, everywhere
(one rule for tools, descriptions and the viewer; the IIF and CPA package
keep their own dates). policy.require_tax_category warns or refuses; a
Form 4797 gain is shown apart on every return.

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 10:41:24 -06:00
1 parent 8255ac2103
commit 9ab003d0d1
69 files changed
+8063 -570

No files matched your search

+25 -2
View File
@@ -43,7 +43,8 @@ pub const CONNECT_LEAD: usize = 512;
/// The handbook's sections, in reading order: (id, markdown). Each starts
/// with a `# Title` line; `{evidence_rule}` stands for the receipt rule in
/// force.
/// force, and `{period_rule}` for what omitted report dates mean
/// ([`period_rule`]).
pub const SECTIONS: &[(&str, &str)] = &[
("contract", include_str!("../handbook/contract.md")),
("entries", include_str!("../handbook/entries.md")),
@@ -116,7 +117,10 @@ pub const ALL: &str = "all";
/// The section `id` (or [`ALL`]), rendered for these settings and the
/// books' base currency (None: no such section).
pub fn section(id: &str, settings: &Settings, currency: &str) -> Option<String> {
let render = |md: &str| md.replace("{evidence_rule}", &evidence_rule(settings, currency));
let render = |md: &str| {
md.replace("{evidence_rule}", &evidence_rule(settings, currency))
.replace("{period_rule}", &period_rule())
};
if id == ALL {
let parts: Vec<String> = SECTIONS.iter().map(|(_, md)| render(md)).collect();
return Some(parts.join("\n"));
@@ -127,6 +131,17 @@ pub fn section(id: &str, settings: &Settings, currency: &str) -> Option<String>
.map(|(_, md)| render(md))
}
/// What omitted report dates mean (rules.md B-30), in the words every
/// report tool's description uses (`ledger_core::calendar::PeriodKind`).
pub fn period_rule() -> String {
use ledger_core::calendar::PeriodKind;
format!(
"{} For a report as of a day (balance sheet, trial balance, aging): {}",
PeriodKind::Statement.describe(),
PeriodKind::AsOf.describe()
)
}
/// The receipt rule in force (INVARIANT 2).
pub fn evidence_rule(settings: &Settings, currency: &str) -> String {
format!(
@@ -460,7 +475,14 @@ mod tests {
assert!(!title(md).is_empty());
let text = section(id, &s, "USD").unwrap();
assert!(!text.contains("{evidence_rule}"), "{id}");
assert!(!text.contains("{period_rule}"), "{id}");
}
// The default period, in the descriptions' own words (B-30).
assert!(
section("tracing-figures", &s, "USD")
.unwrap()
.contains(ledger_core::calendar::PeriodKind::Statement.describe())
);
assert!(
section("evidence-and-receipts", &s, "USD")
.unwrap()
@@ -497,6 +519,7 @@ mod tests {
at += found + one.len();
}
assert!(!all.contains("{evidence_rule}"));
assert!(!all.contains("{period_rule}"));
assert!(SECTIONS.iter().all(|(id, _)| *id != ALL));
}