fix(web): sync staging gate contracts with choice billing and new tables

BUG-367/368 expanded the agent action enum, dropped public thinking traces, and added two business tables, but the quality-gate source scans and exact public table list were still on the old snapshots.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Jesse_Chen
2026-08-25 09:52:21 +08:00
parent 1082338c9b
commit 2325b30227
4 changed files with 54 additions and 3 deletions
+16
View File
@@ -5531,6 +5531,22 @@
- 复发自:无
- 修复版本:未修复
## BUG-369 | staging 质量门 2003/2006:计费合同、思考轨迹与业务表清单未跟上 367/368
- 状态:resolved(本地修复,待提交与发布)
- 首次发现:2026-08-25
- 最近更新:2026-08-25
- 影响面:Gitea `backend-quality-gate.yml` validate `npm test --prefix frontend``application-billing-contract.test.ts``chat-stream-layout.test.ts``database-local-business.test.ts`、staging 发布
- 用户现象:向 `staging` 推送 `1082338c` 后 quality gate run `2056` 失败。`publish``needs: validate` 未构建镜像。公网仍为上一成功 SHA。
- 触发条件:完整 `xiaoxin` runner 跑前端全量测试;Docker PostgreSQL fixture 应用全部 `frontend/supabase/migrations`
- 根因:三处源码/schema 合同未与 BUG-367/368 同步。(1) 计费合同仍要求 `action` 只有 `opening|message|read_only`,忽略已加入且不计费的 `answer_choice`/`stop_and_review`。(2) 布局合同仍要求生时纠正聊天把 `thinking.delta` 写入 `appendActivityTraceThinking`,与禁止公开思考流冲突。(3) self-hosted 精确 `public` 表清单仍缺 `agentic_rectification_choice_actions``agentic_rectification_inference_transitions`。本机先前只跑了聚焦套件,未跑这三项。
- 修复:计费合同改为完整 action enum,仍要求只有 `message` 走 reserve/complete/release。布局合同改为禁止 `appendActivityTraceThinking``thinking.delta`,保留共享 Agent action bar 与工具步骤轨迹。全迁移测试补 applied ledger(含 turn origin)和两张新表,并断言 origin 列与 `record_agentic_rectification_turn_origin` 仅 service_role 可执行。不把业务 SQL 拷进 `frontend/db/migrations`
- 验证:`frontend/tests/application-billing-contract.test.ts``frontend/tests/chat-stream-layout.test.ts``frontend/tests/database-local-business.test.ts` 在有 Docker 的 runner 上执行。
- 防复发:新增业务表必须同步 `database-local-business` 的 applied ledger 和精确表集合。生时纠正路由 enum 变更必须更新计费合同。禁止再把公开 `thinking.delta` 写回纠正聊天合同。
- 相关记录:BUG-127、BUG-144、BUG-367、BUG-368
- 复发自:BUG-127(新业务表未更新精确表清单);BUG-367/368 的合同测试未覆盖计费 enum 与思考轨迹扫描
- 修复版本:待发布
## BUG-368 | 工具步骤英文规划被当成回答,set-focus 失败又整轮重放证据
- 状态:resolved(本地修复,待提交与发布)
@@ -34,7 +34,10 @@ test("free Agentic rectification turns bypass reservation, completion, and cance
const completeBilling = sourceBetween(rectificationRoute, "async complete(usage) {", "async release() {");
const releaseBilling = sourceBetween(rectificationRoute, "async release() {", " };\n\n try {");
assert.match(rectificationRoute, /action: z\.enum\(\["opening", "message", "read_only"\]\)/);
assert.match(
rectificationRoute,
/action: z\.enum\(\["opening", "message", "read_only", "answer_choice", "stop_and_review"\]\)/,
);
assert.equal(rectificationRoute.match(/if \(action !== "message"\)/g)?.length, 3);
assert.match(reserveBilling, /if \(action !== "message"\) \{[\s\S]*return \{ success: true, status: 200 \};/);
assert.match(reserveBilling, /authorizeUsage\(/);
+2 -2
View File
@@ -183,10 +183,10 @@ test("ordinary consultation replies reuse the shared Agent action bar", () => {
assert.match(pageSource, /function regenerateLatestAnswer\(renderKey: string\)/);
assert.match(pageSource, /messages: session\.messages\.slice\(0, -1\)/);
assert.match(pageSource, /restoreOnFailure: session/);
assert.match(rectificationChat, /appendActivityTraceThinking/);
assert.doesNotMatch(rectificationChat, /appendActivityTraceThinking/);
assert.doesNotMatch(rectificationChat, /event\.type === "thinking\.delta"/);
assert.match(rectificationChat, /startActivityTraceStep/);
assert.match(rectificationChat, /completeActivityTraceStep/);
assert.match(rectificationChat, /activityTrace = appendActivityTraceThinking\(activityTrace, event\.text\)/);
assert.match(rectificationChat, /<ChatMessageActions/);
assert.match(globalStyles, /\.message-actions \{/);
assert.doesNotMatch(globalStyles, /\.rectification-message-actions \{/);
@@ -81,6 +81,10 @@ test("local PostgreSQL applies the reviewed business schema and serves authentic
assert.match(migration.stdout, /applied 20260819010000_rectification_ingest_precision_plateau\.sql/);
assert.match(migration.stdout, /applied 20260822010000_declared_birth_window_clocks\.sql/);
assert.match(migration.stdout, /applied 20260823010000_rectification_occupation_dateless\.sql/);
assert.match(migration.stdout, /applied 20260823020000_rectification_inference_choice_write\.sql/);
assert.match(migration.stdout, /applied 20260824010000_rectification_inference_transition_ledger\.sql/);
assert.match(migration.stdout, /applied 20260824020000_rectification_choice_action\.sql/);
assert.match(migration.stdout, /applied 20260824030000_rectification_turn_origin\.sql/);
assert.equal(
fixture.psql(`
@@ -145,8 +149,10 @@ test("local PostgreSQL applies the reviewed business schema and serves authentic
"agentic_rectification_candidates",
"agentic_rectification_case_conversation_summaries",
"agentic_rectification_cases",
"agentic_rectification_choice_actions",
"agentic_rectification_conversation_focuses",
"agentic_rectification_evidence",
"agentic_rectification_inference_transitions",
"agentic_rectification_open_ledger",
"agentic_rectification_results",
"agentic_rectification_run_attempts",
@@ -212,6 +218,32 @@ test("local PostgreSQL applies the reviewed business schema and serves authentic
"user_subscriptions",
].join(","),
);
assert.equal(
fixture.psql(`
select string_agg(column_name, ',' order by column_name)
from information_schema.columns
where table_schema = 'public'
and table_name = 'agentic_rectification_turns'
and column_name in ('client_action_id', 'content_hash', 'message_origin')
`),
"client_action_id,content_hash,message_origin",
);
assert.equal(
fixture.psql(`
select
has_function_privilege(
'service_role',
'public.record_agentic_rectification_turn_origin(uuid, uuid, uuid, text, uuid, text)',
'execute'
) || ':' ||
has_function_privilege(
'authenticated',
'public.record_agentic_rectification_turn_origin(uuid, uuid, uuid, text, uuid, text)',
'execute'
)
`),
"true:f",
);
fixture.psqlAs(
"identity_runtime",