merge: P6, the evidence pipeline (branch P6, checkpoint ce366408)
The last of the paused branches, from its "not for merge" checkpoint:
extraction in ledger-import (text, pages, page images; capped, caught),
journaled as attachment.text_extracted; dedup by hash with
books.find_attachment and books.consolidate_duplicates; annotations and
books.set_entry_settles; the company record categories; the two fuzz
targets; feature attachment_text. Nineteen files conflicted with the
four P4b merges, resolved as plan 8.0.2 says: P6 retakes schema 18 (it
had taken 16, which S4.3 holds; S5 holds 17); the tool table is 129 and
the destructive count 31; both sides' appends kept with their seams
restored; one B-27 paragraph naming every feature; in the old-books
fixture P6's hand-written reimbursement is entry 7 (its ids collided
with S4.3's invoice); the replay fuzzer's list gains S7's
invoice.written_off; S4.3's issued-PDF test expects the extraction
record P6 journals right after a filing.
One integration defect between S7 and P6, found by the arap property
test and fixed here: under P6's dedup, a write-off whose evidence bytes
were filed already (the same collection letter for a second write-off of
the same invoice) was refused only after its entry had been journaled,
at the final link to the invoice ("already linked"). The write-off now
resolves the dedup before anything is journaled and keeps a link the
record already has to the invoice instead of refusing it; an explicit
existing_attachment_id already on an entry is still refused (S7's
one-receipt-once rule). P6's gate never ran before the pause; it runs on
main after this merge, and its ledger-store -> ledger-import dependency
is the open review point (plan 8.0.1).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HS8WZziDnyxunC23MUxrLp
This commit is contained in:
commit
9351f89d38
70 files changed
+4636
-403
No files matched your search
@@ -78,6 +78,20 @@ test = false
|
||||
doc = false
|
||||
bench = false
|
||||
|
||||
[[bin]]
|
||||
name = "fuzz_extract_pdf"
|
||||
path = "fuzz_targets/fuzz_extract_pdf.rs"
|
||||
test = false
|
||||
doc = false
|
||||
bench = false
|
||||
|
||||
[[bin]]
|
||||
name = "fuzz_extract_xlsx"
|
||||
path = "fuzz_targets/fuzz_extract_xlsx.rs"
|
||||
test = false
|
||||
doc = false
|
||||
bench = false
|
||||
|
||||
[[bin]]
|
||||
name = "fuzz_config_parse"
|
||||
path = "fuzz_targets/fuzz_config_parse.rs"
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
//! The PDF extractor on arbitrary bytes (plan P6): reading text, a page's
|
||||
//! pixels and the page count is a refusal or an answer, never a panic or a
|
||||
//! hang (D-32: it runs in the server's process).
|
||||
#![no_main]
|
||||
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
|
||||
fuzz_target!(|data: &[u8]| {
|
||||
let _ = ledger_import::extract::pdf_text(data);
|
||||
let _ = ledger_import::extract::pdf_lines(data);
|
||||
if let Ok(pages) = ledger_import::extract::page_count(data) {
|
||||
for page in [0, pages.saturating_sub(1), pages] {
|
||||
let _ = ledger_import::extract::page_png(data, page, 64);
|
||||
}
|
||||
}
|
||||
let _ = ledger_import::extract::text_of(data, "application/pdf", "receipt.pdf");
|
||||
});
|
||||
@@ -0,0 +1,15 @@
|
||||
//! The XLSX extractor on arbitrary bytes (plan P6): a zip or not, a sheet
|
||||
//! or not, it is a value or a refusal, never a panic; a cell's number is
|
||||
//! read as the decimal string the XML holds.
|
||||
#![no_main]
|
||||
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
|
||||
fuzz_target!(|data: &[u8]| {
|
||||
let _ = ledger_import::extract::xlsx_text(data);
|
||||
let _ = ledger_import::extract::text_of(
|
||||
data,
|
||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||
"sheet.xlsx",
|
||||
);
|
||||
});
|
||||
@@ -22,27 +22,29 @@ use libfuzzer_sys::fuzz_target;
|
||||
use serde_json::{Map, Value, json};
|
||||
|
||||
const TYPES: &[&str] = &[
|
||||
"account.added", "account.renamed", "account.tax_set", "asset.depreciation_posted",
|
||||
"asset.disposed",
|
||||
"asset.registered", "attachment.withdrawn", "bill.created", "bill.paid", "class.added",
|
||||
"customer.added", "document.filed", "entry.created", "entry.line_added",
|
||||
"entry.line_class_set", "entry.posted", "entry.reversed", "entry.vendor_set",
|
||||
"fx.rate_set", "invoice.created", "invoice.payment_received", "invoice.sent",
|
||||
"invoice.written_off",
|
||||
"journal.tail_repaired",
|
||||
"line.cleared", "payroll.run", "period.closed", "period.created", "receipt.attached",
|
||||
"receipt.linked", "receipt.unlinked", "recurring.generated", "recurring.registered",
|
||||
"schedule.posted", "schedule.registered", "vendor.1099_set", "vendor.added",
|
||||
"journal.format_set", "settings.set", "convention.set", "convention.retired",
|
||||
"decision.recorded", "open_item.raised", "open_item.resolved", "entry.approved",
|
||||
"vendor.w9_flag_set", "instrument.added", "entry.instrument_set", "asset.basis_set",
|
||||
"party.creditor_set", "account.renumbered", "asset.acquisition_linked", "asset.corrected",
|
||||
"asset.described", "asset.serial_set", "asset.tagged", "asset.tax_basis_set",
|
||||
"attachment.linked", "attachment.unlinked", "entry.no_party", "entry.parties_set",
|
||||
"entry.party_set", "party.added", "party.role_set", "party.tin_set", "party.updated",
|
||||
"party.w4_set", "party.w9_set", "payroll.taxes_remitted", "reconciliation.completed",
|
||||
"reconciliation.voided", "role.assigned", "statement.recorded", "statement.voided",
|
||||
"project.set",
|
||||
"account.added", "account.renamed", "account.tax_set", "asset.depreciation_posted",
|
||||
"asset.disposed",
|
||||
"asset.registered", "attachment.annotated", "attachment.text_extracted", "attachment.withdrawn",
|
||||
"bill.created", "bill.paid", "class.added",
|
||||
"customer.added", "document.filed", "entry.created", "entry.line_added",
|
||||
"entry.line_class_set", "entry.posted", "entry.reversed", "entry.vendor_set",
|
||||
"fx.rate_set", "invoice.created", "invoice.payment_received", "invoice.sent",
|
||||
"invoice.written_off",
|
||||
"journal.tail_repaired",
|
||||
"line.cleared", "payroll.run", "period.closed", "period.created", "receipt.attached",
|
||||
"receipt.linked", "receipt.unlinked", "recurring.generated", "recurring.registered",
|
||||
"schedule.posted", "schedule.registered", "vendor.1099_set", "vendor.added",
|
||||
"journal.format_set", "settings.set", "convention.set", "convention.retired",
|
||||
"decision.recorded", "open_item.raised", "open_item.resolved", "entry.approved",
|
||||
"vendor.w9_flag_set", "instrument.added", "entry.instrument_set", "asset.basis_set",
|
||||
"party.creditor_set", "account.renumbered", "asset.acquisition_linked", "asset.corrected",
|
||||
"asset.described", "asset.serial_set", "asset.tagged", "asset.tax_basis_set",
|
||||
"attachment.linked", "attachment.unlinked", "entry.no_party", "entry.parties_set",
|
||||
"entry.party_set", "party.added", "party.role_set", "party.tin_set", "party.updated",
|
||||
"party.w4_set", "party.w9_set", "payroll.taxes_remitted", "reconciliation.completed",
|
||||
"reconciliation.voided", "role.assigned", "statement.recorded", "statement.voided",
|
||||
"project.set", "entry.settles",
|
||||
// Merged 2026-10-28 (S7, P6): every type EVENT_TYPES names.
|
||||
];
|
||||
|
||||
const FIELDS: &[&str] = &[
|
||||
|
||||
Reference in new issue
Block a user