feat(audit): books.audit, the attestation tools and the CPA gate (P8)

The whole re-audit through the tools: books.audit previews its checks, then
with the preview's digest runs them, files the workpaper and journals the
run; the same books, day and scope return the run that exists.
books.attest_receipt, books.review_entry and books.attest_period record a
named client's claim with its self-reported method; books.attestations
weighs each against policy.attestation_bar as it stands. Under
policy.cpa_package_requires_audit = refuse, books that declared audits
cannot export the CPA package without a counted audit for the handoff at the
current head unless a reason is given, which is journaled as a decision
(D-9). Needs attention asks for the month-end attestation, the annual audit
and the audit before the handoff. Rules B-45, the handbook section, the
interface, parity, receipt-store and testing records, and the As-built
block. Merge needs no go-ahead: the live books refuse the new writes until
the owner gives it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HS8WZziDnyxunC23MUxrLp
This commit is contained in:
swaitsandClaude Fable 5.1 committed 2026-10-29 15:54:26 -06:00
1 parent d45e842873
commit 45bcce679b
23 files changed
+2128 -22

No files matched your search

+129 -1
View File
@@ -78,7 +78,12 @@
//! pages); a posted entry a member paid personally (a credit on a
//! "due to"/"owed to" liability) that no entry records settling
//! (Todo, one per entry; `entry.settles` only, no FIFO guess,
//! IZ-18).
//! IZ-18); for books that declared `audits` (plan P8): a closed
//! period no `period.attested` names (Todo, one per period, "Month-end
//! attestation due"), the last fiscal year that ended with entries,
//! closed, and no audit run of scope cpa_handoff or full through its
//! end ("Full audit due before the CPA handoff"), else with no run of
//! scope annual, cpa_handoff or full ("Annual audit due").
//! 3. Nothing else: books with none of those yield no items, except
//! that a figure behind an item that can't be computed (an
//! amortization plan past chrono's last day, an aging past exact
@@ -1375,10 +1380,133 @@ pub fn find_with(
});
}
}
out.extend(audit_items(books, &journal, today, settings));
out.sort_by_key(|a| a.severity);
out
}
/// The audit items (plan P8, R-F), for books that declared `audits` (the
/// others can't act on them): a closed month with no attestation, a closed
/// fiscal year with no audit for the handoff, and a finished year with no
/// annual audit. Read from the journal's `audit.run` and `period.attested`
/// lines, so the viewer and `books.start` read the same facts.
fn audit_items(
books: &impl PackageBooks,
journal: &[JournalLine],
today: NaiveDate,
settings: &Settings,
) -> Vec<Attention> {
let declared = journal
.iter()
.rev()
.find(|l| l.line_type == "journal.format_set")
.is_some_and(|l| {
l.payload["features"]
.as_array()
.is_some_and(|f| f.iter().any(|x| x == "audits"))
});
if !declared {
return Vec::new();
}
let ledger = books.ledger();
let attested: HashSet<u64> = journal
.iter()
.filter(|l| l.line_type == "period.attested")
.filter_map(|l| l.payload["period_id"].as_u64())
.collect();
// (scope, through) of every run.
let runs: Vec<(String, NaiveDate)> = journal
.iter()
.filter(|l| l.line_type == "audit.run")
.filter_map(|l| {
let through =
NaiveDate::parse_from_str(l.payload["through"].as_str()?, "%Y-%m-%d").ok()?;
Some((l.payload["scope"].as_str()?.to_string(), through))
})
.collect();
let mut out = Vec::new();
for p in ledger.list_periods() {
if p.status != PeriodStatus::Closed || attested.contains(&p.id) {
continue;
}
out.push(Attention {
severity: Severity::Todo,
kind: "month_attestation_due",
title: format!("Month-end attestation due: {}", p.name),
detail: format!(
"{} ({} to {}) is closed and no one has attested it.",
p.name,
date(p.start),
date(p.end)
),
target: Target::Journal,
prompt: format!(
"In wanderbooks, {} is closed and has no attestation. Audit the books through {} (books.audit with scope month), then have separate verifier agents read each receipt (books.get_receipt, then attest_receipt), review the entries (books.review_entry) and attest the period (books.attest_period). Read the attestations-and-audit section of the handbook first.",
p.name,
p.end
),
tool: Some((
"books.audit".into(),
serde_json::json!({ "scope": "month", "through": p.end.to_string() }),
)),
});
}
// The last fiscal year that ended, if the books have entries in it.
let (this_start, _) = settings.company.fiscal_year_containing(today);
if let Some(before) = this_start.pred_opt() {
let (fy_start, fy_end) = settings.company.fiscal_year_containing(before);
let has_entries = ledger
.posted_entries()
.any(|e| e.date() >= fy_start && e.date() <= fy_end);
let closed = ledger
.list_periods()
.iter()
.any(|p| p.status == PeriodStatus::Closed && p.end >= fy_end);
let year_audit = |scopes: &[&str]| {
runs.iter()
.any(|(s, t)| scopes.contains(&s.as_str()) && *t >= fy_end)
};
if has_entries && closed && !year_audit(&["cpa_handoff", "full"]) {
out.push(Attention {
severity: Severity::Todo,
kind: "handoff_audit_due",
title: format!("Full audit due before the CPA handoff: {}", fy_end.year()),
detail: format!(
"The fiscal year ended {} and is closed; the CPA package waits for an audit for the handoff attested at the bar.",
date(fy_end)
),
target: Target::Journal,
prompt: format!(
"In wanderbooks, the fiscal year ending {fy_end} is closed and has no audit for the CPA handoff. Run books.audit with scope cpa_handoff through {fy_end}, have independent adversarial verifier agents attest the receipts and the entries, and attest the year (books.attest_period). Read the attestations-and-audit section of the handbook first."
),
tool: Some((
"books.audit".into(),
serde_json::json!({ "scope": "cpa_handoff", "through": fy_end.to_string() }),
)),
});
} else if has_entries && !year_audit(&["annual", "cpa_handoff", "full"]) {
out.push(Attention {
severity: Severity::Todo,
kind: "annual_audit_due",
title: format!("Annual audit due: {}", fy_end.year()),
detail: format!(
"The fiscal year ended {} and no audit covers it.",
date(fy_end)
),
target: Target::Journal,
prompt: format!(
"In wanderbooks, the fiscal year ending {fy_end} has no annual audit. Run books.audit with scope annual through {fy_end} and fix what it finds. Read the attestations-and-audit section of the handbook first."
),
tool: Some((
"books.audit".into(),
serde_json::json!({ "scope": "annual", "through": fy_end.to_string() }),
)),
});
}
}
out
}
/// One entry, indexed the way the items read it.
struct Entry {
id: EntryId,