Files
Jyotisha/frontend/tests/rectification-v9-test-support.ts
T
Jesse_Chen 814c924e4a
Independent Staging Quality Gate / validate (push) Successful in 9m20s
Independent Staging Quality Gate / publish (push) Successful in 6m51s
fix(rectification): exhaustion exit, explain layer, range reading, unknown-time scan (BUG-565–568)
Keep askable cards after exhaustion, explain each probe, read the adopted credible range in reports and chat, and compare declared periods before the minute grid when the clock is unknown.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-07 09:10:37 +08:00

290 lines
10 KiB
TypeScript

import type { RectificationRpcClient } from "../src/lib/rectification-agentic/v9/tool-service.ts";
export type FakeRpcHandler = (
fn: string,
args: Record<string, unknown>,
) => unknown | Promise<unknown>;
export type FakeAccounting = {
calls: Array<{ fn: string; args: Record<string, unknown> }>;
client: RectificationRpcClient;
};
export function fakeAccounting(
handlers: Partial<Record<string, FakeRpcHandler>>,
options: { fallback?: FakeRpcHandler } = {},
): FakeAccounting {
const calls: Array<{ fn: string; args: Record<string, unknown> }> = [];
const client: RectificationRpcClient = {
rpc(fn, args) {
calls.push({ fn, args });
const handler = handlers[fn] ?? options.fallback;
if (!handler) {
return Promise.resolve({
data: null,
error: { message: `unexpected rpc ${fn}` },
});
}
return Promise.resolve()
.then(() => handler(fn, args))
.then(
(data) => ({ data, error: null }),
(error: unknown) => ({
data: null,
error: { message: error instanceof Error ? error.message : String(error) },
}),
);
},
};
return { calls, client };
}
export const CASE_ID = "11111111-1111-4111-8111-111111111111";
export const SESSION_ID = "22222222-2222-4222-8222-222222222222";
export const TURN_ID = "33333333-3333-4333-8333-333333333333";
export const ATTEMPT_ID = "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa";
export const FOCUS_ID = "abababab-abab-4bab-8bab-abababababab";
export const EVIDENCE_ID = "44444444-4444-4444-8444-444444444444";
export const RESULT_ID = "55555555-5555-4555-8555-555555555555";
export const CANDIDATE_ID = "88888888-8888-4888-8888-888888888881";
export const SECOND_CANDIDATE_ID = "88888888-8888-4888-8888-888888888882";
export const USER_ID = "66666666-6666-4666-8666-666666666666";
export const SOURCE_TURN_ID = "77777777-7777-4777-8777-777777777777";
export const RECTIFICATION_SKILL_SHA256 = "5acb3103e80993ea611b93d2c1746e70b74aff8f8636bcffc80a837b954b470d";
export const RECTIFICATION_SKILL_SOURCE_COMMIT = "0fd111d16b45796086a6c1d0945dbd3de6755d8a";
export const OPEN_ENGINE_CAPABILITY_CEILING = {
acceptanceAllowed: true,
selectionAllowed: true,
proposeAllowed: true,
confirmationAllowed: true,
} as const;
export const CANDIDATE_RANGE = { start_time: "04:50", end_time: "05:10" };
export function dossierFixture(overrides: {
status?: string;
turnCount?: number;
evidenceCount?: number;
latestResult?: unknown;
evidence?: unknown[];
turns?: unknown[];
candidateRange?: { start_time: string; end_time: string } | null;
stage?: string;
blockScan?: unknown;
acceptedTime?: string | null;
conversationSummary?: unknown;
} = {}) {
return {
case: {
case_id: CASE_ID,
session_id: SESSION_ID,
status: overrides.status ?? "collecting_evidence",
skill_name: "jyotish-birth-time-rectification",
skill_version: "9.0.0",
candidate_range: overrides.candidateRange ?? CANDIDATE_RANGE,
stage: overrides.stage ?? "minute",
block_scan: overrides.blockScan ?? null,
accepted_time: overrides.acceptedTime ?? null,
confirmed_time: null,
completed_at: null,
closed_reason: null,
last_activity_at: "2026-08-12T10:00:00.000Z",
evidence_count: overrides.evidenceCount ?? 1,
turn_count: overrides.turnCount ?? 2,
},
turns: overrides.turns ?? [
{
id: TURN_ID,
role: "user",
text: "2016年9月离开家去北京开始工作",
status: "completed",
created_at: "2026-08-12T10:00:00.000Z",
completed_at: "2026-08-12T10:00:05.000Z",
},
],
evidence: overrides.evidence ?? [
{
id: EVIDENCE_ID,
source_turn_id: TURN_ID,
subject: "self",
event_kind: "career_entry",
domain: "career",
occurred_from: "2016-09-01",
occurred_to: null,
date_precision: "month",
summary: "2016年9月离家去北京开始工作",
status: "confirmed",
supersedes_evidence_id: null,
created_at: "2026-08-12T10:00:06.000Z",
},
],
conversation_summary: overrides.conversationSummary ?? {
confirmed_evidence_summary: [],
pending_revisions: [],
active_focus: null,
declined_skipped_topics: [],
candidate_divergence_summary: null,
missing_evidence_categories: [],
last_result_policy: null,
summary_version: 1,
updated_at: "2026-08-12T10:00:06.000Z",
},
latest_result: overrides.latestResult ?? null,
};
}
export function conversationSummaryFixture(overrides: {
activeFocus?: unknown;
declinedSkippedTopics?: unknown[];
pendingRevisions?: unknown[];
} = {}) {
return {
confirmed_evidence_summary: [],
pending_revisions: overrides.pendingRevisions ?? [],
active_focus: overrides.activeFocus ?? null,
declined_skipped_topics: overrides.declinedSkippedTopics ?? [],
candidate_divergence_summary: null,
missing_evidence_categories: [],
last_result_policy: null,
summary_version: 1,
updated_at: "2026-08-12T10:00:06.000Z",
};
}
export function activeFocusFixture(overrides: {
id?: string;
questionId?: string;
targetEvidenceId?: string | null;
intent?: string;
targetDomain?: string | null;
targetKind?: string | null;
expectedAnswerSchema?: Record<string, unknown>;
askedTurnId?: string | null;
answerOption?: "A" | "B" | "C" | "D" | "stop" | null;
} = {}) {
return {
id: overrides.id ?? FOCUS_ID,
case_id: CASE_ID,
question_id: overrides.questionId ?? "question-1",
intent: overrides.intent ?? "confirm_revision",
target_evidence_id: overrides.targetEvidenceId ?? null,
target_domain: overrides.targetDomain ?? "career",
target_kind: overrides.targetKind ?? "career_entry",
expected_answer_schema: overrides.expectedAnswerSchema ?? {},
status: "active",
asked_at: "2026-08-12T10:00:05.000Z",
resolved_at: null,
asked_turn_id: overrides.askedTurnId ?? null,
answer_option: overrides.answerOption ?? null,
};
}
export function computeFixture(overrides: {
baselineBirthSnapshot?: Record<string, unknown>;
baselineProfileFingerprint?: string;
} = {}) {
return {
case_id: CASE_ID,
skill_version: "9.0.0",
baseline_profile_fingerprint: overrides.baselineProfileFingerprint ?? "a".repeat(64),
baseline_birth_snapshot: overrides.baselineBirthSnapshot ?? {
birth_date: "1997-08-08",
birth_place_label: "河北省邯郸市",
latitude: 36.420487,
longitude: 114.209936,
timezone_id: "Asia/Shanghai",
timezone_offset: 8,
birth_time_source: "family_exact",
reported_birth_time: "05:00",
active_birth_time: null,
uncertainty_before_minutes: 10,
uncertainty_after_minutes: 10,
},
candidate_range: CANDIDATE_RANGE,
};
}
/** Tool receipt RPCs always succeed. */
export const receiptHandlers: Partial<Record<string, FakeRpcHandler>> = {
get_agentic_rectification_skill_identity: () => ({
skill_name: "jyotish-birth-time-rectification",
skill_version: "9.0.0",
skill_sha256: RECTIFICATION_SKILL_SHA256,
skill_source_commit: RECTIFICATION_SKILL_SOURCE_COMMIT,
}),
create_agentic_rectification_run_attempt: (_fn, args) => ({
attempt_id: Number(args.p_attempt_number) === 2
? "bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb"
: ATTEMPT_ID,
idempotent: false,
}),
finalize_agentic_rectification_run_attempt: (_fn, args) => ({
attempt_id: args.p_attempt_id ?? ATTEMPT_ID,
status: args.p_status ?? "completed",
}),
insert_agentic_rectification_skill_run_receipt: () => ({
receipt_id: "88888888-8888-4888-8888-888888888888",
skill_name: "jyotish-birth-time-rectification",
skill_version: "9.0.0",
skill_sha256: RECTIFICATION_SKILL_SHA256,
source_commit: RECTIFICATION_SKILL_SOURCE_COMMIT,
}),
insert_agentic_rectification_tool_receipt: () => ({ receipt_id: "99999999-9999-4999-8999-999999999999" }),
insert_agentic_rectification_run_phase: () => ({ phase_id: "99999999-9999-4999-8999-999999999999" }),
record_agentic_rectification_turn_origin: (_fn, args) => ({
turn_id: args.p_turn_id,
origin: args.p_origin,
client_action_id: args.p_client_action_id,
content_hash: args.p_content_hash,
idempotent: false,
}),
transition_agentic_rectification_case_status: () => ({ case_id: CASE_ID, status: "collecting_evidence", idempotent: false }),
};
export function candidateSnapshotFixture(overrides: {
confirmationAllowed?: boolean;
selectionAllowed?: boolean;
representativeTime?: string | null;
selectedTime?: string | null;
selectionKind?: string | null;
candidates?: unknown[];
evidenceLedgerFingerprint?: string | null;
decisionReceipt?: Record<string, unknown>;
} = {}) {
return {
result_id: RESULT_ID,
candidates: overrides.candidates ?? [
{ candidate_id: CANDIDATE_ID, rank: 1, time: "05:02", relative_support: 58, tied_minute_count: 2 },
{ candidate_id: SECOND_CANDIDATE_ID, rank: 2, time: "04:55", relative_support: 42, tied_minute_count: 3 },
],
overall_confidence: "medium",
selection_allowed: overrides.selectionAllowed ?? true,
confirmation_allowed: overrides.confirmationAllowed ?? false,
decision_receipt: {
receipt_version: "candidate-decision-receipt-v2",
policy_version: "rectification-candidate-policy-v2",
selection_allowed: overrides.selectionAllowed ?? true,
acceptance_allowed: overrides.selectionAllowed ?? true,
propose_allowed: overrides.selectionAllowed ?? true,
confirmation_allowed: overrides.confirmationAllowed ?? false,
representative_candidate_id: overrides.representativeTime ? CANDIDATE_ID : null,
overall_confidence: "medium",
...overrides.decisionReceipt,
},
execution_ledger: [{ method: "d1-rashi", status: "executed" }],
representative_time: overrides.representativeTime ?? null,
selected_time: overrides.selectedTime ?? null,
selection_kind: overrides.selectionKind ?? null,
evidence_ledger_fingerprint: overrides.evidenceLedgerFingerprint === undefined
? "b".repeat(64)
: overrides.evidenceLedgerFingerprint,
candidate_range_fingerprint: "c".repeat(64),
skill_version: "9.0.0",
algorithm_version: "rectification-v5",
created_at: "2026-08-12T10:05:00.000Z",
invalidated_at: null,
};
}