Files
Jyotisha/frontend/tests/rectification-ingest-p0-database.test.ts
T
Jesse_Chen 7c7a25773c
Independent Staging Quality Gate / validate (push) Successful in 8m46s
Independent Staging Quality Gate / publish (push) Successful in 9m8s
fix(rectification): let a tied plateau be adopted as the session result
Adjacent minutes still cannot confirm a unique birth minute. A scored
representative time can now be accepted, and the copy must say the minute
is not unique.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-19 10:41:47 +08:00

289 lines
10 KiB
TypeScript

import assert from "node:assert/strict";
import { spawnSync } from "node:child_process";
import { fileURLToPath } from "node:url";
import test from "node:test";
import { closeLocalPostgresDataPool, createLocalPostgresDataClient } from "../src/lib/db/local-postgres-client-core.ts";
import { startPostgresFixture } from "./helpers/postgres-fixture.ts";
const runnerPath = fileURLToPath(
new URL("../scripts/db-migrate.mjs", import.meta.url),
);
function dockerAvailable(): boolean {
const probe = spawnSync("docker", ["version", "--format", "{{.Server.Version}}"], {
encoding: "utf8",
stdio: "ignore",
});
return probe.status === 0;
}
const skipWithoutDocker = dockerAvailable() ? false : "docker unavailable on this host";
const snapshot = {
birth_date: "1997-08-08",
latitude: 36.420487,
longitude: 114.209936,
timezone_offset: 8,
birth_time_source: "family_exact",
reported_birth_time: "05:00",
active_birth_time: null,
birth_time_period: null,
uncertainty_before_minutes: 10,
uncertainty_after_minutes: 10,
};
const fingerprint = "a".repeat(64);
const range = { start_time: "04:50", end_time: "05:10" };
function rpcError(error: unknown): string {
if (!error || typeof error !== "object") return "";
const value = error as { message?: unknown };
return typeof value.message === "string" ? value.message : "";
}
function asObject(value: unknown): Record<string, unknown> {
if (typeof value === "string") return JSON.parse(value) as Record<string, unknown>;
if (value && typeof value === "object") return value as Record<string, unknown>;
return {};
}
test("ingest P0: education kinds, batch confirm, opening focus reuse, precision lock", { skip: skipWithoutDocker }, async () => {
const fixture = startPostgresFixture();
const schemaUrl = fixture.connectionUrl("schema_owner", "schema-owner-test-password");
try {
const migration = spawnSync(process.execPath, [runnerPath], {
encoding: "utf8",
env: { ...process.env, SCHEMA_DATABASE_URL: schemaUrl },
});
assert.equal(migration.status, 0, migration.stderr);
assert.match(migration.stdout, /applied 20260819010000_rectification_ingest_precision_plateau\.sql/);
fixture.psqlAs(
"identity_runtime",
"identity-runtime-test-password",
`
insert into identity.users (name, email, email_verified, email_verified_at)
values ('Ingest', 'ingest-p0@example.com', true, now())
`,
);
const userId = fixture.psql(
"select id from identity.users where email = 'ingest-p0@example.com'",
);
fixture.psql(`
update public.profiles
set birth_date = '1997-08-08',
reported_birth_time = '05:00',
birth_time_source = 'family_exact',
latitude = 36.420487, longitude = 114.209936, timezone_offset = 8,
birth_time_status = 'reported'
where id = '${userId}';
`);
const service = createLocalPostgresDataClient(
fixture.connectionUrl("service_runtime", "service-runtime-test-password"),
null,
"service_role",
);
const opened = await service.rpc("open_agentic_rectification_case", {
p_user_id: userId,
p_request_id: "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa",
p_intent: "homepage",
p_session_id: null,
p_skill_name: "jyotish-birth-time-rectification",
p_skill_version: "10.0.3",
p_baseline_profile_fingerprint: fingerprint,
p_baseline_birth_snapshot: snapshot,
p_candidate_range: range,
});
assert.equal(opened.error, null, rpcError(opened.error));
const caseId = String(asObject(opened.data).case_id);
const turn = await service.rpc("append_agentic_rectification_turn", {
p_user_id: userId,
p_case_id: caseId,
p_user_message: "2016年6月高考结束,2016年9月大学入学",
p_assistant_message: "已记下这两件教育经历。",
p_model_name: "test-model",
p_model_version: "1",
p_status: "completed",
p_request_id: "bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb",
});
assert.equal(turn.error, null, rpcError(turn.error));
const turnId = String(asObject(turn.data).turn_id);
const batch = await service.rpc("record_agentic_rectification_evidence_batch", {
p_user_id: userId,
p_case_id: caseId,
p_source_turn_id: turnId,
p_focus_id: null,
p_items: [
{
idempotency_key: "ingest-gaokao",
quote: "2016年6月高考结束",
subject: "self",
event_kind: "education_milestone",
domain: "education",
occurred_from: "2016-06-01",
occurred_to: null,
date_precision: "month",
summary: "2016年6月高考结束",
},
{
idempotency_key: "ingest-university",
quote: "2016年9月大学入学",
subject: "self",
event_kind: "education_milestone",
domain: "education",
occurred_from: "2016-09-01",
occurred_to: null,
date_precision: "month",
summary: "2016年9月大学入学",
},
],
});
assert.equal(batch.error, null, rpcError(batch.error));
const batchRow = asObject(batch.data);
assert.equal(batchRow.accepted_count, 2);
assert.equal(batchRow.rejected_count, 0);
const batchItems = Array.isArray(batchRow.items) ? batchRow.items as Record<string, unknown>[] : [];
assert.equal(batchItems.length, 2);
assert.equal(batchItems[0]?.outcome, "accepted");
assert.equal(batchItems[0]?.status, "confirmed");
assert.equal(batchItems[1]?.outcome, "accepted");
assert.equal(batchItems[1]?.status, "confirmed");
const secondTurn = await service.rpc("append_agentic_rectification_turn", {
p_user_id: userId,
p_case_id: caseId,
p_user_message: "2016年6月高考结束,2016年9月大学入学,另外2014年8月8日搬家",
p_assistant_message: "继续核对这几件经历。",
p_model_name: "test-model",
p_model_version: "1",
p_status: "completed",
p_request_id: "cccccccc-cccc-4ccc-8ccc-cccccccccccc",
});
assert.equal(secondTurn.error, null, rpcError(secondTurn.error));
const secondTurnId = String(asObject(secondTurn.data).turn_id);
const openingFocus = await service.rpc("set_agentic_rectification_conversation_focus", {
p_user_id: userId,
p_case_id: caseId,
p_question_id: "opening",
p_intent: "collect_first_event",
p_target_evidence_id: null,
p_target_domain: null,
p_target_kind: null,
p_expected_answer_schema: {},
});
assert.equal(openingFocus.error, null, rpcError(openingFocus.error));
const focusPayload = asObject(openingFocus.data);
const focusId = String(focusPayload.focus_id ?? asObject(focusPayload.focus).id);
assert.match(focusId, /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i);
const firstDraft = await service.rpc("propose_agentic_rectification_evidence", {
p_user_id: userId,
p_case_id: caseId,
p_source_turn_id: secondTurnId,
p_user_quote: "2016年6月高考结束",
p_subject: "self",
p_event_kind: "education_milestone",
p_domain: "education",
p_occurred_from: "2016-06-01",
p_occurred_to: null,
p_date_precision: "month",
p_summary: "2016年6月高考结束",
});
assert.equal(firstDraft.error, null, rpcError(firstDraft.error));
assert.equal(asObject(firstDraft.data).outcome, "accepted");
const firstEvidenceId = String(asObject(firstDraft.data).evidence_id);
const secondDraft = await service.rpc("propose_agentic_rectification_evidence", {
p_user_id: userId,
p_case_id: caseId,
p_source_turn_id: secondTurnId,
p_user_quote: "2016年9月大学入学",
p_subject: "self",
p_event_kind: "education_milestone",
p_domain: "education",
p_occurred_from: "2016-09-01",
p_occurred_to: null,
p_date_precision: "month",
p_summary: "2016年9月大学入学",
});
assert.equal(secondDraft.error, null, rpcError(secondDraft.error));
const secondEvidenceId = String(asObject(secondDraft.data).evidence_id);
const firstConfirm = await service.rpc("confirm_agentic_rectification_evidence_v10", {
p_user_id: userId,
p_case_id: caseId,
p_focus_id: focusId,
p_evidence_id: firstEvidenceId,
});
assert.equal(firstConfirm.error, null, rpcError(firstConfirm.error));
assert.equal(
fixture.psql(`select status from public.agentic_rectification_conversation_focuses where id = '${focusId}'`),
"active",
);
const secondConfirm = await service.rpc("confirm_agentic_rectification_evidence_v10", {
p_user_id: userId,
p_case_id: caseId,
p_focus_id: focusId,
p_evidence_id: secondEvidenceId,
});
assert.equal(secondConfirm.error, null, rpcError(secondConfirm.error));
const dayDraft = await service.rpc("propose_agentic_rectification_evidence", {
p_user_id: userId,
p_case_id: caseId,
p_source_turn_id: secondTurnId,
p_user_quote: "2014年8月8日搬家",
p_subject: "self",
p_event_kind: "relocation",
p_domain: "relocation",
p_occurred_from: "2014-08-08",
p_occurred_to: null,
p_date_precision: "day",
p_summary: "2014年8月8日搬家",
});
assert.equal(dayDraft.error, null, rpcError(dayDraft.error));
const dayEvidenceId = String(asObject(dayDraft.data).evidence_id);
const dayConfirm = await service.rpc("confirm_agentic_rectification_evidence_v10", {
p_user_id: userId,
p_case_id: caseId,
p_focus_id: null,
p_evidence_id: dayEvidenceId,
});
assert.equal(dayConfirm.error, null, rpcError(dayConfirm.error));
assert.equal(
fixture.psql(`select date_precision from public.agentic_rectification_evidence where id = '${dayEvidenceId}'`),
"day",
);
const coarsen = await service.rpc("revise_agentic_rectification_evidence", {
p_user_id: userId,
p_case_id: caseId,
p_evidence_id: dayEvidenceId,
p_user_quote: "是",
p_occurred_from: "2014-01-01",
p_occurred_to: null,
p_date_precision: "year",
p_summary: "改成年级",
});
assert.match(rpcError(coarsen.error), /agentic_rectification_precision_downgrade/);
assert.equal(
fixture.psql(`select date_precision from public.agentic_rectification_evidence where id = '${dayEvidenceId}'`),
"day",
);
} finally {
try {
await closeLocalPostgresDataPool(
fixture.connectionUrl("service_runtime", "service-runtime-test-password"),
);
} finally {
fixture.stop();
}
}
});