Recapture image→post linking (#1288) + ugoira timings + system suggestion category #192

Merged
bvandeusen merged 3 commits from dev into main 2026-07-04 20:36:59 -04:00
Owner

Merges dev → main. All CI-green on dev head 8838b32 (run 1925). No new migration — all three changes are code-only.

Recapture links on-disk images to their post (issue #1288)

Recapture disk-skips already-downloaded media and upsert_post_record only writes Post fields, so pre-existing images (pulled under the old gallery-dl path, imported bare) stayed orphaned even after their post record was written — confirmed 329 orphaned pixiv images / 694 content-only posts / 0 dup posts on the operator's instance. Fix: the recapture relink channel now carries the media's post_id, and phase 3 calls importer.link_existing_image_to_post (match image by path, find Post by source+external_post_id, upsert image_provenance + primary_post_id). Provenance-linking factored into a shared _attach_provenance (DRY with the fresh-import path). Idempotent; no-op for already-linked Patreon/SubscribeStar.

Operator action after deploy: re-run Recapture on the pixiv sources — it now back-links the orphaned art as it re-walks.

Pixiv ugoira frame timings (issue #1287)

write_post_record runs before extract_media, so ugoira frame delays were never captured. Now fetched via a shared/memoized client call (zero extra API calls). Recapture also backfills these.

System suggestion category (task #1286)

wip/banner/editor suggestions group under their own "System" category (top of the panel, above Character/General) instead of mixing into General, so false positives are easy to reject.

🤖 Generated with Claude Code

https://claude.ai/code/session_01CDgx8bQS5YrGRK76v8HUnM

Merges dev → main. All CI-green on dev head `8838b32` (run 1925). **No new migration** — all three changes are code-only. ### Recapture links on-disk images to their post (issue #1288) Recapture disk-skips already-downloaded media and `upsert_post_record` only writes Post fields, so pre-existing images (pulled under the old gallery-dl path, imported bare) stayed orphaned even after their post record was written — confirmed 329 orphaned pixiv images / 694 content-only posts / 0 dup posts on the operator's instance. Fix: the recapture relink channel now carries the media's post_id, and phase 3 calls `importer.link_existing_image_to_post` (match image by path, find Post by source+external_post_id, upsert image_provenance + primary_post_id). Provenance-linking factored into a shared `_attach_provenance` (DRY with the fresh-import path). Idempotent; no-op for already-linked Patreon/SubscribeStar. **Operator action after deploy:** re-run Recapture on the pixiv sources — it now back-links the orphaned art as it re-walks. ### Pixiv ugoira frame timings (issue #1287) `write_post_record` runs before extract_media, so ugoira frame delays were never captured. Now fetched via a shared/memoized client call (zero extra API calls). Recapture also backfills these. ### System suggestion category (task #1286) wip/banner/editor suggestions group under their own "System" category (top of the panel, above Character/General) instead of mixing into General, so false positives are easy to reject. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01CDgx8bQS5YrGRK76v8HUnM
bvandeusen added 3 commits 2026-07-04 20:36:52 -04:00
fix(pixiv): capture ugoira frame timings in the post record (ordering bug)
CI / lint (push) Successful in 3s
CI / frontend-build (push) Successful in 19s
CI / backend-lint-and-test (push) Successful in 28s
CI / integration (push) Successful in 3m33s
f33808b977
The core writes the post record BEFORE extract_media, but the ugoira frame
delays were only memoized DURING extract_media — so write_post_record never saw
them and ugoira_frames was always empty in the record. Extract a memoized
_ugoira_meta (frames + zip url share ONE /v1/ugoira/metadata call regardless of
order) and inject client.fetch_ugoira_frames into the downloader (mirrors
Patreon's content_fetcher) so write_post_record populates the frames itself.
Zero extra API calls — the fetch is shared/memoized with extract_media. A
recapture now backfills the timings onto existing ugoira posts.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CDgx8bQS5YrGRK76v8HUnM
feat(suggestions): group wip/banner/editor under a separate 'system' category
CI / lint (push) Successful in 2s
CI / frontend-build (push) Successful in 22s
CI / backend-lint-and-test (push) Successful in 30s
CI / integration (push) Successful in 3m36s
437bf4d37a
System tags are kind=general, so their suggestions previously landed in the
General group. Give them their own 'system' suggestion category so the operator
reviews them apart from content tags: _current_heads maps is_system heads to
category 'system' (still trained as general heads, still gated by the 0.65
floor). Frontend: CATEGORY_ORDER/LABELS gain 'system'; SuggestionsPanel renders
a 'System' group first (small, collapsible, open — false positives easy to spot
and reject); the typed-dropdown shows the shield icon for system entries. Safe:
system-tag suggestions always carry a canonical_tag_id, so the create-by-kind
path (which would send 'system' as a TagKind) is never hit.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CDgx8bQS5YrGRK76v8HUnM
fix(recapture): link on-disk images to their post (#1288)
CI / lint (push) Successful in 2s
CI / frontend-build (push) Successful in 19s
CI / backend-lint-and-test (push) Successful in 36s
CI / integration (push) Successful in 3m32s
8838b325fb
Recapture disk-skips already-downloaded media, and upsert_post_record only
writes Post fields — so a pre-existing image (e.g. one pulled under the old
gallery-dl path, imported bare with no post) stays orphaned even after its post
record is (re)written. Confirmed on the operator's instance: 329 pixiv images
with primary_post_id NULL, 694 pixiv posts with content but no linked images, 0
duplicate posts.

Fix: the recapture relink channel now carries the media's post_id (2- → 3-tuple
path/url/post_id), and phase 3 calls importer.link_existing_image_to_post — match
the on-disk image by path, find its Post by (source, external_post_id), upsert
image_provenance + primary_post_id. Factored the provenance-linking out of
_apply_sidecar into a shared _attach_provenance so the fresh-import and
recapture-backlink paths can't diverge. Idempotent; generic across native
platforms (no-op for already-linked Patreon/SubscribeStar). Re-running recapture
now repairs orphaned images; future walks never orphan.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CDgx8bQS5YrGRK76v8HUnM
bvandeusen merged commit 4c3ba20198 into main 2026-07-04 20:36:59 -04:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: bvandeusen/FabledCurator#192