-
New blacklist store (dressup-store.js) — explicitly distinct from T32's automated face-blacklist model and T26's garment moderation, per M.11's own warning. isBlacklisted(targetType, targetId) is checked at every submission entry point (/api/dance/pick, both paid upload endpoints — rejected before any spend, matching M.11's "不进流水线、不扣积分") and filters GET /api/dance/wardrobe and pickNextDanceClip's random-fill pool (extending T36's expired-character filter to also drop blacklisted garments/characters/generated_videos) — records are never deleted, just excluded from future selection, same "记录保留" spirit as T36. Admin CRUD: GET/POST /api/admin/blacklist, DELETE /api/admin/blacklist/:id — creation attributed via adminActorUserId (T30), same null-over-the-legacy-ADMIN_PASSWORD-channel behavior as credit/adjust. Playback management (需求文档 6.5 节): POST /api/admin/dance/schedule/pin inserts an existing clip into the very next slot (factored T34's priorityInbox-insert logic into a shared insertClipNext() so both call sites move in lockstep); POST .../schedule/skip advances past whatever's currently playing; POST /api/admin/dance/pause freezes only the random-fill loop (paid_boost content still drains immediately even while paused — 需求文档 6.5 节 frames "暂停自动填充" as filler-specific, not a full stop). dance-admin-ops.test.js covers blacklist CRUD/attribution, entry-point rejection for both a blacklisted garment (pick) and a blacklisted user (upload), pin/skip changing the schedule, and pause/resume against a deliberately drained-to-stable-size schedule (comparing exact lengths — comparing clip ids/count directly was flaky since a small mock pool can legitimately re-pick the same clip after a skip). This completes dev-plan-5.md (T31-T39) — 需求文档 9 节's fifth and final planned phase. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011DUiYs6UjxDMkfvnjtsKFo