fix(consult): move the answer-effort probe out of the image build

The dry-run script lived under frontend/scripts and read a test fixture, so the web image build would type-check a file the image does not copy. Move it to frontend/tests with a non-test filename. The switch default is unchanged.

Checked: guard plus answer-effort tests 5 pass, 0 fail, 0 cancelled; probe --dry-run exit 0; tsc exit 0; lint 0 errors and 123 warnings.

Co-Authored-By: Grok (agent loop)
This commit is contained in:
jesse-ux
2026-10-15 10:56:22 +08:00
co-authored by Grok (agent loop)
parent 0d73cd332b
commit 9324253408
7 changed files with 59 additions and 19 deletions
+9 -9
View File
@@ -15304,17 +15304,17 @@
## BUG-1140 | staging 镜像打包失败:`frontend/scripts` 下的研究脚本引用了 `frontend/tests` 的夹具
- 状态:resolved(修复已推 staging;以门禁 publish 通过与 `/api/health` 部署版本为最终证据)
- 首次发现 / 最近更新:2026-10-01 / 2026-10-14
- 首次发现 / 最近更新:2026-10-01 / 2026-10-15
- 影响面:Gitea `backend-quality-gate` 的 publish 作业(`deploy/railway-web.Dockerfile` 构建阶段 `npm run build`)。validate 通过、publish 失败,未部署,staging 停在上一版。
- 用户现象:盘型口径(BUG-1115~1117、1131)推送后 staging 不更新。
- 触发条件:`frontend/scripts/rectification-segment-persisted-replay.ts`(盘型口径研究的 PG 持久回放 harness)`import … from "../tests/helpers/postgres-fixture.ts"`。web 镜像只复制 `frontend/src`、`frontend/scripts` 等,不复制 `frontend/tests`;`frontend/tsconfig.json` 的 include 为 `**/*.ts`,`next build` 类型检查覆盖 scripts,于是 `TS2307 Cannot find module '../tests/helpers/postgres-fixture.ts'`。
- 根因:本地与验收机都有 `frontend/tests`,`tsc --noEmit` 与 `next build` 均通过,门禁 validate 也在完整检出上跑,没有任何一步按镜像的复制清单构建。
- 修复:harness 移到 `frontend/tests/research/rectification-segment-persisted-replay.ts`(相对路径随之调整),Python driver `scripts/research/varga_resolution_persisted_replay.py` 指向新路径;新增 `frontend/tests/runtime-sources-no-test-imports.test.ts`:`src/` 与 `scripts/` 不得 import / `new URL` 引用 `tests/`。
- 验证:按 `railway-web.Dockerfile` 的 COPY 清单从提交 `git archive` 出构建目录,修复前 `npm run build` 报上述 TS2307、exit 1,修复后 exit 0、`/` Static;守卫测试 2/2,且对旧 harness 文本判定为违规;移动后 harness 1 例 ±10 冒烟 `runner_exit=0`。
- 防复发:守卫测试进 `npm test`(门禁 validate 必跑);错误台账 ERR-113。2026-10-14 这道守卫在合入前拦住了同一形状:issue #58 的往返对照脚本曾放在 `frontend/scripts/` 并导入测试夹具。脚本改放到 `frontend/tests/bench-local-pg-roundtrips.ts`,文件名不是 `.test.ts`,不会被全量测试收进去。业务代码没有改。原任务书里的旧路径保持不动。
- 防复发:守卫测试进 `npm test`(门禁 validate 必跑);错误台账 ERR-113。2026-10-14 这道守卫在合入前拦住了同一形状:issue #58 的往返对照脚本曾放在 `frontend/scripts/` 并导入测试夹具。脚本改放到 `frontend/tests/bench-local-pg-roundtrips.ts`,文件名不是 `.test.ts`,不会被全量测试收进去。业务代码没有改。原任务书里的旧路径保持不动。2026-10-15 issue #65 的请求体探针也是同一形状:`answer-effort-probe.mts` 放在 `frontend/scripts/research/`,用 `new URL` 去读 `frontend/tests` 的夹具。探针挪到 `frontend/tests/answer-effort-probe.mts`,文件名不是 `.test.ts`。业务代码没有改。
- 相关记录:BUG-1115~1117、BUG-1131、BUG-1327。
- 复发自:无。2026-10-14 是同一形状,被守卫拦住,未进测试环境。
- 修复版本:`codex/staging-publish-fix-20261001`。2026-10-14 的同类挪动在 `codex/node-runtime-resources-20261013`。
- 复发自:无。2026-10-14 与 2026-10-15 都是同一形状,被守卫拦住,未进测试环境。
- 修复版本:`codex/staging-publish-fix-20261001`。2026-10-14 的同类挪动在 `codex/node-runtime-resources-20261013`。2026-10-15 的同类挪动在 `codex/answer-effort-ab-20261013`。
## BUG-1141 | 生时校正缺少度数级时间信号(角度类技法研究)
@@ -33372,17 +33372,17 @@
## BUG-1140 | staging 镜像打包失败:`frontend/scripts` 下的研究脚本引用了 `frontend/tests` 的夹具
- 状态:resolved(修复已推 staging;以门禁 publish 通过与 `/api/health` 部署版本为最终证据)
- 首次发现 / 最近更新:2026-10-01 / 2026-10-14
- 首次发现 / 最近更新:2026-10-01 / 2026-10-15
- 影响面:Gitea `backend-quality-gate` 的 publish 作业(`deploy/railway-web.Dockerfile` 构建阶段 `npm run build`)。validate 通过、publish 失败,未部署,staging 停在上一版。
- 用户现象:盘型口径(BUG-1115~1117、1131)推送后 staging 不更新。
- 触发条件:`frontend/scripts/rectification-segment-persisted-replay.ts`(盘型口径研究的 PG 持久回放 harness)`import … from "../tests/helpers/postgres-fixture.ts"`。web 镜像只复制 `frontend/src`、`frontend/scripts` 等,不复制 `frontend/tests`;`frontend/tsconfig.json` 的 include 为 `**/*.ts`,`next build` 类型检查覆盖 scripts,于是 `TS2307 Cannot find module '../tests/helpers/postgres-fixture.ts'`。
- 根因:本地与验收机都有 `frontend/tests`,`tsc --noEmit` 与 `next build` 均通过,门禁 validate 也在完整检出上跑,没有任何一步按镜像的复制清单构建。
- 修复:harness 移到 `frontend/tests/research/rectification-segment-persisted-replay.ts`(相对路径随之调整),Python driver `scripts/research/varga_resolution_persisted_replay.py` 指向新路径;新增 `frontend/tests/runtime-sources-no-test-imports.test.ts`:`src/` 与 `scripts/` 不得 import / `new URL` 引用 `tests/`。
- 验证:按 `railway-web.Dockerfile` 的 COPY 清单从提交 `git archive` 出构建目录,修复前 `npm run build` 报上述 TS2307、exit 1,修复后 exit 0、`/` Static;守卫测试 2/2,且对旧 harness 文本判定为违规;移动后 harness 1 例 ±10 冒烟 `runner_exit=0`。
- 防复发:守卫测试进 `npm test`(门禁 validate 必跑);错误台账 ERR-113。2026-10-14 这道守卫在合入前拦住了同一形状:issue #58 的往返对照脚本曾放在 `frontend/scripts/` 并导入测试夹具。脚本改放到 `frontend/tests/bench-local-pg-roundtrips.ts`,文件名不是 `.test.ts`,不会被全量测试收进去。业务代码没有改。原任务书里的旧路径保持不动。
- 防复发:守卫测试进 `npm test`(门禁 validate 必跑);错误台账 ERR-113。2026-10-14 这道守卫在合入前拦住了同一形状:issue #58 的往返对照脚本曾放在 `frontend/scripts/` 并导入测试夹具。脚本改放到 `frontend/tests/bench-local-pg-roundtrips.ts`,文件名不是 `.test.ts`,不会被全量测试收进去。业务代码没有改。原任务书里的旧路径保持不动。2026-10-15 issue #65 的请求体探针也是同一形状:`answer-effort-probe.mts` 放在 `frontend/scripts/research/`,用 `new URL` 去读 `frontend/tests` 的夹具。探针挪到 `frontend/tests/answer-effort-probe.mts`,文件名不是 `.test.ts`。业务代码没有改。
- 相关记录:BUG-1115~1117、BUG-1131、BUG-1327。
- 复发自:无。2026-10-14 是同一形状,被守卫拦住,未进测试环境。
- 修复版本:`codex/staging-publish-fix-20261001`。2026-10-14 的同类挪动在 `codex/node-runtime-resources-20261013`。
- 复发自:无。2026-10-14 与 2026-10-15 都是同一形状,被守卫拦住,未进测试环境。
- 修复版本:`codex/staging-publish-fix-20261001`。2026-10-14 的同类挪动在 `codex/node-runtime-resources-20261013`。2026-10-15 的同类挪动在 `codex/answer-effort-ab-20261013`。
## BUG-1141 | 生时校正缺少度数级时间信号(角度类技法研究)
@@ -36191,7 +36191,7 @@
- 触发条件:调用 `consultationSliceGenerationSettings`。产品代码里没有调用方,线上对话不受影响。
- 根因:兼容通道只认供应商选项最外层的 `reasoningEffort`,并把它写成 `reasoning_effort`。嵌在 `thinking` 里的同名键会原样送出去,供应商不把它当强度。
- 修复:本单不改这处形状,也不改它的两条断言。答题步的新开关写在最外层。要不要删掉或改掉这处旧形状,等产品拍板。
- 验证:`frontend/scripts/research/answer-effort-probe.mts --dry-run`。这处设置的请求体是 `thinking.reasoningEffort = "low"`,`reasoning_effort` 为空。新开关设成 `low` 时,答题步请求体有 `reasoning_effort: "low"`。
- 验证:`frontend/tests/answer-effort-probe.mts --dry-run`。这处设置的请求体是 `thinking.reasoningEffort = "low"`,`reasoning_effort` 为空。新开关设成 `low` 时,答题步请求体有 `reasoning_effort: "low"`。
- 防复发:新测试锁住「开关不设时请求体与改前一致」,并锁住新强度出现在最外层。
- 相关记录:BUG-148、BUG-1142。
- 复发自:无。
@@ -17,7 +17,7 @@
| 检查 | 命令 | 结果 |
| --- | --- | --- |
| 请求体拦截 | `node node_modules/tsx/dist/cli.mjs scripts/research/answer-effort-probe.mts --dry-run` | 退出码 0。数字见 `docs/testing/answer-effort-ab-20261013.md` |
| 请求体拦截 | `node node_modules/tsx/dist/cli.mjs tests/answer-effort-probe.mts --dry-run` | 退出码 0。数字见 `docs/testing/answer-effort-ab-20261013.md`。2026-10-15 打回后脚本从 `frontend/scripts/research/` 挪到 `frontend/tests/`,命令改成这一条。 |
| 本单测试与任务书点名的四份 | `node node_modules/tsx/dist/cli.mjs --test` 后接 `answer-effort-switch-20261013`、`consultation-agentic-runtime`、`consultation-workflow-contract`、`consult-answer-clock-20261001`、`consult-latency-timing-20261005` | 114 pass,0 fail,0 cancelled |
| 类型检查 | 在 `frontend` 下 `.\node_modules\.bin\tsc --noEmit -p .` | 退出码 0 |
| lint | 在 `frontend` 下 `npm run lint` | 退出码 0,0 error,123 条原有 warning。探针里多出来的 1 条未使用变量已去掉,改过的文件再跑 eslint 是 0 |
@@ -0,0 +1,40 @@
# PROGRESS · 答题推理强度开关修复(2026-10-15)
- 分支:`codex/answer-effort-ab-20261013`
- 被打回的提交:`ab7f66be14d93a5ccbc3433f3c44e134a65b1e21`
- 修复单:`docs/tasks/TASK-answer-effort-ab-fix-20261015.md`
- 已合并 `origin/staging` `71f7fac3a13f817f91755ff01b25b8706380ae19`,合并提交 `0d73cd332bf4efae2b8ec9389d5853384f4616f4`。没有改写已推送的历史。
## 做了什么
1. 把 `frontend/scripts/research/answer-effort-probe.mts` 挪到 `frontend/tests/answer-effort-probe.mts`。文件名不是 `.test.ts`,也不是 `.test.tsx`,全量测试不会把它收成一条用例。
2. 相对路径改过:源码从 `../src/...` 引入,夹具改成 `./fixtures/answer-effort-switch-20261013.json`。本单测试改为从同目录引入。已经保存的夹具文件没有重写。
3. 命令同步进 `docs/tasks/PROGRESS-answer-effort-ab-20261013.md` 和 `docs/testing/answer-effort-ab-20261013.md`。
4. 业务代码没改。开关默认值没改。任务书里留到拍板的默认强度,以及没人调用的旧嵌套设置,都没做。
5. 合并时,本分支原来的调查记录占用了 BUG-1351,和数据层的 BUG-1351 撞号。保留 staging 上的 BUG-1351、BUG-1352、BUG-1353。这条调查记录改为 BUG-1354。BUG-1140 补记了这次同一形状的挪动。
## 自测
| 检查 | 命令 | 结果 |
| --- | --- | --- |
| 镜像守卫和本单测试 | 在 `frontend` 下 `node node_modules/tsx/dist/cli.mjs --test tests/runtime-sources-no-test-imports.test.ts tests/answer-effort-switch-20261013.test.ts` | 5 pass,0 fail,0 cancelled |
| 请求体拦截 | 在 `frontend` 下 `node node_modules/tsx/dist/cli.mjs tests/answer-effort-probe.mts --dry-run` | 退出码 0 |
| 类型检查 | 在 `frontend` 下 `.\node_modules\.bin\tsc --noEmit -p .` | 退出码 0 |
| lint | 在 `frontend` 下 `npm run lint` | 退出码 0,0 error,123 warning |
| 隐私标记与 bug 记录格式 | 在工作树根 `.venv\Scripts\python.exe -m pytest tests/test_repo_privacy_markers.py tests/test_bug_history_workflow.py -q` | 64 pass,0 fail,退出码 0 |
守卫的两条都在上面 5 条里面:镜像目录不再引用测试目录,并且仍认得当初弄坏构建的那几种写法。
## prepareStep 会不会盖掉原有选项
不会整份换掉。开关打开时,答题步返回的供应商选项来自 `agentGenerationSettings`,Mastra 按步做深合并,并进这一步已有的选项。思考仍是打开。输出长度上限在基础流的模型设置里,这一步没有返回它,所以上限还在。缓存标记写在消息上,不在这份流选项里。因此没有往 `BLOCKED.md` 新写一条「被覆盖」。
## 偏离
- 没有跑前端全量 `npm test`。这一侧的约定是不跑全量,留给验收。本机只跑了打回指出的那条守卫,以及本单测试。
- 修复单写的 `git diff ab7f66be..<新提交> -- frontend/src` 不是空的。原因是按修复单先合并了最新 staging,staging 自己改过星盘页和数据层。本轮修复相对合并提交 `0d73cd33`,`frontend/src` 没有差异。业务代码和开关默认值没动。
- A/B 未跑:缺模型 key。没有把请求体拦截写成对照已通过。
## 环境缺口
A/B 未跑:缺模型 key。`BLOCKED.md` 里原有的这一条保留,没有新增。
+1 -1
View File
@@ -486,7 +486,7 @@
| `TASK-api-chart-subprocess-gate-20261013.md` | — | 合盘不带 skip 串行排盘、报告无效子进程、名额轻重混用(只模拟)(BUG-1333~1334,A/B) | 待领取(排队:api-disk-cache-retention + report-reference-perf) | `codex/api-chart-subprocess-gate-20261013` |
| `TASK-api-chart-subprocess-gate-fix-20261015.md` | — | **#64 第 1 次打回**:`336286e4` 内容通过(合盘 1.19→0.015 s、正文逐字节一致);Python 合同按源码检查合盘路由旧写法未跟改;A/B 脚本默认覆盖入库记录 | 待领取 | `codex/api-chart-subprocess-gate-20261013` |
| `TASK-answer-effort-ab-20261013.md` | `PROGRESS-answer-effort-ab-20261013.md` | 答题步推理强度开关 + A/B(需模型 key) | 待验收 | `codex/answer-effort-ab-20261013` |
| `TASK-answer-effort-ab-fix-20261015.md` | — | **#65 第 1 次打回**:`ab7f66be` 开关逻辑通过(默认请求体不变);研究脚本从 `frontend/tests` 读文件(BUG-1140) | 待领取 | `codex/answer-effort-ab-20261013` |
| `TASK-answer-effort-ab-fix-20261015.md` | `PROGRESS-answer-effort-ab-fix-20261015.md` | **#65 第 1 次打回**:`ab7f66be` 开关逻辑通过(默认请求体不变);研究脚本从 `frontend/tests` 读文件(BUG-1140),已挪到 `frontend/tests/answer-effort-probe.mts` | 待验收 | `codex/answer-effort-ab-20261013` |
| `TASK-consult-route-split-20261013.md` | — | consult POST 拆分第一阶段:开流前加载 + 计费结算 | 待领取(排队:consult-prep-parallel、answer-effort-ab) | `codex/consult-route-split-20261013` |
| `TASK-pl9-render-split-20261013.md` | — | render_pl9_markdown 第一阶段:搬出无依赖内部函数 | 待领取(排队:api-chart-subprocess-gate) | `codex/pl9-render-split-20261013` |
| `TASK-python-hygiene-20261013.md` | — | 免费层排队开关报反、静默吞异常、功能吉凶兜底合一、测试专用脚本归位(BUG-1340) | 待领取(排队:pl9-render-split) | `codex/python-hygiene-20261013` |
+1 -1
View File
@@ -2,7 +2,7 @@
没有模型钥匙。下面只是本机拦截到的请求体,不是供应商的接受度,也不是耗时和质量。A/B 未跑。
命令:在 `frontend` 目录执行 `node node_modules/tsx/dist/cli.mjs scripts/research/answer-effort-probe.mts --dry-run`。假请求不离开这台机器。模型对象与产品相同:`providerId: deepseek`,`modelId: deepseek-flash`,带 `url` 和假的 `apiKey`。
命令:在 `frontend` 目录执行 `node node_modules/tsx/dist/cli.mjs tests/answer-effort-probe.mts --dry-run`。假请求不离开这台机器。模型对象与产品相同:`providerId: deepseek`,`modelId: deepseek-flash`,带 `url` 和假的 `apiKey`。2026-10-15 起脚本在 `frontend/tests/`,不再放在 `frontend/scripts/research/`。
## 请求体里实际有什么
@@ -19,13 +19,13 @@ import { Agent } from "@mastra/core/agent";
import { createTool } from "@mastra/core/tools";
import { z } from "zod";
import { agentGenerationSettings } from "../../src/lib/agent-generation-settings.ts";
import { agentGenerationSettings } from "../src/lib/agent-generation-settings.ts";
import {
consultationContinueGenerationSettings,
consultationGenerationSettings,
consultationNatalPrepareStep,
consultationSliceGenerationSettings,
} from "../../src/mastra/consultation-tools.ts";
} from "../src/mastra/consultation-tools.ts";
const MODEL = {
providerId: "deepseek",
@@ -175,7 +175,7 @@ async function main() {
steps: 1,
});
const report = {
fixtureProvenance: "frontend/scripts/research/answer-effort-probe.mts --dry-run",
fixtureProvenance: "frontend/tests/answer-effort-probe.mts --dry-run",
a_consultationGenerationSettings: natal.map(requestFields),
b_consultationSliceGenerationSettings: slice.map(requestFields),
c_providerReasoningEffort: topLevel,
@@ -183,9 +183,9 @@ async function main() {
};
console.log(JSON.stringify(report, null, 2));
if (process.argv.includes("--save-baseline")) {
const file = new URL("../../tests/fixtures/answer-effort-switch-20261013.json", import.meta.url);
const file = new URL("./fixtures/answer-effort-switch-20261013.json", import.meta.url);
writeFileSync(file, `${JSON.stringify({
fixtureProvenance: "node node_modules/tsx/dist/cli.mjs scripts/research/answer-effort-probe.mts --dry-run --save-baseline(开关尚未读取环境变量时的整份请求体)",
fixtureProvenance: "node node_modules/tsx/dist/cli.mjs tests/answer-effort-probe.mts --dry-run --save-baseline(开关尚未读取环境变量时的整份请求体)",
natal: natal,
continue: continued,
}, null, 2)}\n`);
@@ -1,7 +1,7 @@
/**
* Answer-step reasoning effort (issue #65).
* The unset bodies were captured before this switch read the environment:
* node node_modules/tsx/dist/cli.mjs scripts/research/answer-effort-probe.mts --dry-run --save-baseline
* node node_modules/tsx/dist/cli.mjs tests/answer-effort-probe.mts --dry-run --save-baseline
*/
import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
@@ -14,7 +14,7 @@ import {
consultationGenerationSettings,
consultationNatalPrepareStep,
} from "../src/mastra/consultation-tools.ts";
import { captureStreamBodies } from "../scripts/research/answer-effort-probe.mts";
import { captureStreamBodies } from "./answer-effort-probe.mts";
const MODEL = {
providerId: "deepseek",