feat(search): 资源搜索结果附带规则判定

关联到本地作品的资源按作品收录版本的评估口径(硬条件 + 规则组链 + 阶梯,同自动获取的
evaluateCandidate)给出 ruleVerdict:命中第几档 / 不满足哪些维度 / 与库里当前版本相比高几档。
只调用 acquisition-organize 导出的 loadRuleCatalog、slotSpecWithRules、parsedOf、contextOf、
currentFacts;现有版本 pri 按 rulePriOfAsset 同口径在 search 模块里组合。一页最多判定 100 条、
20 个作品,收录版本 / 订阅 / 资源行 / 规则目录批量查一次;没关联作品或没有规则时为 null。

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Cxwgnn2pbzQ7rXv3rq7fei
This commit is contained in:
rootandClaude Opus 5.5 committed 2026-10-06 11:59:07 +08:00
1 parent fb6c76875c
commit a7d20ca370
4 files changed
+556 -1

No files matched your search

+31
View File
@@ -104,6 +104,35 @@ export const SearchReleaseInventory = InventoryEntry.extend({
});
export type SearchReleaseInventory = z.infer<typeof SearchReleaseInventory>;
/**
* 规则判定(只在关联到本地作品、且作品的收录版本配置了条件或规则组时给出):
* 按收录版本的评估口径(硬条件 + 规则组链 + 阶梯)判断这条资源,多个收录版本时取最好的一个。
*/
export const SearchRuleVerdict = z.object({
slotId: Id,
slotName: z.string(),
/** 作品共有几个收录版本参与判定;>1 时界面写出收录版本名 */
slotCount: z.number().int().positive(),
/** hit = 满足;miss = 不满足;unknown = 标题缺少判定需要的字段 */
outcome: z.enum(["hit", "miss", "unknown"]),
/** 命中的档位(1 起);没有分档或未命中为 null */
tier: z.number().int().positive().nullable(),
/** 档位名(规则组名·第 N 层 / 阶梯层名) */
tierName: z.string().nullable(),
/** 不满足(或缺字段)的维度:分辨率 / 来源 / 编码 / HDR / 字幕 / 体积 / 制作组 / 关键字 / 规则组…,去重 */
failed: z.array(z.string()),
/** 逐条说明(悬停提示) */
details: z.array(z.string()),
/**
* 与库里该收录版本当前版本相比:higher / same / lower;steps = 相差几档(按档位比较时给出)。
* 没有当前版本或无法比较时为 null。
*/
vsLibrary: z
.object({ cmp: z.enum(["higher", "same", "lower"]), steps: z.number().int().nonnegative().nullable() })
.nullable(),
});
export type SearchRuleVerdict = z.infer<typeof SearchRuleVerdict>;
export const SearchRelease = z.object({
/** `${siteId}:${siteReleaseId}`,前端列表 key */
key: z.string(),
@@ -140,6 +169,8 @@ export const SearchRelease = z.object({
entity: z.object({ id: Id, title: z.string(), year: z.number().int().nullable(), kind: MediaKind }).nullable(),
/** 库存叠加;candidateReasons 只保留针对本条资源的评估 */
inventory: SearchReleaseInventory.nullable(),
/** 与本地作品收录规则的关系;没关联作品或没有规则时为 null */
ruleVerdict: SearchRuleVerdict.nullable(),
});
export type SearchRelease = z.infer<typeof SearchRelease>;