The archive probe read and checksummed every member before the importer
looked at what the archive held. For a multi-gigabyte game build that is
minutes of work on a file that is kept whole and never extracted, and it
held a re-extract chunk far past its time budget.
- The importer checks the archive's directory for a software build first,
for the outer archive and for one nested inside an art pack, and only
probes archives it may extract.
- The probe rejects an archive over the size cap from its directory totals,
before the integrity test decompresses anything.
- Re-extract logs each archive as it starts and finishes, with its size and
how long it took, so an archive that stalls a chunk is named in the log.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Most archive attachments never had their images imported. The re-extract
action skipped archives without a post, and nothing kept game builds out
of an extraction.
- An archive holding executables, libraries, or game-engine data
(Ren'Py, Unity, Godot, RPG Maker, Python builds) is kept as an
attachment and not extracted. The same holds for one nested inside an
art pack.
- Re-extract now reaches archives imported from a folder without a post.
Their images go to the artist, in a folder named after the archive.
- Re-extract passes over archives whose members are already recorded.
- Re-extract stages each archive by symlink instead of copying it.
- The card says what the action does now.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Images pulled out of a .zip/.rar previously kept no record of WHICH archive
they came from — the member->archive link was computed during extraction and
discarded, leaving only image->post. So the provenance modal could only scope
attachments to the whole post, showing every archive a 'High Resolution Files'
bundle carried instead of the one a given file lives in.
- ImageProvenance.from_attachment_id: nullable FK -> post_attachment.id
(SET NULL), migration 0055.
- importer: _import_archive stamps from_attachment_id on every member's
provenance row for the post (new + superseded + deduped members), resolving
the archive's own PostAttachment by (post, sha). Post-pass UPDATE, NULL-only
and idempotent, so it doesn't touch the dedup/supersede branches and the
backfill is safe to re-run. Nested members link to the outer stored archive.
- provenance_service.for_image: when the originating post's provenance row
records from_attachment_id, return ONLY that archive; else fall back to the
primary-post scoping from 068def2.
- ProvenancePanel: heading pluralizes ('Attachment' for a single file).
- Backfill: re-running reextract_archive_attachments (ArchiveReextractCard)
routes through _import_archive and stamps existing rows — no new code.
Tests: capture stamps on fresh import, nested-archive attribution, per-post
archive on dedup; for_image filters to the containing archive; reextract
backfill stamps the link.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Root cause (operator-confirmed via event metadata + lsar): a "High Resolution
files" pack often wraps a per-chapter .rar/.zip INSIDE one outer archive (incase).
_import_archive only extracted one level — a nested-archive member failed
is_supported and was skipped, so the real pages were silently dropped and the post
showed "archive but no images". The disk scan found this pattern recurring across
the attachment store.
- Recurse into nested archives via _collect_archive_members: a member that is
itself an archive is bomb-probed and extracted too, depth-capped at
_ARCHIVE_MAX_DEPTH=3. Nested members attribute to the OUTER archive's sidecar so
they link to the right Post. Each level is wrapped so one bad nested archive
can't abort the import. The shared path means external (mega/gdrive) archives
recurse too.
- Replace the catch-all "held no supported members" string with a per-outcome
tally (media/deduped/unsupported/failed/nested/nested_rejected). The all-deduped
case is now recognised as BENIGN — images already in the library, re-linked to
this post via enrich-on-duplicate — and returns attached WITHOUT error, so it no
longer false-flags in event metadata.unextracted_archives. Genuine failures
carry the precise breakdown.
Tests: nested zip-in-cbz imports both inner images + links them to the outer post;
all-deduped archive returns attached with error=None and links images to both posts.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>