814c924e4a
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>
73 lines
2.7 KiB
TypeScript
73 lines
2.7 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import { readFileSync } from "node:fs";
|
|
import test from "node:test";
|
|
|
|
import { PROBE_EXPLAIN_COPY } from "../src/lib/rectification-agentic/v9/probe-explain.ts";
|
|
import { projectRectificationStepState, STEP_STATE_COPY } from "../src/lib/rectification-agentic/v9/step-state.ts";
|
|
import { parseRectificationStepState } from "../src/lib/rectification-candidate-result.ts";
|
|
|
|
test("step state covers collect, discriminate, deliver, and post-adopt", () => {
|
|
const collect = projectRectificationStepState({
|
|
nextAction: "ask_fact_collection",
|
|
methodsCovered: false,
|
|
});
|
|
assert.equal(collect.stage, "collect");
|
|
assert.equal(collect.index, 1);
|
|
assert.match(collect.headline, /第 1 步/);
|
|
|
|
const discriminate = projectRectificationStepState({
|
|
nextAction: "ask_candidate_discriminator",
|
|
methodsCovered: true,
|
|
});
|
|
assert.equal(discriminate.stage, "discriminate");
|
|
assert.equal(discriminate.index, 2);
|
|
assert.match(discriminate.next, /先这样/);
|
|
|
|
const exhausted = projectRectificationStepState({
|
|
nextAction: "complete_with_range",
|
|
methodsCovered: true,
|
|
stopReason: "probe_pool_exhausted",
|
|
});
|
|
assert.equal(exhausted.stage, "deliver");
|
|
assert.match(exhausted.reason, /已经问完/);
|
|
|
|
const uncertain = projectRectificationStepState({
|
|
nextAction: "complete_with_range",
|
|
stopReason: "user_uncertainty_too_high",
|
|
});
|
|
assert.equal(uncertain.stage, "deliver");
|
|
assert.match(uncertain.reason, /说不好/);
|
|
|
|
const adopted = projectRectificationStepState({
|
|
accepted: true,
|
|
nextAction: "ask_holdout_validation",
|
|
});
|
|
assert.equal(adopted.stage, "post_adopt");
|
|
assert.equal(adopted.index, 4);
|
|
});
|
|
|
|
test("step state parser rejects forbidden certainty words", () => {
|
|
const parsed = parseRectificationStepState(projectRectificationStepState({
|
|
nextAction: "offer_provisional_range",
|
|
}));
|
|
assert.ok(parsed);
|
|
const blob = `${parsed.headline}${parsed.reason}${parsed.next}`;
|
|
assert.doesNotMatch(blob, /概率|置信度|确定/);
|
|
});
|
|
|
|
test("chat renders rectification-step-state above the composer", () => {
|
|
const chat = readFileSync(new URL("../src/components/rectification-agentic-chat.tsx", import.meta.url), "utf8");
|
|
const route = readFileSync(new URL("../src/app/api/rectification/cases/[caseId]/route.ts", import.meta.url), "utf8");
|
|
assert.match(chat, /rectification-step-state/);
|
|
assert.match(chat, /rectification-composer-meta/);
|
|
assert.match(route, /step_state: stepStateFromCaseDossier/);
|
|
});
|
|
|
|
test("explain-layer copy avoids probability words", () => {
|
|
const blob = [
|
|
...Object.values(PROBE_EXPLAIN_COPY),
|
|
...Object.values(STEP_STATE_COPY).flatMap((item) => Object.values(item)),
|
|
].join("\n");
|
|
assert.doesNotMatch(blob, /概率|置信度|确定/);
|
|
});
|