fix(rules): recompute current asset pri under referenced rule groups for upgrades

Slot units and movie assets recorded pri from slot soft.tiers only, so a rule
group ladder would either never upgrade (pri 100) or re-upgrade forever. The
current pri is now re-evaluated from the asset's source release with the same
chain (fallback: pri recorded in the plan evaluation).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
rootandClaude Opus 5.5 committed 2026-09-28 15:11:43 +08:00
1 parent d28686ed02
commit 36027a4820
2 files changed
+118 -3

No files matched your search

@@ -225,6 +225,66 @@ describe.skipIf(!hasPg)("规则组 API(真实 PG)", () => {
expect((await h.api("DELETE", `/rules/${g.body.data.id}`)).status).toBe(409);
});
it("洗版:现有资产按规则组重算 pri,只接受 pri 严格更高的候选", async () => {
const e = await seedEntity(h.db, { kind: "movie", title: "洗版片", year: 2024 });
const slot = await seedSlot(h.db, { entityId: e, upgrade: { enabled: true } });
const g = await h.api("POST", "/rules", { name: "洗版阶梯", ruleString: "REMUX > WEBDL & CNSUB > WEBDL" });
await h.api("PATCH", `/acquisition-slots/${slot}`, { expectedRevision: 1, ruleGroupIds: [g.body.data.id] });
const tOld = makeTorrent({ name: "Up.2024.1080p.WEB-DL.mkv", length: 1000, pieceSeed: 61 });
const oldRel = await seedRelease(h.db, {
siteId: base.siteId,
entityId: e,
title: "Up.2024.1080p.WEB-DL.H264-OLD",
size: 1000,
hash: tOld.hash,
});
await h.db.updateTable("source_release").set({ subtitle: "中字" }).where("id", "=", oldRel).execute();
const asset = await h.db
.insertInto("media_asset")
.values({
media_entity_id: e,
kind: "video",
size_bytes: 1000,
source_release_id: oldRel,
media_info: JSON.stringify({ _umt: { quality: { resolution: "1080p", source: "WEB-DL" } } }),
})
.returning("id")
.executeTakeFirstOrThrow();
await h.db
.updateTable("acquisition_slot")
.set({ status: "satisfied", current_asset_id: asset.id })
.where("id", "=", slot)
.execute();
// 现有资产 = WEB-DL + 中字 → pri 99;同档 WEB-DL 中字不换,REMUX(pri 100)升级
const tSame = makeTorrent({ name: "Up.2024.1080p.WEB-DL.2.mkv", length: 1000, pieceSeed: 62 });
const same = await seedRelease(h.db, {
siteId: base.siteId,
entityId: e,
title: "Up.2024.1080p.WEB-DL.H264-NEW",
size: 1000,
hash: tSame.hash,
});
await h.db.updateTable("source_release").set({ subtitle: "中字" }).where("id", "=", same).execute();
expect((await evaluateAcquisition(h.d, { sourceReleaseId: same })).plans).toHaveLength(0);
const tBetter = makeTorrent({ name: "Up.2024.1080p.REMUX.mkv", length: 1000, pieceSeed: 63 });
const better = await seedRelease(h.db, {
siteId: base.siteId,
entityId: e,
title: "Up.2024.1080p.BluRay.REMUX.AVC-GRP",
size: 1000,
hash: tBetter.hash,
});
const ev = await evaluateAcquisition(h.d, { sourceReleaseId: better });
expect(ev.plans).toHaveLength(1);
const plan = await h.db
.selectFrom("acquisition_plan")
.select(["purpose", "evaluation"])
.where("id", "=", ev.plans[0]!)
.executeTakeFirstOrThrow();
expect(plan.purpose).toBe("upgrade");
expect(plan.evaluation).toMatchObject({ pri: 100 });
});
it("默认链:订阅默认组有层时对未引用规则组的版本目标生效;PUT /rules/defaults 校验类型", async () => {
const defs = (await h.api("GET", "/rules/defaults")).body.data;
const dflt = defs.acquisition[0];