Repository navigation
Conversation
) An applied redaction keeps the remaining text in place through a TJ displacement of the removed glyphs' width. text_lines measured a show from its origin to the end of its advance, displacement included, so the box the redaction drew over that gap covered 40% of the "line" and the audit flagged the program's own output. A show's box now spans the glyphs it paints, split at large displacements, and a line keeps those spans; the audit measures a cover against them, so a gap under a box hides nothing while a box over glyphs is still found. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RUNQSPVXx3dDBabRZHAnjz
0082452 to
fc27cbc
Compare
|
This is still needed alongside #1949: its audit changes continue to measure |
|
Agreed. Once #1949 is merged I will rebase this on top of it and merge the two sets of checks, keeping the leading, trailing and interior-gap tests here and the opaque-cover and appearance tests there. |
|
Closing: #1898 (merged today) fixed #1885 another way, by measuring covers against word boxes ( |
What this changes
Fixes #1885. The redaction audit no longer flags the program's own applied redaction. All three acceptance criteria in the issue hold.
Cause.
redact_applykeeps the text left on a line in place through aTJdisplacement of the removed glyphs' width:[(Call ) -6672] TJ.pdfcraft_edit::text_linesmeasured a text show from its origin to the end of its advance, displacement included, so the "Call " line's box ran on under the black box the redaction drew. The box covered more than 40% of that box, and the audit reportedcovered_text: "Call". The same happened with a leading displacement ([-6672 (is mine)] TJ, "is mine" flagged) and would with one in the middle.Fix.
crates/edit/src/text.rs: a show's box spans the glyphs it paints. A displacement before, between or after them (a tab stop, the width of text a redaction removed) paints nothing, so it is in no box. Glyph runs separated by a large displacement (the existing "reads as a space" threshold) become separate boxes, and aTextLinekeeps the boxes of every show it joins (TextLine::spans). The line'srect,advance,start_x/end_xand the line-joining rules are unchanged, so editing, reflow and move/resize behave as before (the edit crate's 132 tests and the engine's text tests pass).crates/audit/src/lib.rs:coversmeasures the cover against those spans, not the line's whole box: the covered fraction is the overlapped span area over the total span area. Unapplied-mark findings use the same measure.The audit's documented behaviour, "a properly applied redaction removes the text, so it never flags", is now true for the program's own output as well as for other producers' streams with the same shape (tab stops drawn as
TJgaps under a filled box).How you verified it
cargo fmt --checkcargo clippy -p pdfcraft-edit -p pdfcraft-audit -p pdfcraft-automation -j 2 --all-targets -- -D warningscargo test -p pdfcraft-audit -j 2(14),-p pdfcraft-edit(132),-p pdfcraft-redact(40),-p pdfcraft-automation --test automation(154),-p pdfcraft-engine --lib text(13): all passcargo test -p pdfcraft-ui-egui --test editing: 115 pass; the two that fail (files_dropped_outside_the_page_grid_still_open_as_documents,password_prompt_opens_and_security_tab_reports_the_details) fail or flake onmainwithout this change — they are the background-open race from Desktop: prepare large PDFs off the UI thread #1493 that test(ui): extend native opening and continuation regression coverage #1764 fixes withwait_for.The issue's own steps, with the PyMuPDF fixture and a built
pdfcraft-cli:pdfcraft-cli audit m2_out.pdf{"count":1,"findings":[{"covered_text":"Call",…,"rect":[72.0,759.8,145.392,770.8]}]}, exit 1{"count":0,"findings":[]}, exit 0m2_out.pdfCallCallTests.
a_cover_over_a_tj_gap_hides_no_text(audit): the one-line fixture as a content stream, in the three shapes[(Call ) -6672] TJ,[-6672 (is mine)] TJand[(Call ) -6672 ( is mine)] TJ, each with the box over the displacement: no finding. The same text with the box over "Call" itself: one finding,covered_text: "Call"(criterion 2, together with the existingrectangle_drawn_as_a_path_covers_text_like_re).an_applied_redaction_audits_clean(automation, end to end):doc_create from=text→redact_mark pattern=phone→redact_apply→doc_audit_redactionsonCall 01 23 45 67 89,01 23 45 67 89 is mineandCall 01 23 45 67 89 is mine: the number is gone from the page text and the count is 0.Each half of the fix is needed; the tests show it:
count: 1"Call is mine")Never-crash
unwrap/expect/indexing outside tests; the span fold usesfold/max/minover finite operands as beforeunsafeProvenance
Security
Parity and reach
doc_audit_redactionsandpdfcraft-cli auditshare it🤖 Generated with Claude Code