Merge branch 'deai2'
Co-Authored-By: Claude Fable 5.1 <[email protected]> # Conflicts: # apps/server/src/modules/acquisition-organize/services/organize.ts # apps/web/app/routes/console/sites.$siteId.tsx
This commit is contained in:
commit
12bc4664b6
247 files changed
+2658
-2148
No files matched your search
@@ -158,7 +158,7 @@ describe.skipIf(!hasPg)("bootstrap + worker(真实 PG)", () => {
|
||||
decisionId,
|
||||
kind: "identity_unresolved",
|
||||
severity: "info",
|
||||
title: "待识别",
|
||||
title: "未识别",
|
||||
});
|
||||
});
|
||||
const deadline = Date.now() + 20_000;
|
||||
|
||||
@@ -93,7 +93,7 @@ const optionsScript = (goal: string): FakeScript => ({
|
||||
},
|
||||
});
|
||||
|
||||
// 审批:两个目标各用一个版本目标(拒绝与批准互不影响);ID 在 beforeAll 里填
|
||||
// 审批:两个目标各用一个收录版本(拒绝与批准互不影响);ID 在 beforeAll 里填
|
||||
const T: Record<"approve" | "reject", { slotId: string; releaseId: string }> = {
|
||||
approve: { slotId: ZERO, releaseId: ZERO },
|
||||
reject: { slotId: ZERO, releaseId: ZERO },
|
||||
|
||||
@@ -15,7 +15,7 @@ type Any = any;
|
||||
const hasPg = await pgAvailable();
|
||||
const HASH = "ab".repeat(20);
|
||||
const SURVEY = "盘点订阅、待处理与下载";
|
||||
const LOOP = (at: string) => `巡检库存(${at}):逐个作品查看版本目标`;
|
||||
const LOOP = (at: string) => `巡检库存(${at}):逐个作品查看收录版本`;
|
||||
|
||||
describe.skipIf(!hasPg)("E15 Agent 质量(fake 模型 + 真实能力)", () => {
|
||||
const scripts: FakeScript[] = [];
|
||||
|
||||
@@ -394,7 +394,7 @@ describe.skipIf(!hasPg)("Pi 上游(真实 PG)", () => {
|
||||
const r4 = await newRun(null);
|
||||
const d4 = await drive(env, h.ctx.capabilities, r4, new AbortController().signal);
|
||||
expect(d4).toMatchObject({ status: "failed" });
|
||||
expect(d4.message).toMatch(/未配置 Agent 上游/);
|
||||
expect(d4.message).toMatch(/未配置模型服务/);
|
||||
await setDefaultUpstream(h.ctx, fake.id);
|
||||
});
|
||||
});
|
||||
@@ -154,7 +154,7 @@ describe.skipIf(!hasPg)("规则组 API(真实 PG)", () => {
|
||||
expect(draft.body.data.items[0]).toMatchObject({ passed: true, pri: 100 });
|
||||
});
|
||||
|
||||
it("评估接入:版本目标引用规则组 → 硬排除拒绝、pri 进候选评估 trace;被引用的组不能删", async () => {
|
||||
it("评估接入:收录版本引用规则组 → 硬排除拒绝、pri 进候选评估 trace;被引用的组不能删", async () => {
|
||||
const e = await seedEntity(h.db, { kind: "movie", title: "规则片", year: 2024 });
|
||||
const slot = await seedSlot(h.db, { entityId: e });
|
||||
const g = await h.api("POST", "/rules", { name: "片源", ruleString: "4K > 1080P", hardExcludes: ["REMUX"] });
|
||||
@@ -285,7 +285,7 @@ describe.skipIf(!hasPg)("规则组 API(真实 PG)", () => {
|
||||
expect(plan.evaluation).toMatchObject({ pri: 100 });
|
||||
});
|
||||
|
||||
it("默认链:订阅默认组有层时对未引用规则组的版本目标生效;PUT /rules/defaults 校验类型", async () => {
|
||||
it("默认链:订阅默认组有层时对未引用规则组的收录版本生效;PUT /rules/defaults 校验类型", async () => {
|
||||
const defs = (await h.api("GET", "/rules/defaults")).body.data;
|
||||
const dflt = defs.acquisition[0];
|
||||
expect((await h.api("PUT", "/rules/defaults", { ...defs, acquisition: defs.upgrade })).status).toBe(400);
|
||||
|
||||
@@ -293,7 +293,7 @@ describe.skipIf(!up)("全局搜索", () => {
|
||||
expect(a.body.data.items[0]).toMatchObject({ siteId: sites.mteam, siteReleaseId: "912234" });
|
||||
});
|
||||
|
||||
it("库存叠加:已识别资源 → resolved + 订阅/版本目标缺口;未识别但标题命中唯一作品别名 → alias", async () => {
|
||||
it("库存叠加:已识别资源 → resolved + 订阅/收录版本缺口;未识别但标题命中唯一作品别名 → alias", async () => {
|
||||
const entity = (
|
||||
await db
|
||||
.insertInto("media_entity")
|
||||
@@ -346,7 +346,7 @@ describe.skipIf(!up)("全局搜索", () => {
|
||||
const mt = items.find((i) => i.siteReleaseId === "990001");
|
||||
expect(mt).toMatchObject({ mediaEntityId: entity, entityMatch: "alias", inventory: { state: "gap" } });
|
||||
|
||||
// 本地作品组:别名精确命中 + 版本目标状态摘要
|
||||
// 本地作品组:别名精确命中 + 收录版本状态摘要
|
||||
const all = await req("/search?q=沙丘2&scope=media");
|
||||
const local = all.body.data.media.local.items;
|
||||
expect(local[0]).toMatchObject({
|
||||
@@ -512,7 +512,7 @@ describe.skipIf(!up)("全局搜索", () => {
|
||||
expect(unresolved.status).toBe(412);
|
||||
expect(unresolved.body.error.code).toBe("precondition_failed");
|
||||
|
||||
// 已识别但作品没有版本目标 → submitted=false + no_slot
|
||||
// 已识别但作品没有收录版本 → submitted=false + no_slot
|
||||
const other = (
|
||||
await db
|
||||
.insertInto("media_entity")
|
||||
|
||||
@@ -167,7 +167,7 @@ describe.skipIf(!up)("两阶段搜索(SEARCH-2)", () => {
|
||||
sites.c = await addSite("hdhome", "家园", null, true);
|
||||
await db.updateTable("site").set({ enabled: false }).where("id", "=", sites.c).execute();
|
||||
|
||||
// 本地已建档的沙丘2(接受了 TMDB 693134),有一个未满足的版本目标
|
||||
// 本地已建档的沙丘2(接受了 TMDB 693134),有一个未满足的收录版本
|
||||
dune = (
|
||||
await db
|
||||
.insertInto("media_entity")
|
||||
|
||||
@@ -179,7 +179,7 @@ describe.skipIf(!pg)("DEC-1 惰性识别 + 待识别池", () => {
|
||||
expect(ds).toHaveLength(1);
|
||||
const d = ds[0]!;
|
||||
expect(d.severity).toBe("warning");
|
||||
expect(d.title).toMatch(/^来源「.+」的 3 条资源待确认身份:Twins$/);
|
||||
expect(d.title).toMatch(/^来源「.+」的 3 条资源没识别出作品:Twins$/);
|
||||
const ev = d.evidence as { count: number; releases: { sourceReleaseId: string }[] };
|
||||
expect(ev.count).toBe(3);
|
||||
expect(ev.releases.map((x) => x.sourceReleaseId).sort()).toEqual([...ids].sort());
|
||||
@@ -228,7 +228,7 @@ describe.skipIf(!pg)("DEC-1 惰性识别 + 待识别池", () => {
|
||||
expect(after.status).toBe("open");
|
||||
expect((after.evidence as { count: number }).count).toBe(1);
|
||||
expect(after.subject_id).toBe(pool[1]!.source_release_id);
|
||||
expect(after.title).toMatch(/^待确认身份:Nightfall\.1995\./);
|
||||
expect(after.title).toMatch(/^没识别出作品:Nightfall\.1995\./);
|
||||
// 最后一条忽略 → 事项关闭
|
||||
const last = await h.db
|
||||
.selectFrom("identity_candidate")
|
||||
@@ -336,7 +336,7 @@ describe.skipIf(!pg)("迁移 0047:存量 identity_unresolved 清理", () => {
|
||||
.values({
|
||||
kind: "identity_unresolved",
|
||||
severity: "info",
|
||||
title: `待识别:${title}`,
|
||||
title: `未识别:${title}`,
|
||||
subject_type: "source_release",
|
||||
subject_id: r.id,
|
||||
dedupe_key: `identity:${r.id}`,
|
||||
|
||||
@@ -26,7 +26,7 @@ import {
|
||||
presetConditions,
|
||||
} from "../../src/modules/acquisition-organize/services/subscriptions-params.ts";
|
||||
|
||||
// C1-A 订阅遗留收尾:包含 / 排除 → 订阅私有规则组(评估链纳入、随订阅删除)、MP 分辨率 / 来源 / 特效 → 版本目标、
|
||||
// C1-A 订阅遗留收尾:包含 / 排除 → 订阅私有规则组(评估链纳入、随订阅删除)、MP 分辨率 / 来源 / 特效 → 收录版本、
|
||||
// 保存路径经路径映射传给 qB、库根用于首次整理、下载器实例、重置进度、日历。
|
||||
|
||||
const hasPg = await pgAvailable();
|
||||
@@ -182,7 +182,7 @@ describe.skipIf(!hasPg)("C1-A 订阅遗留收尾(真实 PG + mock qB)", () => {
|
||||
expect(again[0]!.hard).toEqual({ exclude: ["CAM"] });
|
||||
});
|
||||
|
||||
it("评估链纳入私有组:包含没命中 / 排除命中都拒绝;命中包含建计划;与版本目标自己的包含取 AND", async () => {
|
||||
it("评估链纳入私有组:包含没命中 / 排除命中都拒绝;命中包含建计划;与收录版本自己的包含取 AND", async () => {
|
||||
const e = await seedEntity(db(), { kind: "movie", title: "Filter Film", year: 2024 });
|
||||
const c = await h.api("POST", "/subscriptions", {
|
||||
mediaEntityId: e,
|
||||
@@ -207,7 +207,7 @@ describe.skipIf(!hasPg)("C1-A 订阅遗留收尾(真实 PG + mock qB)", () => {
|
||||
const ok = await release(e, "Filter.Film.2024.1080p.WEB-DL.CHS.x264-GRP");
|
||||
const r3 = await evaluateAcquisition(h.d, { sourceReleaseId: ok });
|
||||
expect(r3.plans, JSON.stringify(r3)).toHaveLength(1);
|
||||
// 版本目标自己也要求 "GRP2":与私有组的 CHS 取 AND
|
||||
// 收录版本自己也要求 "GRP2":与私有组的 CHS 取 AND
|
||||
await db().updateTable("acquisition_plan").set({ status: "cancelled" }).where("id", "=", r3.plans[0]!).execute();
|
||||
await db()
|
||||
.updateTable("acquisition_slot")
|
||||
@@ -223,7 +223,7 @@ describe.skipIf(!hasPg)("C1-A 订阅遗留收尾(真实 PG + mock qB)", () => {
|
||||
expect((await evaluateAcquisition(h.d, { sourceReleaseId: both })).plans).toHaveLength(1);
|
||||
});
|
||||
|
||||
it("MP 分辨率 / 来源 / 特效:新建时建默认版本目标承载预设;改预设覆盖同一字段,手改过的字段保留;无法识别 400", async () => {
|
||||
it("MP 分辨率 / 来源 / 特效:新建时建默认收录版本承载预设;改预设覆盖同一字段,手改过的字段保留;无法识别 400", async () => {
|
||||
const e = await seedEntity(db(), { kind: "series", title: "预设剧", year: 2025 });
|
||||
const bad = await h.api("POST", "/subscriptions", {
|
||||
mediaEntityId: e,
|
||||
@@ -461,7 +461,7 @@ describe.skipIf(!hasPg)("C1-A 订阅遗留收尾(真实 PG + mock qB)", () => {
|
||||
});
|
||||
expect(c.status, JSON.stringify(c.body)).toBe(201);
|
||||
const subId = c.body.data.id as string;
|
||||
// E01 已入库(单版本目标:作品下资产都算)
|
||||
// E01 已入库(单收录版本:作品下资产都算)
|
||||
const a = await db()
|
||||
.insertInto("media_asset")
|
||||
.values({
|
||||
|
||||
@@ -264,7 +264,7 @@ describe.skipIf(!hasPg)("订阅重做(真实 PG)", () => {
|
||||
expect((await h.api("GET", "/subscriptions/00000000-0000-0000-0000-000000000000/coverage")).status).toBe(404);
|
||||
});
|
||||
|
||||
it("覆盖矩阵:集范围裁剪;总集数未知列到已见最高集并标 suspected;电影按内容版本 × 版本目标", async () => {
|
||||
it("覆盖矩阵:集范围裁剪;总集数未知列到已见最高集并标 suspected;电影按内容版本 × 收录版本", async () => {
|
||||
const e = await seedEntity(db(), { kind: "series", title: "范围剧", year: 2025 });
|
||||
await season(e, 1, null);
|
||||
const e3 = await episode(e, 1, 3);
|
||||
@@ -325,7 +325,7 @@ describe.skipIf(!hasPg)("订阅重做(真实 PG)", () => {
|
||||
// 暂停
|
||||
const e4 = await seedEntity(db(), { kind: "series", title: `${tag}丁`, year: 2022 });
|
||||
const s4 = await sub(e4, { status: "paused" });
|
||||
// 已完成(电影:唯一版本目标已入库)
|
||||
// 已完成(电影:唯一收录版本已入库)
|
||||
const e5 = await seedEntity(db(), { kind: "movie", title: `${tag}戊`, year: 2021 });
|
||||
const a5 = await asset(e5);
|
||||
const s5 = await sub(e5, { kind: "movie", mode: "once" });
|
||||
@@ -584,7 +584,7 @@ describe.skipIf(!hasPg)("订阅重做(真实 PG)", () => {
|
||||
expect(r.status, JSON.stringify(bad)).toBe(400);
|
||||
}
|
||||
|
||||
// PATCH:autoFill 布尔 → on/off;best_version → 版本目标升级策略
|
||||
// PATCH:autoFill 布尔 → on/off;best_version → 收录版本升级策略
|
||||
const sid = c.body.data.id;
|
||||
const sl = await slot(e, sid, "main");
|
||||
const u = await h.api("PATCH", `/subscriptions/${sid}`, {
|
||||
@@ -611,7 +611,7 @@ describe.skipIf(!hasPg)("订阅重做(真实 PG)", () => {
|
||||
).toEqual({ enabled: false, mode: "full_pack" });
|
||||
});
|
||||
|
||||
it("暂停 / 恢复 / 重新订阅 / 批量 / 版本目标排序", async () => {
|
||||
it("暂停 / 恢复 / 重新订阅 / 批量 / 收录版本排序", async () => {
|
||||
const e = await seedEntity(db(), { kind: "movie", title: "动作片", year: 2024 });
|
||||
const s = await sub(e, { kind: "movie", mode: "once" });
|
||||
const a = await slot(e, s, "A", { position: 0 });
|
||||
|
||||
@@ -211,7 +211,7 @@ describe.skipIf(!hasPg)("CACHE-2 存储(真实 PG)", () => {
|
||||
(${done}, 1, 'run_started', ${old}), (${done}, 2, 'run_started', ${now}), (${live}, 1, 'run_started', ${old})`.execute(
|
||||
h.db,
|
||||
);
|
||||
expect(await job("agent_event")(now)).toMatch(/Agent 事件 1、/);
|
||||
expect(await job("agent_event")(now)).toMatch(/智能体事件 1、/);
|
||||
expect(await count(sql<{ n: number }>`select count(*)::int as n from agent_run_event`)).toBe(2);
|
||||
|
||||
await sql`delete from audit_event`.execute(h.db);
|
||||
@@ -250,7 +250,7 @@ describe.skipIf(!hasPg)("CACHE-2 存储(真实 PG)", () => {
|
||||
await cand("r1", "unmatched", 31);
|
||||
await cand("r2", "unmatched", 29);
|
||||
await cand("r3", "ambiguous", 31);
|
||||
expect(await job("identity_pool")(now)).toBe("归档 1 条待识别条目");
|
||||
expect(await job("identity_pool")(now)).toBe("归档 1 条未识别条目");
|
||||
const st = await sql<{ t: string; s: string }>`select sr.title as t, c.status as s from identity_candidate c
|
||||
join source_release sr on sr.id = c.source_release_id order by sr.title`.execute(h.db);
|
||||
expect(st.rows).toEqual([
|
||||
|
||||
Reference in new issue
Block a user