test(rectification): cover v9 migration rollout and regressions
- New suites: entry routing (13), evidence (11), skill/agent (13), stream (9), status/security (11) plus shared fake-accounting support. - Migration static contract tests extended for the v9 agent api migration (run_phases, dossier/finalize/persist/accept/confirm RPCs, consent gate, needs_rebaseline guard, runtime flag, identity-foundation boundary). - database-local-business.test.ts ledger + exact public table set updated (agentic_rectification_run_phases; BUG-127/BUG-144 boundary). - rectification-v9-database.test.ts adds the agent-api migration test (flag seed, turn finalize, run phase receipt, consent rejection). - rectification-agentic-entry.test.ts rewritten: the old tests locked in the hasRectificationSession + sessions.find guessing, textStream consumption and client-side session creation; they now assert the server-owned Case open flow, fullStream NDJSON, durable turns and exact-session routing. - consultation-entrypoint / application-billing-contract rectification sections updated to the caseId-bound billing and open API contracts. - docs/BUG_HISTORY.md: BUG-162 follow-up with regression record explaining why the old tests missed the broken entry guessing.
This commit is contained in:
@@ -759,3 +759,108 @@ test("v9 legacy backfill maps statuses, keeps one resumable per user and is idem
|
||||
fixture.stop();
|
||||
}
|
||||
});
|
||||
|
||||
test("v9 agent api migration applies, seeds the runtime flag and guards consent", { 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 20260813010000_agentic_rectification_v9_agent_api\.sql/);
|
||||
|
||||
// The runtime selector flag is published and enabled.
|
||||
assert.equal(
|
||||
fixture.psql(`select enabled || ':' || rollout_percentage || ':' || status
|
||||
from public.feature_flags where flag_key = 'rectification_runtime_version'`),
|
||||
"true:100:published",
|
||||
);
|
||||
|
||||
// Run phases table exists with RLS.
|
||||
assert.equal(
|
||||
fixture.psql(`select count(*) from pg_tables where schemaname='public' and tablename='agentic_rectification_run_phases'`),
|
||||
"1",
|
||||
);
|
||||
|
||||
// Set up a profile + case + pending turn, then exercise the turn
|
||||
// finalize and run-phase receipt RPCs.
|
||||
fixture.psqlAs("identity_runtime", "identity-runtime-test-password", `
|
||||
insert into public.profiles (id, birth_date, reported_birth_time, active_birth_time, birth_time_source,
|
||||
uncertainty_before_minutes, uncertainty_after_minutes, latitude, longitude, timezone_offset)
|
||||
values ('66666666-6666-4666-8666-666666666666', '1997-08-08', '05:00', null, 'family_exact',
|
||||
10, 10, 36.420487, 114.209936, 8);
|
||||
`);
|
||||
fixture.psqlAs("identity_runtime", "identity-runtime-test-password", `
|
||||
insert into public.chat_sessions (id, user_id, title, theme, session_type, messages)
|
||||
values ('22222222-2222-4222-8222-222222222222', '66666666-6666-4666-8666-666666666666', '生时校正', 'general', 'birth_time_rectification', '[]'::jsonb);
|
||||
`);
|
||||
fixture.psqlAs("identity_runtime", "identity-runtime-test-password", `
|
||||
insert into public.agentic_rectification_cases (
|
||||
id, user_id, session_id, status, skill_name, skill_version,
|
||||
baseline_profile_fingerprint, baseline_birth_snapshot, candidate_range
|
||||
) values (
|
||||
'11111111-1111-4111-8111-111111111111', '66666666-6666-4666-8666-666666666666',
|
||||
'22222222-2222-4222-8222-222222222222', 'draft', 'jyotish-birth-time-rectification', '9.0.0',
|
||||
'a'.repeat(64),
|
||||
'{"birth_date":"1997-08-08","latitude":36.420487,"longitude":114.209936,"timezone_offset":8,"birth_time_source":"family_exact"}'::jsonb,
|
||||
'{"start_time":"04:50","end_time":"05:10"}'::jsonb
|
||||
);
|
||||
`);
|
||||
fixture.psqlAs("identity_runtime", "identity-runtime-test-password", `
|
||||
insert into public.agentic_rectification_turns (id, case_id, user_message, status, model_name)
|
||||
values ('33333333-3333-4333-8333-333333333333', '11111111-1111-4111-8111-111111111111',
|
||||
'2016年9月离开家去北京开始工作', 'pending', 'gpt-4o-mini');
|
||||
`);
|
||||
|
||||
const service = createLocalPostgresDataClient(
|
||||
fixture.connectionUrl("service_runtime", "service-runtime-test-password"),
|
||||
null,
|
||||
"service_role",
|
||||
);
|
||||
const finalize = await service.rpc("finalize_agentic_rectification_turn", {
|
||||
p_user_id: "66666666-6666-4666-8666-666666666666",
|
||||
p_case_id: "11111111-1111-4111-8111-111111111111",
|
||||
p_turn_id: "33333333-3333-4333-8333-333333333333",
|
||||
p_status: "completed",
|
||||
p_assistant_message: "好的,我会先核对出生时间范围。",
|
||||
});
|
||||
assert.equal(finalize.error, null, rpcError(finalize.error));
|
||||
|
||||
const phase = await service.rpc("insert_agentic_rectification_run_phase", {
|
||||
p_user_id: "66666666-6666-4666-8666-666666666666",
|
||||
p_case_id: "11111111-1111-4111-8111-111111111111",
|
||||
p_turn_id: "33333333-3333-4333-8333-333333333333",
|
||||
p_phase: "skill.loaded",
|
||||
p_tool_name: null,
|
||||
p_sequence: 1,
|
||||
});
|
||||
assert.equal(phase.error, null, rpcError(phase.error));
|
||||
|
||||
const receipt = await service.rpc("get_agentic_rectification_turn_receipt", {
|
||||
p_user_id: "66666666-6666-4666-8666-666666666666",
|
||||
p_case_id: "11111111-1111-4111-8111-111111111111",
|
||||
p_turn_id: "33333333-3333-4333-8333-333333333333",
|
||||
});
|
||||
assert.equal(receipt.error, null, rpcError(receipt.error));
|
||||
const receiptRow = receipt.data as Record<string, unknown>;
|
||||
assert.equal(receiptRow.status, "completed");
|
||||
assert.equal(receiptRow.skill_version, "9.0.0");
|
||||
|
||||
// Consent-less confirmation is rejected even with a confirmable result.
|
||||
const consent = await service.rpc("confirm_agentic_rectification_birth_time", {
|
||||
p_user_id: "66666666-6666-4666-8666-666666666666",
|
||||
p_case_id: "11111111-1111-4111-8111-111111111111",
|
||||
p_result_id: "55555555-5555-4555-8555-555555555555",
|
||||
p_time: "05:02",
|
||||
p_consent_quote: "就用05:02",
|
||||
p_source_turn_id: "33333333-3333-4333-8333-333333333333",
|
||||
});
|
||||
assert.equal(consent.error, null);
|
||||
const consentRow = consent.data as { error?: unknown };
|
||||
assert.equal(consentRow.error, "agentic_rectification_candidate_not_found");
|
||||
} finally {
|
||||
fixture.stop();
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user