fix(audit-g5a): small architectural cleanups bundle
Five small G5 findings from the 2026-06-02 audit. Each is local and
follows an established FC pattern.
- download_service: replace hardcoded ('discord','pixiv') tuple with
auth_type_for(platform) == 'token'. A 7th token-platform now picks
up the right credential path without touching this site.
- /api/tags/<source_id>/merge enqueues recompute_centroid.delay after
merge so the target's centroid reflects its new image set
immediately. Daily list_drifted catches it within 24h, but eager
recompute closes the suggestion-quality dip in the meantime.
- backfill_thumbnails added to beat_schedule (daily). The task
docstring claimed periodic Beat but the entry was never registered,
so the library got no self-healing thumbnail repair; only the
manual admin-UI button fired it.
- modal.createAndAdd pushes a kind='fandom' tag into
tagsStore.fandomCache so FandomPicker sees the new fandom on next
open. Was: cache-gated load (length===0) skipped refetch, new
fandom invisible until full page reload.
- cleanup cluster:
- Drop .webp from cleanup_service.unlink — thumbnailer only writes
.jpg/.png; the third tuple member was dead code.
- Drop effective_date from /api/gallery/scroll response — no FE
consumer reads it. Service still computes the attribute for
timeline ordering; this just trims the JSON.
- Rename store.recentMinute → store.recentRuns across the
systemActivity store + three consumers (SystemActivitySummary,
QueuesTable, SystemActivityTab). The data is the last 200 runs
(not actually "last minute"), so the name lied.
NOT in this bundle: the duplicate tag-merge endpoint
(/api/tags vs /api/admin/tags) is harder — has 1 FE caller and 3 tests
on the admin variant; consolidation is its own change.
This commit is contained in:
@@ -43,7 +43,6 @@ async def scroll():
|
||||
"height": i.height,
|
||||
"created_at": i.created_at.isoformat(),
|
||||
"posted_at": i.posted_at.isoformat() if i.posted_at else None,
|
||||
"effective_date": i.effective_date.isoformat(),
|
||||
"thumbnail_url": i.thumbnail_url,
|
||||
"artist": i.artist,
|
||||
}
|
||||
|
||||
@@ -245,6 +245,12 @@ async def merge_tag(source_id: int):
|
||||
from ..tasks.ml import apply_allowlist_tags
|
||||
|
||||
apply_allowlist_tags.delay(tag_id=result.target_id)
|
||||
# Tag merge invalidates the target's centroid (the merged-in source
|
||||
# tag's images now contribute to it). Daily list_drifted catches it
|
||||
# within 24h, but eager recompute closes the suggestion-quality dip
|
||||
# in the meantime. Audit 2026-06-02.
|
||||
from ..tasks.ml import recompute_centroid
|
||||
recompute_centroid.delay(result.target_id)
|
||||
return jsonify(
|
||||
{
|
||||
"target": {
|
||||
|
||||
@@ -130,6 +130,16 @@ def make_celery() -> Celery:
|
||||
"task": "backend.app.tasks.maintenance.prune_import_batches",
|
||||
"schedule": 86400.0,
|
||||
},
|
||||
# Audit 2026-06-02 — backfill_thumbnails's docstring claimed
|
||||
# "periodic Beat" but the entry was never registered, so the
|
||||
# library got no self-healing thumbnail repair; only the
|
||||
# manual admin-UI button fired it. Daily cadence is gentle
|
||||
# (the task is idempotent and only enqueues regen for rows
|
||||
# whose stored thumbnails are missing or corrupt).
|
||||
"backfill-thumbnails-daily": {
|
||||
"task": "backend.app.tasks.thumbnail.backfill_thumbnails",
|
||||
"schedule": 86400.0,
|
||||
},
|
||||
},
|
||||
timezone="UTC",
|
||||
)
|
||||
|
||||
@@ -187,10 +187,14 @@ def unlink_image_files(
|
||||
out["thumbnail"] = True
|
||||
except OSError:
|
||||
out["thumbnail"] = False
|
||||
# Convention thumbs dir — try all extensions; missing OK.
|
||||
# Convention thumbs dir — try both extensions thumbnailer writes
|
||||
# (.jpg for opaque, .png for alpha). `.webp` used to be in this
|
||||
# tuple but the thumbnailer never writes it (operator-flagged in
|
||||
# the 2026-06-02 audit) — keep the tuple aligned with what
|
||||
# actually lands on disk.
|
||||
if image.sha256:
|
||||
bucket = image.sha256[:3]
|
||||
for ext in ("jpg", "png", "webp"):
|
||||
for ext in ("jpg", "png"):
|
||||
try:
|
||||
(images_root / "thumbs" / bucket / f"{image.sha256}.{ext}").unlink(
|
||||
missing_ok=True,
|
||||
|
||||
@@ -34,6 +34,7 @@ from .gallery_dl import (
|
||||
SourceConfig,
|
||||
)
|
||||
from .importer import Importer
|
||||
from .platforms import auth_type_for
|
||||
from .patreon_resolver import resolve_campaign_id
|
||||
from .scheduler_service import set_platform_cooldown
|
||||
|
||||
@@ -194,7 +195,12 @@ class DownloadService:
|
||||
event_id = ev.id
|
||||
|
||||
artist = source.artist
|
||||
if source.platform in ("discord", "pixiv"):
|
||||
# Drive cookies-vs-token selection from the platform registry's
|
||||
# auth_type so a new 7th token-platform automatically picks the
|
||||
# right credential path. The hardcoded tuple here used to drift
|
||||
# out of sync with credential_service's auth_type_for(). Audit
|
||||
# 2026-06-02.
|
||||
if auth_type_for(source.platform) == "token":
|
||||
cookies_path = None
|
||||
auth_token = await self.cred_service.get_token(source.platform)
|
||||
else:
|
||||
|
||||
Reference in New Issue
Block a user