fix(rectification): align leftover prompt and focus tests with the shrunk agent contract
Independent Staging Quality Gate / validate (push) Successful in 27m23s
Independent Staging Quality Gate / publish (push) Successful in 52m48s

Independent Staging Quality Gate 2141 failed because four tests still matched the old Mastra prompt wall and treated an unrenderable focus as null.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Jesse_Chen
2026-08-28 20:56:58 +08:00
parent 63b4591aae
commit 7de36e11d6
4 changed files with 10 additions and 7 deletions
+1 -1
View File
@@ -6407,7 +6407,7 @@
- 触发条件:varga 风格标签含禁词或不足两项;已持久化 Focus 的 choice schema 缺四选项;`proposeAllowed` 为 false 时模型仍看到 `offer-candidates`
- 根因:选项补全和可渲染检查只返回成功数组或 `null`,没有 `reason`。读路径把坏 schema 当成「没有题」。Agent 工具表不看 `decideFromDossier`。TS/Python 合同没有 byte-equal golden。`uniquify` 曾用 `answer_class` 当可见后缀。
- 修复:补全/可渲染返回 `{ ok, options|reason }``inspectDiscriminatorProbes` 把丢题写入 `decision.droppedProbes` 和 receipt `dropped_probes`。GET/`turn_decision` 对坏选择题返回 `{ unrenderable: true, reason }`,采集类 Focus 仍为 `null``createRectificationV9AgentTools(ctx, decision)` 按 phase / `proposeAllowed` / `selectionAllowed` / `canConfirmExactMinute` 过滤工具。合同 golden 在 `contracts/probe-question-v1.json`,引擎 client 拒不匹配的 `question_contract_version`。重复标签用 `·2` 而不是 `weak_yes`。Mastra 提示词删掉已由代码执行的外貌/财务/工具禁令,Skill 保持 10.0.13。`lib/birth-time-*` 仍被 `app/``components/` 的 guided/journey/intake 与 `/api/birth-time-journey``/api/birth-time-guide` 引用,本批不删。
- 验证:`rectification-probe-question-contract` 锁定 result type、index uniquify、golden bytes、forbidden_copy 丢题。Python `test_probe_question_contract` 同样对齐 golden。`rectification-answer-choice` 锁定坏 schema 为 unrenderable、采集 Focus 仍 null。`rectification-v10-tool-contract` 锁定 `proposeAllowed` 为 false 时没有 `offer-candidates``rectification-v9-engine-contract` 锁定错误合同版本 fail-closed。`rectification-v9-agent` / `rectification-agentic-entry` 锁定瘦身后的提示词
- 验证:`rectification-probe-question-contract` 锁定 result type、index uniquify、golden bytes、forbidden_copy 丢题。Python `test_probe_question_contract` 同样对齐 golden。`rectification-answer-choice` 锁定坏 schema 为 unrenderable、采集 Focus 仍 null。`rectification-server-focus` 锁定不完整 choice schema 为 unrenderable 而不是可点选 prompt。`rectification-v10-tool-contract` 锁定 `proposeAllowed` 为 false 时没有 `offer-candidates``rectification-v9-engine-contract` 锁定错误合同版本 fail-closed。`rectification-v9-agent` / `rectification-agentic-entry` / `rectification-ingest-p0` / `rectification-confirmation-gate` 锁定瘦身后的提示词(`confirmation_allowed``不得宣称唯一出生分钟``新事件走 rectification-record-evidence-batch`),不再要求 Mastra 提示词复述 `confirmation_gate`。Independent Staging Quality Gate 必须通过后才算部署
- 防复发:不得把 `completeStyleOptions` / `isRenderableProbe` 改回只返回数组或 boolean。不得把坏选择题投影成 `current_question: null`。不得在无决策时按 phase 过滤工具后,再把 `offer-candidates` 写进提示词禁令。不得用 `answer_class` 当可见标签后缀。不得在本路径删除仍被 journey/guide UI 引用的 `birth-time-*`。不得把 Skill 升出版本。
- 相关记录:BUG-403、BUG-421、#42
- 复发自:BUG-403(动态四选项合同未贯穿丢题原因)
@@ -211,8 +211,8 @@ test("holdout not_ready forbids unique-minute copy and still blocks confirm", as
assert.match(skill, /unique_minute_path=closed_at_representative/);
assert.doesNotMatch(skill, /还不能确认唯一分钟/);
assert.match(candidateComparison, /confirmation_gate/);
assert.match(agentSource, /confirmation_gate/);
assert.match(agentSource, /session_outcome=adopt_representative/);
assert.match(agentSource, /confirmation_allowed/);
assert.match(agentSource, /不得宣称唯一出生分钟/);
assert.doesNotMatch(agentSource, /±2 分钟/);
assert.equal(PUBLIC_RECTIFICATION_TOOLS.length, 14);
assert.equal(RECTIFICATION_SKILL_VERSION, "10.0.13");
@@ -140,7 +140,7 @@ test("a 25-minute tied plateau projects width and forbids unique-minute confirma
);
assert.match(candidateComparison, /一段不可分区间/);
assert.match(candidateComparison, /代表性候选/);
assert.match(agentSource, /不得说已定位到唯一分钟/);
assert.match(agentSource, /不得宣称唯一出生分钟/);
});
test("read-case evidence context keeps day labels and confirm does not rewrite dates", async () => {
@@ -215,7 +215,7 @@ test("new-case skill identity is 10.0.13 and the prompt prefers batch ingest", (
assert.equal(RECTIFICATION_SKILL_VERSION, "10.0.13");
assert.match(skill, /^version: 10\.0\.13$/m);
assert.match(skill, /不要对同一句用户消息里的多件事件逐条 propose\+confirm/);
assert.match(agentSource, /当前轮新事件一律走 rectification-record-evidence-batch/);
assert.match(agentSource, /新事件走 rectification-record-evidence-batch/);
assert.doesNotMatch(agentSource, /分别调用 rectification-propose-evidence 和 rectification-confirm-evidence/);
});
@@ -172,12 +172,15 @@ test("an unpersisted, mismatched, or incomplete focus cannot expose a discrimina
questionId: focus.questionId,
prompt: "不能展示",
}), null);
assert.equal(openQuestionFromPersistedFocus({
const incomplete = openQuestionFromPersistedFocus({
status: "created",
focus: { ...focus, expectedAnswerSchema: { choice: { prompt: "不完整" } } },
questionId: focus.questionId,
prompt: "不能展示",
}), null);
});
assert.equal(incomplete?.unrenderable, true);
assert.equal(incomplete?.prompt, null);
assert.equal(incomplete?.reason, "invalid_choice_schema");
});
test("complete dynamic event options persist a server-owned focus", async () => {