A converted file can stop saying who made it - #26
Merged
Merged
Conversation
Three levels - keep everything, remove the location, remove what identifies a person, a device or a moment - as a step in the chain like any other, so it comes from Settings, or a preset, or a batch, or from the file's own name, in that order of specificity, and history records that it happened. What is never removed, at any level, is the colour profile and the orientation. They are not information about a person: without them the photograph arrives on its side, in the wrong colours. The test asserts both survive every strip. What counts as identifying is a list, not a chain of ifs about formats, and a tag on no list is carried across - a conversion that quietly loses something is worse than one that keeps too much. Maker notes are the exception that proves it: they are named after the camera that wrote them, so the shape of the key is the rule rather than a list of cameras nobody can finish. Reading the filename had to change to do this: only the last piece was read, so `holiday_10MB_privacy.jpg` lost the size. Tokens are now read from the end and stop at the first piece that is not one, which keeps `10MB_notes.jpg` meaning what it always meant. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018H9CZxWumc3ryumgEHd578
Vision reads faces and text, Natural Language reads that text for names, places and organisations, and all of it arrives as suggestions with every box unticked. A detector's opinion is not consent: the type that burns a redaction into a file takes regions, not a session, so there is no argument it can be handed that means "whatever was found". It misses things - a face turned away, handwriting, a name in a reflection - and the sheet says so where it cannot be missed. Nothing in the app calls this anonymisation. The copy is written to a place the user chose, through the same scratch file and single move as every other write here. The original is never the thing that gets covered. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018H9CZxWumc3ryumgEHd578
Choosing a preset filled the fields in from it and cleared most of them first - but not the size ceiling, and not the metadata level I had just added. Pick a preset that strips metadata, then pick one that says nothing about it, and the chip still read "remove identifying metadata". That is worse than a wrong-looking chip: touching any other field lets the preset go, and from that moment the stale answer is what actually runs. The mapping from a preset to the sheet's fields moves onto ConvertChoice so it can be tested at all, which is how the same bug will be caught next time a field is added. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018H9CZxWumc3ryumgEHd578
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two layers, separable on purpose.
Layer 1 — metadata, deterministic and ship-ready. Three levels (keep all / remove the location / remove identifying metadata) as a step in the chain like any other, so it comes from Settings, or a preset, or a batch, or from the file's own name, in that order of specificity — and history records that it happened.
What is never removed, at any level, is the colour profile and the orientation. They are not information about a person: without them the photograph arrives on its side, in the wrong colours. The tests assert both survive every strip.
What counts as identifying is a list, not a chain of
ifs about formats, and a tag on no list is carried across — a conversion that quietly loses something is worse than one that keeps too much. Maker notes are the exception that proves it: they are named after the camera that wrote them, so the shape of the key is the rule rather than a list of cameras nobody can finish. PDFs lose author, creator and producer and keep their title; exports lose location, and at the thorough level go through AVFoundation's own sharing filter.Reading the filename had to change: only the last piece was read, so
holiday_10MB_privacy.jpglost the size. Tokens are now read from the end and stop at the first piece that is not one, which keeps10MB_notes.jpgmeaning what it always meant.Layer 2 — assisted redaction, behind its own types. Vision reads faces and text, Natural Language reads that text for names, places and organisations, and all of it arrives as suggestions with every box unticked. The type that burns a redaction into a file takes regions, not a session, so there is no argument it can be handed that means "whatever was found". It misses things, the sheet says so where it cannot be missed, and nothing in the app calls this anonymisation.
Also fixed: choosing a preset now clears every field the previous one set — the metadata level and the size ceiling were left behind, and touching any other field let the preset go and applied the stale answer for real.
Test plan
swift test— green_10MB_privacyapplies both;_privacyclassifies as explicit, so no popup_privacystripped GPS and camera make, kept orientation 6 and sRGB; without the token everything was carried across🤖 Generated with Claude Code
https://claude.ai/code/session_018H9CZxWumc3ryumgEHd578