feat(db,contracts): W5-C subscription units migration 0025, contracts and mapping

- subscription: status pending (TMDB not ready: searchable/evaluable, not completable),
  last_searched_at / next_search_at
- content_unit (season): episode_total ledger with source / lock / timestamp
- acquisition_plan: unit_keys (Slot × unit reservation) and file_selection; drop the
  one-in-flight-per-slot unique index (checked under slot row lock per unit instead)
- new tables slot_deferral, slot_unit (per-unit quality ledger), subscription_history
- contracts: SubscriptionParams, SubscriptionHistory, SlotDeferral, SlotUnit, SubscriptionProgress,
  EpisodeTotalSet, CandidateEvaluation pri/trace/unitKeys and decision deferred;
  endpoints subscriptions.search/progress/setEpisodeTotal and subscription-history
- mapping: evaluation messages via describeViolation, pri/trace passthrough

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
rootandClaude Opus 5.5 committed 2026-09-27 23:33:56 +08:00
1 parent d162d464c4
commit 1dd460d359
9 files changed
+405 -34

No files matched your search

+7 -1
View File
@@ -90,6 +90,10 @@ const EXPECTED_TABLES = [
"browser_control_lease",
// W5-A 文件管理回收站(0024)
"trash_item",
// W5-C 订阅增强(0025)
"slot_deferral",
"slot_unit",
"subscription_history",
].sort();
/** 不走 entityTable() 的表:追加型/引擎自有表,没有 uuid id + created_at/updated_at 三件套 */
@@ -257,8 +261,10 @@ describe.skipIf(skip)("schema migrations (real PG)", () => {
idempotency_key: k,
});
await db.insertInto("acquisition_plan").values(plan("k1")).execute();
// 0025 起剧集 Slot 允许多个单元不相交的在途计划(服务端在 Slot 行锁内按单元校验);幂等键仍唯一
await db.insertInto("acquisition_plan").values(plan("k2")).execute();
await expect(db.insertInto("acquisition_plan").values(plan("k2")).execute()).rejects.toThrow(
/acquisition_plan_slot_active_key/,
/acquisition_plan_idempotency_key/,
);
});