# TASK · 前端死代码与无调用方接口清理(issue #待定) - 日期:2026-10-13 - 来源:「2026-10-13 全仓屎山与性能排查」· 前端死代码条目 - 执行方:**Grok(Windows + Docker)**,分支 `codex/frontend-dead-code-20261013`,只推这个分支 - 验收:Claude(Linux) - BUG 编号:本单发现 **1 个真实缺陷**(§2.3,未登录可触发的引擎重计算),编号 **BUG-1342**(写作时最大号 BUG-1317,1323~1341 已被同批任务书占用;开工时核对 `docs/BUG_HISTORY.md` 最大号)。其余删除是重构,无 BUG 号,记 PROGRESS。(另:`TASK-upstream-sync7-20261014` 占 BUG-1318~1322,本批号段整体从 BUG-1323 起) - 开工前置:无(第一批,立即派发)。后续 `contracts-helpers-dedupe` 依赖本单合入。 ## 1. 基线 - 基线 commit:`origin/staging` `77057a819` - 判定口径:从 Next 约定入口(`src/app/**` 下 `page/layout/route/loading/error/not-found/...`、`src/instrumentation.ts`)出发,沿 `@/`、相对路径、动态 `import()` 做可达性遍历;再补查字符串引用(`readFileSync(new URL(...))`)、Python 测试、`deploy/`、文档对外承诺。 - 复现命令(写作时用的脚本,Grok 可直接用;在 `frontend/` 下运行): ```bash python3 - <<'EOF' import os,re imp=re.compile(r'''(?:from\s+|import\s*\(\s*|import\s+|require\(\s*)['"]([^'"]+)['"]''') files=[os.path.join(d,f) for d,_,fs in os.walk('src') for f in fs if f.endswith(('.ts','.tsx'))] def res(src,spec): if spec.startswith('@/'): b=os.path.join('src',spec[2:]) elif spec.startswith('.'): b=os.path.normpath(os.path.join(os.path.dirname(src),spec)) else: return None b2=re.sub(r'\.(ts|tsx|js)$','',b) for c in [b,b2+'.ts',b2+'.tsx',os.path.join(b,'index.ts'),os.path.join(b,'index.tsx')]: if os.path.isfile(c): return os.path.normpath(c) g={f:{r for m in imp.findall(open(f,encoding='utf8').read()) if (r:=res(f,m))} for f in files} conv=re.compile(r'(^|/)(page|layout|route|loading|error|not-found|global-error|forbidden|template|default|instrumentation|middleware|proxy)\.(ts|tsx)$') seen=set(); st=[f for f in files if conv.search(f)] while st: x=st.pop() if x not in seen: seen.add(x); st+=g.get(x,()) for f in sorted(set(files)-seen): print(f, sum(1 for _ in open(f,encoding='utf8'))) EOF ``` ## 2. 事故实证(`77057a819`) ### 2.1 生产入口不可达的源文件(脚本输出,17 个,共 3,028 行) | 文件 | 行 | 引用方(全仓) | 结论 | | --- | ---: | --- | --- | | `src/mastra/rectification-tools.ts` | 736 | 仅 `rectification-agentic/session.ts` + `tests/rectification-agentic-tools.test.ts` | 删 | | `src/lib/rectification-agentic/session.ts` | 351 | `tests/rectification-agentic-session.test.ts`、`tests/database-local-business.test.ts`(DB 测试,2 处断言) | 删 | | `src/lib/rectification-agentic/date-range.ts` | 53 | 仅 `rectification-tools.ts` | 删(传递死) | | `src/lib/agent-evals.ts` | 796 | `tests/agent-evals.test.ts`(+ fixture `tests/fixtures/agent-golden-dataset-v1.json`) | 删 | | `src/components/personal-report/personal-report-document-view.tsx` | 630 | `personal-report-view.test.ts`(渲染)、`personal-report-progress.test.ts:208-209`、`personal-report-export.test.ts:49`(读源码) | 删;阅读页 09 月起走 `personal-report-markdown-view.tsx` | | `src/lib/think-step-gate.ts` | 17 | `public-thinking.test.ts`、`rectification-step-answer.test.ts:64`(读源码) | 删;最后一个生产调用方在 `eef0cb748`(BUG-1053)移除 | | `src/lib/birth-time-candidate-completion.ts` | 14 | `birth-time-candidate-completion.test.ts` | 删(函数恒返回 null;顺带消掉 BLOCKED.md 登记的 2 条 lint warning) | | `src/components/birth-time-life-events.tsx` | 207 | 无(BUG-1193 已注明「无引用方」) | 删 | | `src/components/evidence-audit-panel.tsx` | 64 | `evidence-audit-panel.test.ts` 读源码 | 删,**保留否定断言**(见红线) | | `src/components/claim-boundary-badge.tsx` | 13 | `claim-boundary-badge.test.ts` 读源码 | 删,**保留否定断言** | | `src/components/birth-time-soft-notice.tsx` | 36 | 只有否定断言(`doesNotMatch`) | 删 | | `src/components/personal-report/raw-appendix-download.tsx` | 33 | `personal-report-raw-appendix.test.ts:106` 读源码 | 删(09-24 已授权,见 §4) | | `src/lib/chart-library-view.ts` | 18 | 无 | 删 | | `src/lib/db/client.ts` | 18 | 无(仓内唯一 `drizzle-orm` 引用方) | 删;依赖不动,见后续阶段 | | `src/lib/rectification-agentic/core/index.ts` | 23 | `rectification-decide-next-action.test.ts:587` 读源码 | 删 barrel,对应测试改写 | | `src/lib/rectification-agentic/v9/index.ts` | 11 | 无 | 删 barrel | | `src/lib/personal-report-longform-download.ts` | 8 | 4 个测试 | **不删**——见下 | **修正排查结论**:`personal-report-longform-download.ts::ordinaryReportDownloadMarkdown` 是 `TASK-report-chapter-export-20260924` D5 明文保留的**逐字节回归锁**(`report-export-blocks.test.ts:55-57`「全选导出 ≡ 旧普通导出」与冻结 sha256),文件头注释也写明「retained as the full-body byte regression lock」。本单不动它。 ### 2.2 无前端调用方的接口 | 接口 | 行 | 现状 | | --- | ---: | --- | | `POST /api/birth-rectification`(`src/app/api/birth-rectification/route.ts`) | 49 | 全仓无 fetch;只被 `tests/test_daily_and_rectification_entrypoints.py::test_birth_rectification_api_proxies_active_questionnaire_with_boundary` 读源码钉住(07 月「入口产品化」时代的源码文本断言,首页卡片入口 BUG-1247 后早已删除)。唯一依赖 `src/lib/birth-rectification-payload.ts`(41 行),后者另被 `global-birth-profile-routes.test.ts:43` 一处断言使用 | | `POST /api/birth-time-candidate-completion` | 20 | 无调用方;恒返回 400/409 的「旧客户端兼容」桩(07-21 起),任何客户端都不会再发 | | `POST /api/reports/[reportId]/raw-appendix` | 48 | 唯一调用方就是上面的死组件 `raw-appendix-download.tsx`;`releaseRawReportAppendix`(`src/lib/personal-report-raw-appendix.ts`,13 行)只剩这条路由 + 测试使用 | 对外承诺核查:`deploy/`、`skills/`、`references/`、MCP、文档对外章节都没有这三个路径(`references/oracle/...json` 中的 `birth-rectification` 是无关英文词)。 ### 2.3 真实缺陷:未登录即可触发约 20 秒的引擎重计算 - `/api/birth-rectification` **不鉴权**(`src/` 下没有 middleware/proxy;该 route 不读会话),Caddy 把 `/api/*` 全部反代到 web(`deploy/Caddyfile.staging`、`Caddyfile.production.selfhosted`)。 - 它把请求转发到 Python `/api/active_rectification_questions`(`uncertainty_minutes: 30, step_minutes: 2`),**该路径不在** `scripts/api_heavy_compute_gate.py::HEAVY_COMPUTE_PATHS` 中,不受并发 2 的闸门限制。 - 实测(本机,虚构盘 1990-01-01 12:00 新德里,`build_questionnaire` 同参数,3 次):**20.7 s / 25.6 s / 23.6 s**,中位 23.6 s 单核 CPU。 - Next 侧 2.5 s 后 abort,但 Python 是同步处理,中止不会打断计算(推断,未在 staging 实打)。即:任何人无需登录,每发一次 POST 就消耗生产 API 容器约 20 秒 CPU(主机 2 vCPU),且无并发上限。 - 复现命令: ```bash python3 -c " import sys,time; sys.path[:0]=['.','scripts'] from scripts.active_rectification_questions import build_questionnaire t=time.time(); build_questionnaire('1990-01-01 12:00',uncertainty_minutes=30,step_minutes=2,lat=28.6139,lon=77.2090,tz=5.5,ayanamsa='lahiri',node_mode='mean'); print(round(time.time()-t,1))" ``` (运行后若工作树产生 `scratch/` 缓存,它在 `.gitignore` 里,不入库。) ## 3. 根因 - 这些文件是历次改版的残留:旧 agentic 校正(被 v9 取代)、旧结构化报告阅读页(被 Markdown 阅读页取代)、内部审计面板(BUG-011/298 从聊天里摘掉后没删组件)、09-24 原始附录下线时**删除被权限系统拒绝**(BUG-1004 修订条)。每次只摘入口、不删实现,测试又在读源码文本,所以死代码一直「有测试、看起来活着」。 - `/api/birth-rectification` 是 07 月早期首页卡片的后端;卡片删了,路由没删;写它时还没有鉴权约定与重计算闸门。**不是回归,是遗留入口从未收口。** - 关联:BUG-011、BUG-298(内部面板不得重新挂载)、BUG-953(think 门保留的来由)、BUG-1004(原始附录下线时删除被拒)、BUG-1053(移除 think 门最后调用方)、BUG-1178(注明旧 `rectification-tools.ts` 仅 legacy 引用)、BUG-1193(`birth-time-life-events.tsx` 无引用方)。 ## 4. 决策记录 - 2026-10-13 产品负责人同意按排查结论全部立单交 Grok 执行;产品偏好「多余入口宁可删除也不修」(CLAUDE.md)。 - **测试总数下降是产品授权的例外**:AGENTS.md §7.3 规定测试总数不得低于基线;本单删除的是「只测死代码」的测试,授权其随实现一起删除。条件:PROGRESS 里逐条列出删掉的测试名(文件 + 测试标题)与原因;否定合同(「不得再挂载 X」)不在例外内,必须保留或改写成等价断言。 - 原始附录路由:`TASK-report-reader-actions-20260924` D2 已授权「`/api/reports/[reportId]/raw-appendix` 路由与 `releaseRawReportAppendix` 若全仓再无调用者一并删除(含其测试,三栏说明)」,当时被权限系统拒绝。本单完成该授权,**不新增授权**。 - `/api/birth-rectification`:删除即修复 §2.3 缺陷,不给它补鉴权(多余入口删除而不修)。Python 端 `/api/active_rectification_questions` 只在 Docker 内网,**不动**(`jyotish_api_server.py` 冻结)。 - `ordinaryReportDownloadMarkdown` 保留(09-24 D5 回归锁),不推翻。 - 不在本单:旧协议 `legacy-guided-v1` 全链路、裸 textarea(存量数据还在用);`drizzle-orm` 依赖移除;其它疑似无调用方路由(见后续阶段)。 ## 5. 硬红线 1. **只删不改**:除下面列明的测试改写、DESIGN.md 一行、BLOCKED.md 划线、BUG_HISTORY/PROGRESS 外,不改任何生产文件的逻辑。删一个文件导致的编译错误只能通过「继续删死代码」或「删 import」解决,不得改业务代码去迁就。 2. 否定合同必须保留:`chat-message-row.tsx` / `chat-message-content.tsx` / `technique-audit` 不得出现 `EvidenceAuditPanel`、`ClaimBoundaryBadge`、`techniqueTruth`/`workflowReceipt` 挂载(BUG-011/298);`" frontend/src frontend/tests`。 - 验收:Claude `next build` 后首屏 gzip 只减不增。 ## 7. 让步顺序 时间不够依次砍:T5 → T3 中 raw-appendix 部分(退回为 PROGRESS 待办)→ T2 中 `personal-report-view.test.ts` 拆分(保留 document-view 文件,写 PROGRESS)。**T3 的 `/api/birth-rectification` 删除与 T4 BUG 记录不得砍**。 ## 8. 验收命令分工 | 谁 | 命令 | | --- | --- | | Grok 自跑 | `tsc --noEmit`;`npm run lint`;改到/删到的前端测试文件逐个单跑(fail、cancelled 均为 0);`.venv/bin/python -m pytest tests/test_daily_and_rectification_entrypoints.py tests/test_repo_privacy_markers.py -q`;**`npm run test:db`**(动了 `database-local-business.test.ts`,以 Grok 为准,按 `windows-known-failures.txt` 比对)。前端全量、Python 快速门、`next build` 不跑 | | Claude 验收 | 上述全部 + 前端全量 `npm test`:失败清单与基线逐条一致,总数下降量 = PROGRESS 删除测试清单条数(逐名核对)+ Python 快速门 + `next build`(`/` 仍 Static,首屏 gzip 不增)+ 重跑 §1 脚本 | ## 9. 开工前置命令 ```bash git fetch origin --prune git worktree add -b codex/frontend-dead-code-20261013 .worktrees/frontend-dead-code-20261013 origin/staging cd .worktrees/frontend-dead-code-20261013 git log -1 --format=%h # 应为 77057a819 或其后代 grep -n "^## BUG-" docs/BUG_HISTORY.md | tail -3 # 核对最大号 # 开工基线:前端测试文件数与测试数(写进 PROGRESS) ls frontend/tests/*.test.ts frontend/tests/*.test.tsx | wc -l grep -rn "EvidenceAuditPanel\|ClaimBoundaryBadge\|BirthTimeSoftNotice\|RawAppendixDownload\|think-step-gate\|document-view\|rectification-agentic/core/index" frontend/tests tests ``` ## 10. 交付物 - 分支 `codex/frontend-dead-code-20261013`;`docs/tasks/PROGRESS-frontend-dead-code-20261013.md`;`docs/BUG_HISTORY.md` 新号 + BUG-1004/953 追记;`BLOCKED.md` 划线;`CHANGELOG.md` 一行;`frontend/DESIGN.md` 一行修正(不是 UI 改动)。 ## 11. 后续阶段(本单不做) 1. `drizzle-orm` 依赖:`lib/db/client.ts` 删除后仓内零引用,但 `@better-auth/drizzle-adapter` 在 lock 里有 peer 关系,移除前需单独核实,另立单。 2. 疑似无前端调用方的路由(写作时字面量检索无命中,未核实是否被 Agent 工具/后台/运维使用):`/api/reports/[reportId]/professional-reference`、`/api/rectification/cases/[caseId]/{close,tie-break,upgrade-skill,adopt-skill}`、`/api/locations/search`。另立单逐个核实后再删。 3. 全站 `app/api/**/route.ts` 鉴权盘点(本单只删一个未鉴权入口;`chart-view`、`birth-sky` 在 service 内部鉴权,未在本单复核)。 4. `legacy-guided-v1` 旧协议退役(需存量数据迁移决策)。