报告创建请求、校正入口和同名类型改从 contracts 推导;同义的对象判断与 sha256 改走共享函数。调用处用 import 别名保留原名,使 diff 低于 1500 行。行为、哈希和状态字符串不变。 Co-Authored-By: Grok (agent loop)
78 lines
2.7 KiB
TypeScript
78 lines
2.7 KiB
TypeScript
/**
|
||
* V9 rectification Case state machine contracts.
|
||
*
|
||
* The server owns the authoritative Case status. The browser and the agent
|
||
* never derive status from message counts, candidate existence or session
|
||
* ordering.
|
||
*/
|
||
|
||
import {
|
||
RECTIFICATION_CASE_STATUSES,
|
||
RESUMABLE_CASE_STATUSES,
|
||
TERMINAL_CASE_STATUSES,
|
||
} from "@/lib/contracts/rectification-entry";
|
||
import type { RectificationCaseStatus } from "@/lib/contracts/rectification-entry";
|
||
|
||
export {
|
||
RECTIFICATION_CASE_STATUSES,
|
||
RESUMABLE_CASE_STATUSES,
|
||
TERMINAL_CASE_STATUSES,
|
||
};
|
||
export type { RectificationCaseStatus };
|
||
|
||
const RESUMABLE_SET = new Set<string>(RESUMABLE_CASE_STATUSES);
|
||
const TERMINAL_SET = new Set<string>(TERMINAL_CASE_STATUSES);
|
||
|
||
export function isRectificationCaseStatus(
|
||
value: unknown,
|
||
): value is RectificationCaseStatus {
|
||
return (
|
||
typeof value === "string" &&
|
||
(RESUMABLE_SET.has(value) || TERMINAL_SET.has(value))
|
||
);
|
||
}
|
||
|
||
export function isResumableStatus(
|
||
status: RectificationCaseStatus,
|
||
): boolean {
|
||
return RESUMABLE_SET.has(status);
|
||
}
|
||
|
||
export function isTerminalStatus(status: RectificationCaseStatus): boolean {
|
||
return TERMINAL_SET.has(status);
|
||
}
|
||
|
||
/**
|
||
* Legal terminal transitions. A resumable case may move to any terminal
|
||
* status; terminal statuses are immutable.
|
||
*/
|
||
export function canTransitToTerminal(
|
||
from: RectificationCaseStatus,
|
||
to: RectificationCaseStatus,
|
||
): boolean {
|
||
if (isTerminalStatus(from)) return false;
|
||
return isTerminalStatus(to);
|
||
}
|
||
|
||
/** statuses that reject evidence/turn writes. Terminal cases are read-only. */
|
||
export function evidenceWritesAllowed(
|
||
status: RectificationCaseStatus,
|
||
): boolean {
|
||
return isResumableStatus(status);
|
||
}
|
||
|
||
/**
|
||
* The one-resumable-case-per-user invariant, mirrored from the database
|
||
* partial unique index. The database is the enforcement point; this is the
|
||
* contract the service layer relies on.
|
||
*/
|
||
export const MAX_RESUMABLE_CASES_PER_USER = 1;
|
||
|
||
export const RECTIFICATION_SKILL_NAME = "jyotish-birth-time-rectification";
|
||
// 原值: "10.0.28" / 新值: "10.0.29" / 原因: 年月阶段改口述并禁止追问本人
|
||
// 原值: "10.0.29" / 新值: "10.0.30" / 原因: D2 出卡句与 D4 卡上百分比规则写进 Skill(2026-09-26)
|
||
// 原值: "10.0.30" / 新值: "10.0.31" / 原因: 开场改大白话、题干带例子和示例回答写进 Skill OpeningPolicy(BUG-1049,2026-09-26)
|
||
// 原值: "10.0.31" / 新值: "10.0.32" / 原因: 训练门开后只问点选卡、交付正文去吻合率写进 Skill(BUG-1084/1085,2026-09-29)
|
||
// 原值: "10.0.32" / 新值: "10.0.33" / 原因: 持久opt-in盘型交付,nullable历史保持旧身份/方法(BUG-1115~1117)
|
||
export const RECTIFICATION_SKILL_VERSION = "10.0.33";
|