feat(audit): audit runs and attestations are journaled (P8)
A claim that someone checked the books is evidence the CPA handoff rests on, so it is a journal fact and replays: audit.run (a programme run through a day at the books' figure head, with the hashes that make it reproducible and the two filed workpapers), receipt.attested, entry.reviewed and period.attested. Behind the journal feature audits, schema 20; no figure moves. The figure head is the last line that bears on a figure: filing a workpaper, a run or an attestation never makes an audit stale, an entry, document, close, settings or role change does, so a period is attested only on an audit that still describes the books. A receipt reading that differs from the entry is recorded as disagreeing and never counts; whether a claim counts is derived against the bar when asked, never stored. The store also reads what a ledger cannot: the chain, the database against a replay, stored and extracted files, the access log, duplicate files, and the backups' standing handed in by the server. Fixture old-books/p8_before was written by the version before this one and opens to its figures. period.attested was the tests' placeholder for an unknown event type; they use ledger.not_yet_written now. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HS8WZziDnyxunC23MUxrLp
This commit is contained in:
1 parent
843bcc421f
commit
6b7dccd1ee
19 files changed
+2479
-18
No files matched your search
@@ -66,6 +66,7 @@ pub const KNOWN_FEATURES: &[&str] = &[
|
||||
ATTACHMENT_TEXT,
|
||||
DRAFTS_V2,
|
||||
SOURCE_REVISIONS,
|
||||
AUDITS,
|
||||
];
|
||||
|
||||
/// Feature: `period.closed` closes to members with `"rounding":
|
||||
@@ -105,6 +106,9 @@ pub(crate) fn setting_feature(key: &str) -> Option<&'static str> {
|
||||
| "bills.discount_warn_days"
|
||||
| "company.email"
|
||||
| "company.website" => Some(DOCUMENTS_V2),
|
||||
// P8: what counts as an attestation, and whether the CPA package
|
||||
// waits for an audit.
|
||||
"policy.attestation_bar" | "policy.cpa_package_requires_audit" => Some(AUDITS),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@@ -228,6 +232,17 @@ pub const DRAFTS_V2: &str = "drafts_v2";
|
||||
/// declaration instead (rules.md B-27).
|
||||
pub const SOURCE_REVISIONS: &str = "source_revisions";
|
||||
|
||||
/// Feature: `audits` (plan P8): `audit.run` (a programme of checks run
|
||||
/// through a date, with the hash of its findings and its workpaper),
|
||||
/// `receipt.attested`, `entry.reviewed` and `period.attested` (claims by
|
||||
/// an authenticated client that it checked), and the two settings that
|
||||
/// say what counts (`policy.attestation_bar`) and whether the CPA package
|
||||
/// waits for an audit (`policy.cpa_package_requires_audit`). An older
|
||||
/// version doesn't know those event types or settings; it stops at the
|
||||
/// declaration instead of dropping the claims a handoff rests on
|
||||
/// (rules.md B-27, B-45).
|
||||
pub const AUDITS: &str = "audits";
|
||||
|
||||
/// The line type that declares the journal format.
|
||||
pub const FORMAT_SET: &str = "journal.format_set";
|
||||
|
||||
@@ -253,6 +268,7 @@ pub const EVENT_TYPES: &[&str] = &[
|
||||
"attachment.text_extracted",
|
||||
"attachment.unlinked",
|
||||
"attachment.withdrawn",
|
||||
"audit.run",
|
||||
"bill.created",
|
||||
"bill.paid",
|
||||
"class.added",
|
||||
@@ -275,6 +291,7 @@ pub const EVENT_TYPES: &[&str] = &[
|
||||
"entry.party_set",
|
||||
"entry.posted",
|
||||
"entry.reversed",
|
||||
"entry.reviewed",
|
||||
"entry.settles",
|
||||
"entry.vendor_set",
|
||||
"fx.rate_set",
|
||||
@@ -298,10 +315,12 @@ pub const EVENT_TYPES: &[&str] = &[
|
||||
"party.w9_set",
|
||||
"payroll.run",
|
||||
"payroll.taxes_remitted",
|
||||
"period.attested",
|
||||
"period.closed",
|
||||
"period.created",
|
||||
"project.set",
|
||||
"receipt.attached",
|
||||
"receipt.attested",
|
||||
"receipt.linked",
|
||||
"receipt.unlinked",
|
||||
"reconciliation.completed",
|
||||
@@ -1035,6 +1054,39 @@ mod tests {
|
||||
assert_eq!(up.adds(), vec!["the journal feature source_revisions"]);
|
||||
}
|
||||
|
||||
/// The version before P8 stops at a declaration of `audits` as newer,
|
||||
/// never dropping an attestation a handoff rests on; books that
|
||||
/// declared every earlier feature still wait for it (B-27, D-39).
|
||||
#[test]
|
||||
fn audits_is_its_own_feature() {
|
||||
assert!(KNOWN_FEATURES.contains(&AUDITS));
|
||||
let before: Vec<&str> = KNOWN_FEATURES
|
||||
.iter()
|
||||
.copied()
|
||||
.filter(|f| *f != AUDITS)
|
||||
.collect();
|
||||
let l = line(
|
||||
FORMAT_SET,
|
||||
json!({"format": 2, "features": [DRAFTS_V2, AUDITS]}),
|
||||
);
|
||||
match declared_knowing(&l, &before) {
|
||||
Err(StoreError::NewerJournal { need, .. }) => {
|
||||
assert_eq!(need, "journal features audits")
|
||||
}
|
||||
other => panic!("expected NewerJournal, got {other:?}"),
|
||||
}
|
||||
let older = JournalFormat {
|
||||
format: 2,
|
||||
features: before.iter().map(|f| f.to_string()).collect(),
|
||||
};
|
||||
assert!(matches!(
|
||||
older.require_feature(AUDITS),
|
||||
Err(StoreError::FormatUpgradePending { .. })
|
||||
));
|
||||
let up = older.upgrade().expect("waits for it");
|
||||
assert_eq!(up.adds(), vec!["the journal feature audits"]);
|
||||
}
|
||||
|
||||
/// This version's format: the newest it reads, every feature it
|
||||
/// knows, each once, sorted (what new books and an upgrade declare).
|
||||
#[test]
|
||||
|
||||
Reference in new issue
Block a user