Files
UHD_Media_Tool/docs/runbook/identity.md
T
rootandClaude Opus 5.5 94fd48bff2 feat(identity): lazy TMDB lookup and bounded identity pool (DEC-1)
RSS/list releases that match no subscription or local work no longer hit
TMDB or open a pending item; they go to the identity pool as `unmatched`.
TMDB is queried only on a local alias hit, a published new-title rule whose
prefilter passes, manual/Agent retry, search results, or when the new
setting identity.eagerTmdbLookup (default off) is on. Mirrors MoviePilot:
torrents are recognised only when matched to a subscription or searched,
and recognition failures are logged, not alerted.

- Pending items only for related releases (ambiguous after lookup, or
  related to a local work but unresolved); same source + normalized title
  merge into one decision ("来源「X」的 N 条资源待识别"), resolve/dismiss
  applies to the whole group, members detach as they get resolved.
- Pool governance: unmatched reviews capped (daily, 3x), title_alias
  insert trigger wakes similar entries, stale unmatched entries archived
  after identity.poolArchiveDays (30); review idempotency keys include the
  due time.
- Migration 0047_identity_pool: reason/outcome `unmatched`,
  identity_candidate.normalized_title (+trgm index), wake trigger, and
  cleanup of open identity_unresolved items with no related work
  (dismissed, resolution=moved_to_pool).
- Inbox: group by type + work/source with collapse, hide info-only items
  by default (minSeverity=warning), badge counts warning+ only; pool sheet
  gets manual TMDB/local-work assign and dismiss; settings card for the
  new identity settings.
- Runbook docs/runbook/identity.md.

Requires rebuild/restart (migration runs on start).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-29 15:05:39 +08:00

6.0 KiB

资源识别与待识别池运行手册(DEC-1)

新观察到的资源(RSS、站点列表快照、搜索结果)先进待识别池,只在有理由时才查 TMDB。只有和订阅或本地作品相关、 又需要你决定的资源才进待处理。对照 MoviePilot:RSS / 站点资源只在匹配订阅或用户搜索时才识别,识别失败只写日志、不告警 (app/chain/subscribe/match.py _prepare_match_torrents:未识别的种子最多重试 3 次,之后跳过)。

需求依据:REQ §4.2–4.3(观察不等于事实)、§6.3(新作品收录 / 追更补缺 / 升级都由规则触发)、§7.5(待识别池可检索、 不污染正式库、有界复查、不留死数据)、§13(待处理按作品与问题类型合并)。

识别流程(resolveObservation)

  1. 解析标题(release-parser),本地召回:显式外部 ID、title_alias 精确 / pg_trgm ≥ 0.45(本地作品 = 订阅、追踪、已登记的作品)。

  2. 判断是否查 TMDB(lookup,记在 source_release.resolution_evidence.lookup 和池条目 query.lookup):

    lookup 条件
    manual 任务输入 trigger: "manual":池里点「重新识别」、Agent / 能力 identity.resolve
    search 任务输入 trigger: "search":搜索结果
    tracked_alias 本地召回有候选(标题命中订阅 / 本地作品的别名)
    previously_looked_up 周期复查,且这条池条目以前查过 TMDB(旧数据、手动、规则触发)
    eager 设置 identity.eagerTmdbLookup = true
    new_title_rule 有已发布、开启 newTitle 且有有效持续授权的获取策略,资源类型在规则的 mediaKinds 内,标题年份(若有)不早于窗口能覆盖的年份

    都不满足:只进池,reason = unmatched,不查 TMDB,不开待处理。

  3. 查了 TMDB 的,走原来的 domain.resolveIdentity:auto 建档 / 关联并发 release.resolved;否则进池。

任务输入 trigger 缺省:force 为 true 视为 review(池复查),否则 observed。 搜索模块想让搜索结果直接识别,入队 resolveObservation 时传 trigger: "search"(目前搜索结果经 release.observed 进来, 按 observed 处理;命中订阅别名的照样会查)。

待处理只收相关的

结果 开事项?
unmatched 否
ambiguous / proposed(查过 TMDB,有候选) 是,identity_ambiguous,级别 warning
no_match / 复查已停的 lookup_failed 只有本地召回有候选(与本地作品相关)时开 identity_unresolved,级别 warning

合并:dedupeKey identity-group:<siteId>:<归一化标题>,同来源同标题的资源并成一条。成员 = identity_candidate.decision_id 指向该事项且仍 pending 的条目。标题 1 条时写资源原标题,多条时写「来源「X」的 N 条资源待识别 / 待确认身份:<标题>」, evidence.releases 列前 50 条,evidence.count 为总数。

  • 处理(选候选 / 手动 TMDB ID / 选本地作品):先处理代表资源(subject),再把确定的作品套到组内其它资源(都加人工锁)。
  • 忽略:组内每条池条目都 dismissed。
  • 组内某条被单独识别 / 指定 / 忽略:从组里摘除,代表资源和候选选项换成剩下的最近一条;组空了才关事项。
  • 旧式单条事项(identity:<releaseId>)在该资源下次复查时并入合并事项并关闭。

收件箱:顶栏角标和待处理页缺省只算 warning 及以上(minSeverity=warning),"仅信息"类在待处理页「级别 → 含仅信息」里看。 待处理页按问题类型 + 作品 / 来源分组,前 3 组展开,其余折叠;合并事项卡片可展开组内资源。

池的治理

  • 复查有上限:unmatched 每天一次本地召回,最多 3 次;查过 TMDB 的按原退避(无结果 1h 起、查询失败 15min 起,翻倍到 7 天,最多 8 次)。
  • 新证据即重试:title_alias 插入触发器 title_alias_wake_identity_pool,把归一化标题相同或相似度 ≥ 0.45 的 unmatched / no_match 池条目的 next_review_at 设为现在。建档、手动加别名、合并作品都会触发。
  • 过期归档:identity.poolArchiveDays(缺省 30)天没有新尝试的 unmatched 条目改为 archived,在池复查定时任务里做, 每进程每小时最多一次。归档不删资源,仍可按状态筛出、手动指定。
  • 检索:媒体概览 → 待识别,按原始标题 / 解析标题检索,原因筛「未命中订阅」即 unmatched。条目详情里可「重新识别」 (手动触发,会查 TMDB)、手动指定 TMDB ID / 本地作品(复用 /identity-pool/{id}/assign,加人工锁)或忽略。

设置

设置 → 元数据 → 资源识别:

  • identity.eagerTmdbLookup(缺省关):打开即旧行为,每条新资源都查 TMDB。每条约 1–2 次搜索 + 命中时 1 次详情 (识别缓存命中为 0);每小时 100 条的 RSS 约每天 2400–7200 次请求,站点独有的短剧 / 综艺多半查不到。 打开后无结果的资源仍只进池,不开事项。
  • identity.poolArchiveDays(缺省 30)。

存量清理(迁移 0047_identity_pool)

未关闭的 identity_unresolved 事项中,资源未关联作品、池里没有候选、归一化标题也不命中任何本地别名的: 事项改 dismissed,resolution = {"resolution":"moved_to_pool","by":"migration:0047_identity_pool"}; 池条目改 reason = unmatched、清 decision_id、停自动复查。相关的保留原样,下次复查时并入合并事项。

需要重建镜像 / 重启 api + worker 才生效(迁移随启动执行)。

排查

-- 池分布
select reason, status, count(*) from identity_candidate group by 1, 2 order by 3 desc;
-- 某条资源为什么没查 TMDB
select resolution_status, resolution_evidence->>'lookup' as lookup, resolution_evidence->>'detail' as detail
  from source_release where id = '<id>';
-- 某个合并事项的成员
select p.source_release_id, r.title, p.reason from identity_candidate p join source_release r on r.id = p.source_release_id
 where p.decision_id = '<decisionId>' and p.status = 'pending';
-- 迁移搬走的事项
select count(*) from decision where resolution->>'resolution' = 'moved_to_pool';