feat(identity): open identity_unresolved decisions for resources with no candidates

no_match resources (and lookup failures after auto-review gives up) now
open a decision in the inbox with options to set a TMDB ID, pick a local
work, or dismiss; ambiguous decisions get the same manual options.
Resolve accepts identity {tmdb | mediaEntityId} and assigns with a manual
lock. The inbox option dialog collects the TMDB type/ID or searches local
works; the identity pool links each pending item to its inbox filter.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
rootandClaude Opus 5.5 committed 2026-09-28 13:44:57 +08:00
1 parent a0b0a64246
commit fb7727cf66
14 files changed
+280 -37

No files matched your search

+20
View File
@@ -142,6 +142,8 @@ export const DecisionKind = z.enum([
"metadata_conflict",
"source_unreachable",
"other",
/** 待识别资源没有可选候选(no_match / 复查耗尽的查询失败):手动指定 TMDB id、选本地作品或忽略 */
"identity_unresolved",
]);
export type DecisionKind = z.infer<typeof DecisionKind>;
export const DecisionStatus = z.enum(["open", "investigating", "awaiting_user", "resolved", "dismissed", "expired"]);
@@ -220,6 +222,24 @@ export const DecisionResolveInput = z.object({
optionKey: z.string().min(1).optional(),
dismiss: z.boolean().optional(),
note: z.string().max(2000).optional(),
/**
* 身份类事项的手动指定(选项 input.requires 标明需要哪一项):
* requires=tmdb → tmdb {type, id};requires=mediaEntityId → mediaEntityId
*/
identity: z
.object({
mediaEntityId: Id.optional(),
tmdb: z
.object({
type: z.enum(["movie", "tv"]),
id: z
.string()
.trim()
.regex(/^\d{1,10}$/),
})
.optional(),
})
.optional(),
});
export type DecisionResolveInput = z.infer<typeof DecisionResolveInput>;