Files
Jyotisha/frontend/src/lib/rectification-agentic/v9/case-status.ts
T
Jesse_ChenandCursor dd8f35f7ba fix(rectification): invite-first collect, holdout at 4 events, Skill 10.0.23 (BUG-646–648)
Stop domain-wheel collecting and age-band years in prompts. Ask until the training gate, then discriminate until convergence, then deliver a range plus a concrete follow-up. Reserve holdout only with four dated events.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-11 01:43:02 +08:00

93 lines
2.4 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.
*/
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<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";
export const RECTIFICATION_SKILL_VERSION = "10.0.23";