Files
Jyotisha/docs/tasks/TASK-frontend-dead-code-20261013.md
T
Jesse_ChenandClaude Opus 5.5 0be4cb299c docs(tasks): code-health + performance audit briefs, 16 tasks (BUG-1323 onward)
Batch 1 (dispatch now): rect-scoring-perf, node-runtime-resources,
home-sidebar-rerender, api-disk-cache-retention, report-reference-perf,
consult-prep-parallel, frontend-dead-code.
Batch 2 (queued on predecessors): api-chart-subprocess-gate, answer-effort-ab,
consult-route-split, pl9-render-split, python-hygiene, dasha-unify,
api-server-service-extract, data-layer-types, contracts-helpers-dedupe.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014Ad9rqAB8pXXvyzh7f4X8v
2026-10-14 00:34:35 +08:00

194 lines
21 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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);`<BirthTimeSoftNotice` 否定断言;`report-actions` 不得出现 `RawAppendixDownload`;`step-answer` 对 `reasoning-delta` 一律丢弃(BUG-953)。删组件后,这些测试里**读被删文件源码的行**删掉,否定断言原样保留。
3. `ordinaryReportDownloadMarkdown` 与其 4 个测试不动;`report-export-blocks.test.ts` 的冻结 sha256 不动。
4. 改既有断言按 §7.3 写「原值 / 新值 / 原因」三栏注释;整条测试删除的,写进 PROGRESS「删除测试清单」。
5. 不改数据库结构与迁移(RPC `accept_agentic_rectification_candidate*` 等保留,只删 TS 调用方);`frontend/src/app/(app)/page.tsx` 不增长;`scripts/jyotish_api_server.py` 不增长(本单不碰);不改 `.gitea/workflows/**`;不升级、不删除依赖(`drizzle-orm`、`@mastra/*` 都不动)。
6. 不碰 `legacy-guided-v1` 相关文件(`birth-time-journey*`、`birth-time-scoring*`、`birth-time-legacy-rectification.tsx` 等)。
## 6. 任务分解
### T1 · 删旧 agentic 校正链(Grok 自跑 + Claude 复验)
- 删:`src/mastra/rectification-tools.ts`、`src/lib/rectification-agentic/session.ts`、`src/lib/rectification-agentic/date-range.ts`、`tests/rectification-agentic-tools.test.ts`(14 条)、`tests/rectification-agentic-session.test.ts`(16 条)。
- `tests/database-local-business.test.ts`:删第 11 行 import 与两处 `loadLatestAgenticRectificationResult(...)` 断言(约 842–852、1040–1043 行),同一测试里的 `psql` 权限断言、RPC 断言原样保留;三栏注释。
- 验收:`grep -rn "rectification-tools\"\|rectification-agentic/session\|date-range" frontend/src frontend/tests` 无结果;`tsc --noEmit` 0 错;**`npm run test:db` 由 Grok 跑**,失败清单与 `tools/agent-loop/windows-known-failures.txt` 逐条比对,多一条即未通过;Docker 没开就写「未跑」。
### T2 · 删旧报告阅读视图、think 门、评测、零引用组件与 barrel
- 删:`personal-report-document-view.tsx`、`think-step-gate.ts`、`agent-evals.ts` + `tests/agent-evals.test.ts`(11 条)+ `tests/fixtures/agent-golden-dataset-v1.json`、`birth-time-candidate-completion.ts` + 其测试(1 条)、`birth-time-life-events.tsx`、`evidence-audit-panel.tsx`、`claim-boundary-badge.tsx`、`birth-time-soft-notice.tsx`、`chart-library-view.ts`、`lib/db/client.ts`、`rectification-agentic/core/index.ts`、`rectification-agentic/v9/index.ts`、`tests/public-thinking.test.ts`(5 条)。
- 测试改写(三栏):
- `personal-report-view.test.ts`:删掉渲染 `PersonalReportDocumentView` 的用例(约 32–283 行之间,Grok 逐条判断:凡调用 `render(...)`/`PersonalReportDocumentView` 的删,测 `parseReportEnvelope`、路由、阅读页外壳、TOC、打印的保留)。若「v1/v2 fixture 通过契约解析」等用例只依赖 `personal-report-contract`,保留并去掉 view import。
- `personal-report-progress.test.ts:200-209`:去掉对 document-view 源码的两条断言,保留「章节名只定义一处」对其它文件的断言。
- `personal-report-export.test.ts:18-19, 49`:去掉 documentViewSource 读取与断言,`pageSource` 否定断言保留。
- `rectification-step-answer.test.ts:64-65`:去掉读 gate 源码两行,`reasoning-delta` 丢弃断言保留。
- `rectification-decide-next-action.test.ts:586-594`「core barrel re-exports…」:barrel 删除后整条删除(PROGRESS 列名)。
- `evidence-audit-panel.test.ts`、`claim-boundary-badge.test.ts`:删 `panelSource`/`badgeSource` 读取与对其的正向断言;对 `rowSource`/`contentSource` 的否定与 `TechniqueAuditDisclosure` 断言保留;对 `globals.css` 中 `.evidence-audit-panel`、`.claim-boundary-badge`、`.raw-evidence-receipt` 的「存在」断言删除(T5 删 CSS 时这些类将不存在)。
- `tests/test_repo_privacy_markers.py` `SAFE_LINES` 删 `frontend/tests/agent-evals.test.ts` 一项(文件已删;参数化用例少 1 条,PROGRESS 列名)。
- 验收:再跑 §1 脚本,输出只剩 `personal-report-longform-download.ts`;`tsc --noEmit` 0 错;`npm run lint` 0 error(预期 warning 减少 2 条:`birth-time-candidate-completion.ts:10,11`);改到的测试文件单跑 fail=0、cancelled=0;`.venv` 下 `pytest tests/test_repo_privacy_markers.py -q` 通过。
### T3 · 删三个无调用方接口(含本单 BUG)
- 删:`src/app/api/birth-rectification/route.ts`、`src/lib/birth-rectification-payload.ts`、`src/app/api/birth-time-candidate-completion/route.ts`、`src/app/api/reports/[reportId]/raw-appendix/route.ts`、`src/components/personal-report/raw-appendix-download.tsx`、`src/lib/personal-report-raw-appendix.ts`。
- `tests/test_daily_and_rectification_entrypoints.py::test_birth_rectification_api_proxies_active_questionnaire_with_boundary` **改写为否定合同**(测试数不降):断言 `frontend/src/app/api/birth-rectification/route.ts` 不存在,且 `frontend/src/app/api` 下没有任何 route 源码含 `/api/active_rectification_questions`。三栏注释(原值:钉住代理源码;新值:路由不存在且无代理;原因:本单 BUG,未鉴权的重计算入口)。
- `global-birth-profile-routes.test.ts:43-49`:删 `payloadFromProfile` 那段断言与 import,daily/synastry 断言保留;三栏。
- `tests/personal-report-raw-appendix.test.ts`:整文件删除(4 条 + 11 条路由守卫参数化)。
- `tests/personal-report-density-retry.test.ts`:第 9、33、55、124 行使用 `releaseRawReportAppendix`。Grok 逐条判断:只为验证原始附录输出的断言随之删除;验证快照写入/恢复本身的断言保留(把对 `releaseRawReportAppendix(...)` 结果的检查改成对快照字段的检查,不得弱化快照合同);每处三栏。若无法在不弱化的前提下改写,**本条退回**:保留 `personal-report-raw-appendix.ts`(仅删路由与组件),写进 PROGRESS。
- 验收:`grep -rn "birth-rectification\b\|birth-rectification-payload\|birth-time-candidate-completion\|raw-appendix\|releaseRawReportAppendix" frontend/src` 无结果(`birth-rectification-card` 否定断言在 tests 中仍在);`.venv/bin/python -m pytest tests/test_daily_and_rectification_entrypoints.py -q` 通过;相关前端测试单跑通过。
### T4 · 记录(Grok)
- `docs/BUG_HISTORY.md`:
- 新增本单 BUG(标题建议:「未登录即可调用 `/api/birth-rectification`,每次触发约 20 秒、不受闸门限制的引擎计算」),状态 `resolved(分支)`,写实测数字、根因、修复(删除)、验证(否定合同测试)、防复发(新增 `app/api/**/route.ts` 必须鉴权或显式列为公开;重计算路径必须进 `HEAVY_COMPUTE_PATHS`——本单只记录,不改 gate 文件)。
- BUG-1004 追加「2026-10-13 `frontend-dead-code` 完成 09-24 D2 删除」一行;BUG-953 追加「`acceptThinkStepText` 最后调用方 BUG-1053 移除,10-13 删除」一行。
- `BLOCKED.md` 第 631 行附近 `birth-time-candidate-completion.ts:10,11` 两条 warning:划掉并注明已随文件删除(不删原文)。
- `frontend/DESIGN.md:1084`「个人报告页走 `personal-report-document-view.tsx`」改为 `personal-report-markdown-view.tsx`。
- `docs/tasks/PROGRESS-frontend-dead-code-20261013.md`:删除文件清单(路径 + 行数)、**删除测试清单**(文件 + 测试标题 + 原因)、改写断言三栏汇总、`test:db` 比对结果、§1 脚本前后输出。
- `CHANGELOG.md`:一行「删除三个无调用方接口(含一个未鉴权的重计算入口)与约 3,000 行死代码」,Skill 版本不 bump。
### T5 · 死 CSS(可砍)
- 只删**选择器里的类名在 `frontend/src/**/*.{ts,tsx}` 中 0 引用**的规则:预期包括 `globals.css` 497–506 行(`.claim-boundary-badge`、`.evidence-audit-panel*`、`.raw-evidence-receipt*`)与 1148 行 `.birth-time-life-events`。`.personal-report-document` 等被 Markdown 阅读页共用的类**不得删**。每删一个类前 `grep -rn "<类名>" 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` 旧协议退役(需存量数据迁移决策)。