mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-11-02 14:38:13 -06:00
The redaction audit turned an re rectangle into an unknown path on a redundant h, and its fill branch left out the close-fill-stroke operators b and b*, so those opaque covers over extractable text produced no finding. Keep a closed rectangle closed under h and treat b/b* like the other fills. Claude-Session: https://claude.ai/code/session_01RUNQSPVXx3dDBabRZHAnjz Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
pdfcraft-audit
Layer L4 (may use edit): verification tooling, the faux-redaction audit.
let findings: Vec<Finding> = audit_redactions(&doc)?; // page, kind, rect, covered_text
It reports two kinds of finding:
- faux redaction: an opaque filled rectangle painted after text it overlaps, dark enough against the text's colour (WCAG contrast below 3) to hide it, while the text is still extractable underneath;
- unapplied mark: a Redact annotation that was marked but never applied.
A properly applied redaction removes the text, so it never flags. Page backgrounds, table shading and highlights don't either: they're painted before the text, or light against it.
Limits, by design and documented rather than hidden:
- only filled rectangles count as covers, drawn with
reor as a singlem/lsubpath whose corners form an axis-aligned rectangle (not other paths, shadings or patterns), and a translucent one (/cabelow 1) is not flagged; - covers inside form XObjects are found, but only text drawn directly in the page content is checked under them;
- annotation rectangles are compared in unrotated user space, so
/Rotatepages may misalign.
It fails closed: an undecodable content stream, malformed /Annots, form XObjects nested deeper
than 32 or in a cycle, or a walk past the operator bound is an error, never "no findings".
Surfaces: the redact_audit automation tool and pdfcraft-cli.