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:
1 parent
d162d464c4
commit
1dd460d359
9 files changed
+405
-34
No files matched your search
@@ -4,14 +4,15 @@ import type {
|
||||
SlotStatus as ContractSlotStatus,
|
||||
JsonObject,
|
||||
} from "@umt/contracts";
|
||||
import type {
|
||||
SlotStatus as DomainSlotStatus,
|
||||
SlotCompletionSpec,
|
||||
SlotEvaluation,
|
||||
SlotHardConditions,
|
||||
SlotSoftPreferences,
|
||||
SlotSpec,
|
||||
SlotUpgradePolicy,
|
||||
import {
|
||||
type SlotStatus as DomainSlotStatus,
|
||||
describeViolation,
|
||||
type SlotCompletionSpec,
|
||||
type SlotEvaluation,
|
||||
type SlotHardConditions,
|
||||
type SlotSoftPreferences,
|
||||
type SlotSpec,
|
||||
type SlotUpgradePolicy,
|
||||
} from "@umt/domain";
|
||||
|
||||
// Slot:状态两侧取值相同(REQ §6.1),映射表只为让任一侧增删值时编译/测试失败。
|
||||
@@ -92,26 +93,34 @@ export interface ContractSlotEvaluation {
|
||||
/** 与 DownloadPlanOutput.rejected 同形:硬条件不满足 / 字段未知的原因 */
|
||||
rejected: { code: string; message: string }[];
|
||||
reasons: string[];
|
||||
/** 优先级阶梯 pri(未配置阶梯为 100;拒绝/未知为 null) */
|
||||
pri: number | null;
|
||||
/** 可读说明(逐条违规 + 逐层阶梯) */
|
||||
trace: string[];
|
||||
}
|
||||
|
||||
/** domain 评估结果 → 能力输出/决策记录用的扁平表示 */
|
||||
export function toContractSlotEvaluation(ev: SlotEvaluation): ContractSlotEvaluation {
|
||||
const trace = [...(ev.trace ?? [])];
|
||||
switch (ev.decision) {
|
||||
case "accept":
|
||||
case "upgrade":
|
||||
return { decision: ev.decision, acceptable: true, rejected: [], reasons: [...ev.reasons] };
|
||||
return {
|
||||
decision: ev.decision,
|
||||
acceptable: true,
|
||||
rejected: [],
|
||||
reasons: [...ev.reasons],
|
||||
pri: ev.pri ?? null,
|
||||
trace,
|
||||
};
|
||||
case "reject":
|
||||
return {
|
||||
decision: "reject",
|
||||
acceptable: false,
|
||||
rejected: ev.violations.map((v) => ({
|
||||
code: `${v.field}.${v.code}`,
|
||||
message:
|
||||
v.expected === undefined
|
||||
? `${v.field}: ${v.code}`
|
||||
: `${v.field}: ${v.code}(期望 ${JSON.stringify(v.expected)},实际 ${JSON.stringify(v.actual ?? null)})`,
|
||||
})),
|
||||
rejected: ev.violations.map((v) => ({ code: `${v.field}.${v.code}`, message: describeViolation(v) })),
|
||||
reasons: [],
|
||||
pri: ev.ladder?.pri ?? null,
|
||||
trace,
|
||||
};
|
||||
case "unknown_field":
|
||||
return {
|
||||
@@ -119,6 +128,8 @@ export function toContractSlotEvaluation(ev: SlotEvaluation): ContractSlotEvalua
|
||||
acceptable: false,
|
||||
rejected: ev.missing.map((m) => ({ code: `unknown_field.${m}`, message: `字段未知,需要补充: ${m}` })),
|
||||
reasons: [],
|
||||
pri: null,
|
||||
trace,
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user