Fail closed on unreadable inputs, empty batches and failed strips

The metadata scanners read raw bytes, so random bytes, an empty file or a
truncated PNG or MP4 printed the same "No AI metadata found" or "AI metadata
stripped" a real file gets, with exit 0. `metadata.unreadable_reason` is now
the one readability probe: `identify`, `metadata` and every `video` command
exit 1 on such input, and `batch` and `video batch` fail its row.
`strip_and_verify` refuses it before writing anything.

A `batch` or `video batch` directory with no supported file exits 2 and
creates no output directory. `visible` and `erase` strip and verify on a
staged sibling and publish nothing when a marker survives, as the library
`remove_visible` now does; the diffusion writer raises on a surviving
marker. An invisible engine that cannot start exits 1 without a traceback,
and the MCP server reports a child that could not start.

NotebookLM and Gemini slide-deck templates are recorded as not planned.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Victor KuznetsovandClaude Opus 5.5 committed 2026-10-19 11:23:59 -07:00
1 parent 33a0e6c987
commit 7e167c3c76
24 files changed
+636 -116

No files matched your search

+8 -4
View File
@@ -79,7 +79,8 @@ For a path input, `remove_visible` and `remove_visible_detailed`:
- reads metadata provenance for the default `auto` sensitivity;
- preserves a separate alpha channel;
- writes the output when an output path is supplied;
- strips AI metadata from the written output by default;
- strips AI metadata from the written output by default, and raises
`MetadataStripIncomplete` without publishing it when a marker survives;
- preserves the original bytes for a same-format no-op copy.
```python
@@ -226,8 +227,9 @@ The complete field set, with the shipped defaults:
and not to this table, because this seam had already drifted by eight fields
before anything checked it.
If AI metadata survives the strip, `remove_all` raises `MetadataStripIncomplete`
**before** writing anything: an AI-readable output is worse than no output.
If AI metadata survives the strip, `remove_all` and a path-input `remove_visible`
raise `MetadataStripIncomplete` **before** publishing anything: an AI-readable
output is worse than no output.
`remove_batch` runs one mode over a directory and never lets a single bad file
end the run:
@@ -525,7 +527,9 @@ It checks the written output and returns `(output_path, surviving_markers)`.
When the first strip leaves markers in a malformed but raster-decodable image,
it normalizes the container through `image_io` and checks again. That recovery
path preserves the pixels but drops standard metadata. Treat a nonempty
`surviving_markers` mapping as a failure.
`surviving_markers` mapping as a failure. A source that is not a readable image,
video or audio container raises `ValueError` before anything is written;
`metadata.unreadable_reason(path)` returns the same reason without stripping.
`remove_ai_metadata` is the lower level fail-safe transformer. It may copy an
undecodable input through unchanged, so its return alone must not be presented