You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Sad Catapella B5][Scientific integrity] Reused TIFF-converted Zarr copies are not validated against their stored pixels #87
Adversarial audit Batch 5 at d7a538e56d41ac1093ba79adcad397c21b3dfd32. Confirmed missing verification in copy-reuse predicate; a missing Zarr chunk can be interpreted as fill value rather than a read error. End-to-end fixture not run.
Evidence
run_experiment() unchanged-copy predicate checks only whether the copy folder exists, conversion settings match, axis units match and channel labels match. It never checks level-0 shape, dtype, chunks, chunk presence/content or a copy integrity digest.
_load_previous() validates the CSV hash and source TIFF signatures, not the converted Zarr chunks.
OmeZarrWriter._open() creates Zarr arrays with a fill value of zero (see _create_array()). A deleted, previously nonzero chunk can therefore read as zeros from a sparse Zarr array rather than failing loudly.
Tests check that deleting the entire copy directory triggers re-conversion, not an interior 0/ chunk.
Reproducer to implement
Convert a TIFF with a nonzero level-0 chunk. Save table/manifest. Delete or overwrite one level-0 Zarr chunk while leaving .zattrs, .zarray and the source TIFF unchanged. Rerun with convert_tiffs=True. The current predicate can treat the source as unchanged and reuse its prior histogram; the reused copy's pixel values no longer match the histogram. Validate also truncation, dtype/shape edits and changes to non-level-0 pyramids.
Impact
A manifest and histogram table can claim to describe the exported data while that persisted exported data has been changed or lost. Downstream consumers of converted copies can silently analyze zero-filled/mismatching pixels.
Fix
Record and validate copy integrity (versioned per-chunk hashes or a trustworthy immutable manifest/index, including metadata), or rebuild/verify copies that cannot be trusted; the chosen trade-off should be documented and benchmarked for large stores. Ensure successful reuse implies level-0 data exactly matches recorded source histograms. Do not silently interpret missing expected chunk payload as a real zero image. Test corrupt/missing chunks, changed metadata, intact unchanged copies and rollback. No Numba benefit for I/O verification; hashing codecs may already be accelerated.
Obsolete in v0.4.0: convert_tiffs, zarr_export and OME-Zarr copy reuse were removed in PP-2 (#66, commit 3c2802d; plan question 46). Named-axis copies of images with axis errors are now the OME-TIFF convert step (PP-11, #124, merged as 8db1f4a). Closing as not planned (owner-approved triage, 2026-11-02).
PP-11 reuses a copy only after checking its fingerprint against the conversion record, and RunInputs refuses a run whose conversion record changed or disappeared.
Reopening: an independent review of commit 8db1f4a found the closure premature. Copy reuse checks the copy's fingerprint, but a fingerprint is only size + mtime (fingerprint.py), and the conversion record's SHA-256 covers the JSON record, not the image copies. A same-size change with the mtime preserved is not caught. Owner decision: record a SHA-256 of each copy when it is written; reuse, review_conversion and RunInputs on a copy tree verify it. Tracked in PR PP-11c.
Fixed by PR #126, merged as 6ac81ad (fix commits 4312b5a, 792a6c1 and 418bbbd). I checked each point in the code before closing:
Every copy's SHA-256 (copy_sha256, record version 2) is computed from the copy on disk after it is written.
The SHA-256 is checked at reuse, in review_conversion (check/run) and in RunInputs.open, which checks every recorded image. Excluded images are never read.
A same-size change with the modification time put back is caught, and so is an OME-Zarr chunk changed in place.
An OME-Zarr copy that holds a folder link counts as changed: it is never hashed in part.
A version 1 record is refused everywhere it is read.
Activity
guijacquemet commentedon Nov 2, 2026
Obsolete in v0.4.0:
convert_tiffs,zarr_exportand OME-Zarr copy reuse were removed in PP-2 (#66, commit 3c2802d; plan question 46). Named-axis copies of images with axis errors are now the OME-TIFFconvertstep (PP-11, #124, merged as 8db1f4a). Closing as not planned (owner-approved triage, 2026-11-02).PP-11 reuses a copy only after checking its fingerprint against the conversion record, and RunInputs refuses a run whose conversion record changed or disappeared.
Generated by Claude Code
guijacquemet commentedon Nov 2, 2026
Reopening: an independent review of commit 8db1f4a found the closure premature. Copy reuse checks the copy's fingerprint, but a fingerprint is only size + mtime (
fingerprint.py), and the conversion record's SHA-256 covers the JSON record, not the image copies. A same-size change with the mtime preserved is not caught. Owner decision: record a SHA-256 of each copy when it is written; reuse,review_conversionandRunInputson a copy tree verify it. Tracked in PR PP-11c.Generated by Claude Code
PP-11c: conversion integrity (copy SHA-256, one metadata epoch, exact…
guijacquemet commentedon Nov 2, 2026
Fixed by PR #126, merged as 6ac81ad (fix commits 4312b5a, 792a6c1 and 418bbbd). I checked each point in the code before closing:
copy_sha256, record version 2) is computed from the copy on disk after it is written.review_conversion(check/run) and inRunInputs.open, which checks every recorded image. Excluded images are never read.Generated by Claude Code