258 lines
9.0 KiB
TypeScript
258 lines
9.0 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 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;
|
|
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,
|
|
accepted_time: 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;
|
|
targetEvidenceId?: string | null;
|
|
intent?: string;
|
|
targetDomain?: string | null;
|
|
targetKind?: string | null;
|
|
expectedAnswerSchema?: Record<string, unknown>;
|
|
} = {}) {
|
|
return {
|
|
id: overrides.id ?? FOCUS_ID,
|
|
case_id: CASE_ID,
|
|
question_id: "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,
|
|
};
|
|
}
|
|
|
|
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" }),
|
|
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[];
|
|
} = {}) {
|
|
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",
|
|
decision_receipt: {
|
|
receipt_version: "candidate-decision-receipt-v2",
|
|
policy_version: "rectification-candidate-policy-v2",
|
|
selection_allowed: overrides.selectionAllowed ?? true,
|
|
acceptance_allowed: overrides.selectionAllowed ?? true,
|
|
confirmation_allowed: overrides.confirmationAllowed ?? false,
|
|
representative_candidate_id: overrides.representativeTime ? CANDIDATE_ID : null,
|
|
overall_confidence: "medium",
|
|
},
|
|
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: "b".repeat(64),
|
|
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,
|
|
};
|
|
}
|