/** * 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. */ export const RECTIFICATION_CASE_STATUSES = [ "draft", "collecting_evidence", "candidate_ready", "candidate_accepted", "needs_rebaseline", "paused", "confirmed", "closed", "abandoned", "superseded", ] as const; export type RectificationCaseStatus = (typeof RECTIFICATION_CASE_STATUSES)[number]; /** Statuses that may be resumed by the user. */ export const RESUMABLE_CASE_STATUSES: readonly RectificationCaseStatus[] = [ "draft", "collecting_evidence", "candidate_ready", "candidate_accepted", "needs_rebaseline", "paused", ]; /** Statuses that only allow read-only history access. */ export const TERMINAL_CASE_STATUSES: readonly RectificationCaseStatus[] = [ "confirmed", "closed", "abandoned", "superseded", ]; const RESUMABLE_SET = new Set(RESUMABLE_CASE_STATUSES); const TERMINAL_SET = new Set(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"; export const RECTIFICATION_SKILL_VERSION = "10.0.23";