AgentEvalTool/docs/archive/codebase-architecture-review-20260824.html
sinohqb 9588dcbfda
All checks were successful
CI / test (push) Successful in 3m22s
docs: 归档 2026-08-24 架构审查报告(Phase 5)
将本轮架构审查 HTML 报告按先例归档至 docs/archive/,并同步
登记 docs/README.md 与 docs/archive/README.md 索引。

本轮五个深化候选已全部落地:
- 候选① 智能作业结算统一(ADR-0012)
- 候选② 可见性接缝(require_live_eval 单一接缝)
- 候选③ storage/repository.py 拆分
- 候选④ 前端 ReadSlot 资源接缝
- 候选⑤ api.ts 拆分为 10 个域模块

刻意不做项(CAS 共享原语、db.py 拆分、app.py 关停顺序归一、
会话/任务状态机转换表)已在 v3 计划与 ADR-0012 中记录。
2026-08-24 05:54:54 +08:00

398 lines
27 KiB
HTML
Raw Permalink 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.

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>架构审查 · AgentEvalTool · 2026-08-24</title>
<script src="https://cdn.tailwindcss.com"></script>
<script type="module">
import mermaid from "https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs";
mermaid.initialize({ startOnLoad: true, theme: "neutral", securityLevel: "loose" });
</script>
<style>
body { font-family: -apple-system, "PingFang SC", "Helvetica Neue", sans-serif; }
.badge-strong { @apply bg-emerald-100 text-emerald-800 border-emerald-300; }
.iface { background:#fef3c7; border:2px solid #f59e0b; }
.impl { background:#0f172a; color:#e2e8f0; }
.impl-shallow { background:#e2e8f0; color:#334155; border:2px dashed #94a3b8; }
.seam { border-top:3px dashed #ef4444; }
.leak { box-shadow: 0 0 0 3px rgba(239,68,68,.35); }
pre.mermaid { background: transparent; }
</style>
</head>
<body class="bg-slate-100 text-slate-800">
<header class="bg-slate-900 text-slate-100 py-10 px-6">
<div class="max-w-6xl mx-auto">
<p class="text-emerald-400 font-mono text-sm mb-2">/improve-codebase-architecture · 第三轮</p>
<h1 class="text-3xl font-bold">架构审查总结 — AgentEvalTool</h1>
<p class="mt-3 text-slate-300 max-w-3xl">
2026-08-24 · 前两轮campaign v1.0、智能评估 v1.2)的候选已全部落地。本轮聚焦落地后新暴露与新残留的摩擦:
耐久作业结算序列、逻辑删除可见性、存储 monolith、前端读模型采纳面、api.ts 单文件。
</p>
<div class="mt-5 flex gap-6 text-sm flex-wrap">
<div><span class="text-2xl font-bold text-emerald-400">5</span> 深化候选</div>
<div><span class="text-2xl font-bold text-emerald-400">2</span> 已落地前轮v1.0 / v1.2</div>
<div><span class="text-2xl font-bold text-amber-400">3</span> 处"已删 eval 仍可见"泄漏</div>
<div><span class="text-2xl font-bold text-amber-400">1180</span> 行 repository.py · 12 个类</div>
</div>
</div>
</header>
<main class="max-w-6xl mx-auto px-6 py-10 space-y-12">
<!-- ============ 全景 ============ -->
<section>
<h2 class="text-xl font-bold mb-4">摩擦全景</h2>
<div class="bg-white rounded-xl shadow p-6">
<pre class="mermaid">
flowchart TB
subgraph BE["后端"]
IJ["intelligence_jobs.py<br/>两套手写结算序列"] --> AR["AsyncJobRepository<br/>claim/recovery 已深"]
R1["routers/intelligent_evals.py<br/>直 import ORM 表"] -.泄漏.-> VIS["逻辑删除可见性<br/>三处独立实现"]
DL["decision_logs._require_eval"] -.泄漏.-> VIS
REPO["storage/repository.py<br/>1180 行 · 12 类 · 5 域"]
APP["web/app.py<br/>手工编排 5 个 registry 关停顺序"]
end
subgraph FE["前端"]
READ["src/read 深模块<br/>仅 1 个消费者"] -.绕过.-> TABS["drawer 标签页群<br/>各自手写 fetch/polling"]
API["api.ts 909 行 · 12 域"]
end
classDef warn fill:#fef3c7,stroke:#f59e0b,stroke-width:2px;
class IJ,VIS,REPO,APP,TABS,API warn;
</pre>
</div>
</section>
<!-- ============ 候选 1 ============ -->
<section class="bg-white rounded-xl shadow overflow-hidden">
<div class="p-6 border-b border-slate-200 flex items-start justify-between gap-4">
<div>
<h2 class="text-2xl font-bold">① 耐久智能作业:结算序列收进单一执行器</h2>
<p class="text-slate-500 mt-1 font-mono text-sm">intelligence_jobs.py · AsyncJobRepository · campaigns 路由 · app.py</p>
</div>
<span class="shrink-0 px-3 py-1 rounded-full text-sm font-semibold border bg-emerald-100 text-emerald-800 border-emerald-300">Strong</span>
</div>
<div class="p-6 grid md:grid-cols-2 gap-8">
<div class="space-y-4 text-sm leading-relaxed">
<div>
<h3 class="font-semibold text-slate-900 mb-1">Files</h3>
<ul class="list-disc ml-5 space-y-0.5 text-slate-600">
<li><code>evaluation/intelligence_jobs.py</code> — 两个 executor53150、153263</li>
<li><code>storage/repository.py</code><code>AsyncJobRepository</code>782863</li>
<li><code>evaluation/campaign_runner.py:242-247</code><code>routers/campaigns.py:128-134</code></li>
<li><code>evaluation/comparison.py:245-280</code>(死代码 + 投影越界)</li>
</ul>
</div>
<div>
<h3 class="font-semibold text-slate-900 mb-1">Problem</h3>
<p>v2 计划已建出 <code>AsyncJobRepository</code>claim / recovery / orphan 结算都深),但<strong>编排序列仍按 adapter 手抄</strong>:分析与周期对比两个 executor 各自复制「缺则入队 → claim_queued → upsert(generating) → try/except → failed/completed」。错误截断 <code>str(exc)[:500]</code> 出现两次123、250正式线跳过守卫两处campaign_runner.py:242 与 intelligence_jobs.py:136分析触发校验在路由与 executor 各一份(周期对比已有共享入口,分析没有);<code>build_comparison_payload</code> 是零调用死代码且与 <code>_build_auto_baseline_payload</code> 逐字节相同。</p>
</div>
<div>
<h3 class="font-semibold text-slate-900 mb-1">Solution</h3>
<p>在执行器层提供单一深接缝 <code>execute(job_kind, work_fn)</code>入队幂等、认领、generating、失败归一截断、成功结算、重复触发幂等观察——全部收进 implementation。分析与周期对比退化为纯领域工作 adapter顺带删除死代码、把 <code>load_comparison_view</code> 投影移回读模型、分析校验对齐周期对比的共享入口。</p>
</div>
<div>
<h3 class="font-semibold text-slate-900 mb-1">Benefits</h3>
<p><strong>Locality</strong>:结算顺序知识(先认领再 generating、失败先归一再落库只住一处。<strong>Leverage</strong>:第三个作业类型只需一个 work adapter。测试面从"两套序列各测一遍"收敛为执行器接口一组契约测试 + 每 adapter 的纯领域测试。两个 adapter 已存在——这是真接缝,不是假想接缝。</p>
</div>
</div>
<div>
<h3 class="font-semibold text-slate-900 mb-3 text-sm">Before / After</h3>
<div class="grid grid-cols-2 gap-3 text-xs mb-4">
<div>
<p class="text-center font-semibold text-red-600 mb-2">Before · 序列手抄 ×2</p>
<div class="iface rounded p-2 text-center text-slate-800">长接口:调用方须知认领顺序 / 截断 / 幂等</div>
<div class="impl-shallow rounded p-2 mt-1 text-center">分析 executor~100 行编排</div>
<div class="impl-shallow rounded p-2 mt-1 text-center">对比 executor~110 行同形编排</div>
</div>
<div>
<p class="text-center font-semibold text-emerald-600 mb-2">After · 单一执行器</p>
<div class="iface rounded p-2 text-center text-slate-800">小接口execute(kind, work_fn)</div>
<div class="impl rounded p-4 mt-1 text-center">深 implementation<br>认领·结算·归一·幂等</div>
<div class="flex gap-1 mt-1">
<div class="flex-1 bg-slate-200 rounded p-1 text-center">分析 adapter</div>
<div class="flex-1 bg-slate-200 rounded p-1 text-center">对比 adapter</div>
</div>
</div>
</div>
<pre class="mermaid">
sequenceDiagram
participant C as 触发方(路由/自动)
participant E as execute() 深模块
participant W as work adapter
C->>E: execute(kind, work_fn)
E->>E: 幂等入队 + claim_queued
E->>E: upsert(generating)
E->>W: 领域工作(无 Session 编排)
alt 成功
E->>E: upsert(completed + 结果)
else 异常
E->>E: 归一 + 截断 + upsert(failed)
end
</pre>
</div>
</div>
</section>
<!-- ============ 候选 2 ============ -->
<section class="bg-white rounded-xl shadow overflow-hidden leak">
<div class="p-6 border-b border-slate-200 flex items-start justify-between gap-4">
<div>
<h2 class="text-2xl font-bold">② 智能评估可见性接缝:逻辑删除语义三处收敛为一</h2>
<p class="text-slate-500 mt-1 font-mono text-sm">intelligent_eval/repository.py · decision_logs.py · routers/intelligent_evals.py · task_queue.py</p>
</div>
<span class="shrink-0 px-3 py-1 rounded-full text-sm font-semibold border bg-emerald-100 text-emerald-800 border-emerald-300">Strong</span>
</div>
<div class="p-6 grid md:grid-cols-2 gap-8">
<div class="space-y-4 text-sm leading-relaxed">
<div>
<h3 class="font-semibold text-slate-900 mb-1">Files</h3>
<ul class="list-disc ml-5 space-y-0.5 text-slate-600">
<li><code>intelligent_eval/repository.py</code> — 可见性谓词重复 6 处103、117、130、137、147、171</li>
<li><code>decision_logs.py:30-33</code><code>_require_eval</code> 绕过 repo 直查 ORM</li>
<li><code>routers/intelligent_evals.py:73-80</code> — 第三份实现,且路由直接 import <code>IntelligentEvalDB</code></li>
<li><code>task_queue.list_tasks:330</code> — 删除不感知,监控面板泄漏已删评估</li>
</ul>
</div>
<div>
<h3 class="font-semibold text-slate-900 mb-1">Problem</h3>
<p>逻辑删除2d2c5a2一周前落地后「已删即 404」由<strong>三个独立实现</strong>分别裁决repo 的 <code>get()</code> 隐藏 + <code>get_including_deleted()</code><code>decision_logs._require_eval</code> 直查 ORM、路由 <code>_require_eval_exists</code> 再直查 ORM——路由跨过 repository 接缝直接握表,等于把删除语义焊死在 HTTP 层。附带浅点:配置快照 11 字段序列化 dict 在路由里逐字写了两遍399416、430442expired 会话的 Markdown 标注住在路由242252<code>count_decisions</code> 全量载入后 <code>len()</code>112121</p>
</div>
<div>
<h3 class="font-semibold text-slate-900 mb-1">Solution</h3>
<p>可见性收进 repository 单一谓词(内部 <code>_visible()</code>),对外只留 <code>require_live_eval(session, id)</code> 服务接缝——三处调用方改走它,路由删掉 ORM import。快照序列化与 expired 标注下沉到读模型投影;<code>count_decisions</code><code>func.count</code></p>
</div>
<div>
<h3 class="font-semibold text-slate-900 mb-1">Benefits</h3>
<p><strong>Locality</strong>:删除语义改动(如未来回收站、级联策略)只改一处。<strong>正确性</strong>:消除三处分歧风险——当前任务监控已实际泄漏已删评估。测试面:逻辑删除契约从分散的集成断言收敛为 repo 接口一组测试。这是新功能知识<strong>正在扩散</strong>的窗口期,越早收敛成本越低。</p>
</div>
</div>
<div>
<h3 class="font-semibold text-slate-900 mb-3 text-sm">Before / After</h3>
<div class="grid grid-cols-2 gap-3 text-xs mb-4">
<div>
<p class="text-center font-semibold text-red-600 mb-2">Before · 三处裁决"已删即 404"</p>
<div class="space-y-1">
<div class="bg-slate-200 rounded p-1.5 text-center">repo.get() 隐藏删除</div>
<div class="bg-red-50 border border-red-300 rounded p-1.5 text-center">decision_logs 直查 ORM</div>
<div class="bg-red-50 border border-red-300 rounded p-1.5 text-center">路由直查 ORMimport 表)</div>
<div class="bg-amber-50 border border-amber-300 rounded p-1.5 text-center">task_queue 完全不知情</div>
</div>
</div>
<div>
<p class="text-center font-semibold text-emerald-600 mb-2">After · 单一可见性接缝</p>
<div class="iface rounded p-2 text-center text-slate-800">require_live_eval(id)</div>
<div class="impl rounded p-3 mt-1 text-center">repository_visible 谓词 + get/get_including_deleted</div>
<div class="flex gap-1 mt-1">
<div class="flex-1 bg-slate-200 rounded p-1 text-center">decision_logs</div>
<div class="flex-1 bg-slate-200 rounded p-1 text-center">路由</div>
<div class="flex-1 bg-slate-200 rounded p-1 text-center">task_queue</div>
</div>
</div>
</div>
<pre class="mermaid">
flowchart LR
subgraph NOW["现状:三份语义"]
A["router 直查<br>IntelligentEvalDB"] --> D["DB"]
B["decision_logs<br>session.get()"] --> D
C["repo.get()<br>隐藏 deleted"] --> D
end
classDef bad fill:#fee2e2,stroke:#ef4444;
class A,B bad;
</pre>
</div>
</div>
</section>
<!-- ============ 候选 3 ============ -->
<section class="bg-white rounded-xl shadow overflow-hidden">
<div class="p-6 border-b border-slate-200 flex items-start justify-between gap-4">
<div>
<h2 class="text-2xl font-bold">③ 存储层 monolithrepository.py / db.py 按域拆分</h2>
<p class="text-slate-500 mt-1 font-mono text-sm">storage/repository.py1180 行)· storage/db.py709 行)</p>
</div>
<span class="shrink-0 px-3 py-1 rounded-full text-sm font-semibold border bg-amber-100 text-amber-800 border-amber-300">Worth exploring</span>
</div>
<div class="p-6 grid md:grid-cols-2 gap-8">
<div class="space-y-4 text-sm leading-relaxed">
<div>
<h3 class="font-semibold text-slate-900 mb-1">Files</h3>
<ul class="list-disc ml-5 space-y-0.5 text-slate-600">
<li><code>storage/repository.py</code> — 1180 行、12 个 repository 类、跨约 5 个域</li>
<li><code>storage/db.py</code> — 709 行、20 张表一个模块</li>
<li>对比项:<code>intelligent_eval/repository.py</code>510 行、单域)是良好范本</li>
</ul>
</div>
<div>
<h3 class="font-semibold text-slate-900 mb-1">Problem</h3>
<p>文件级 <strong>locality</strong> 欠佳目录Target/Scenario、执行Run/Result、评估活动Campaign + 两个智能作业、探索式评测ExplorationSession/Message同居一文件探索对10571163与异步作业仓库782996完全自包含却被迫与无关域共享导航成本。AI 与新成员定位"活动的 CAS 写入"必须扫过全部 12 个类。CAS 条件写模式也在此三度独立实现680739、802828 与 intelligent_eval 的 190248同文件却不共享原语。</p>
</div>
<div>
<h3 class="font-semibold text-slate-900 mb-1">Solution</h3>
<p>纯移动不改行为:拆出 <code>storage/exploration_repository.py</code><code>storage/async_job_repository.py</code>或随候选①并入执行器模块db.py 可暂不动(表定义集中有 create_all 的便利)。可选第二步:把三份 CAS 收敛为一个共享条件写原语——但需先过<strong>删除测试</strong>:三处的条件字段与冲突语义确有差异,只有当共享原语接口小到不泄漏这些差异时才值得。</p>
</div>
<div>
<h3 class="font-semibold text-slate-900 mb-1">Benefits</h3>
<p>每域一个文件 = 改动、bug、知识同址导航成本从"扫 1180 行"降到"开对应文件"。本身不产生 leverage故标记为 Worth exploring——它是其他候选①②的天然搭车项单独做价值有限。</p>
</div>
</div>
<div>
<h3 class="font-semibold text-slate-900 mb-3 text-sm">Before / After</h3>
<div class="text-xs space-y-3">
<div>
<p class="text-center font-semibold text-red-600 mb-2">Before · 一文件 12 类 5 域</p>
<div class="border-2 border-slate-400 rounded p-2">
<p class="text-center font-mono mb-1.5">storage/repository.py — 1180 行</p>
<div class="grid grid-cols-3 gap-1">
<div class="bg-sky-100 rounded p-1 text-center">Target</div>
<div class="bg-sky-100 rounded p-1 text-center">Scenario</div>
<div class="bg-violet-100 rounded p-1 text-center">Run</div>
<div class="bg-violet-100 rounded p-1 text-center">Result</div>
<div class="bg-emerald-100 rounded p-1 text-center">Campaign</div>
<div class="bg-emerald-100 rounded p-1 text-center">AnalysisJob</div>
<div class="bg-emerald-100 rounded p-1 text-center">ComparisonJob</div>
<div class="bg-rose-100 rounded p-1 text-center">ExplSession</div>
<div class="bg-rose-100 rounded p-1 text-center">ExplMessage</div>
</div>
</div>
</div>
<div>
<p class="text-center font-semibold text-emerald-600 mb-2">After · 每域一文件</p>
<div class="grid grid-cols-2 gap-1.5">
<div class="bg-sky-50 border border-sky-300 rounded p-1.5 text-center">catalog_repository</div>
<div class="bg-violet-50 border border-violet-300 rounded p-1.5 text-center">run_repository</div>
<div class="bg-emerald-50 border border-emerald-300 rounded p-1.5 text-center">campaign_repository</div>
<div class="bg-rose-50 border border-rose-300 rounded p-1.5 text-center">exploration_repository</div>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- ============ 候选 4 ============ -->
<section class="bg-white rounded-xl shadow overflow-hidden">
<div class="p-6 border-b border-slate-200 flex items-start justify-between gap-4">
<div>
<h2 class="text-2xl font-bold">④ 前端读取模块src/read 从单消费者扩展为统一资源接缝</h2>
<p class="text-slate-500 mt-1 font-mono text-sm">src/read/* · components/intelligent_eval/* · hooks/useCampaignReport.ts · hooks/useResource.ts</p>
</div>
<span class="shrink-0 px-3 py-1 rounded-full text-sm font-semibold border bg-emerald-100 text-emerald-800 border-emerald-300">Strong</span>
</div>
<div class="p-6 grid md:grid-cols-2 gap-8">
<div class="space-y-4 text-sm leading-relaxed">
<div>
<h3 class="font-semibold text-slate-900 mb-1">Files</h3>
<ul class="list-disc ml-5 space-y-0.5 text-slate-600">
<li><code>read/intelligentEval.ts</code>118 行,有测试)· <code>read/useIntelligentEvalRead.ts</code>83 行,有测试)</li>
<li><code>components/intelligent_eval/</code> — ExecutionProcess480 行、DecisionProcess、ConfigSnapshots、TaskQueueMonitor</li>
<li><code>hooks/useCampaignReport.ts:16-21</code><code>hooks/useResource.ts</code></li>
</ul>
</div>
<div>
<h3 class="font-semibold text-slate-900 mb-1">Problem</h3>
<p><code>src/read</code> 是一个<strong>真正的深模块</strong>ReadSlot 相位机、竞态守卫、静默刷新、可注入 adapter且有测试——但只有 IntelligentEvals.tsx 一个消费者,连它自己都绕过读模块做 mutation。五个 drawer 标签页各自手写同形 fetch 样板DecisionProcess:25-35、ConfigSnapshots:32-42、TaskQueueMonitor:39-50<code>ACTIVE_STATUSES</code> 定义两份;<code>ReadPhase/ReadSlot</code> 在 useCampaignReport.ts 里平行重造Blob 导出仪式重复三遍;同一份决策日志有三种新鲜度策略(父级 5s 轮询详情 + ExecutionProcess 独立 5s 轮询 + DecisionProcess 只挂载取一次。组件群零测试EvalReport / EvalOverview / DecisionProcess / ConfigSnapshots / TaskQueueMonitor</p>
</div>
<div>
<h3 class="font-semibold text-slate-900 mb-1">Solution</h3>
<p>把 ReadSlot 泛化为通用资源接缝(或强制 drawer 标签页走既有 <code>useResource</code> + 轮询门控),决策日志的新鲜度策略由父级读模块统一供给一次;常量与导出仪式各自归位单一出口。组件退化为纯渲染,状态经 props/reducer 注入。</p>
</div>
<div>
<h3 class="font-semibold text-slate-900 mb-1">Benefits</h3>
<p><strong>Leverage</strong>:竞态守卫、静默刷新、轮询暂停这些已写好且已测的行为,一次学习全组件受益。<strong>可测性</strong>:接口即测试面——五个零覆盖组件的测试从"mock 整个 api + 时序"变成对纯 reducer/props 的断言,这正是 sessionReducer 已验证的形状。深模块已存在、adapter 需求已出现campaign 报告平行重造)——符合"两个 adapter 才是真接缝"。</p>
</div>
</div>
<div>
<h3 class="font-semibold text-slate-900 mb-3 text-sm">Before / After</h3>
<div class="text-xs space-y-3">
<div>
<p class="text-center font-semibold text-red-600 mb-2">Before · 深模块闲置,样板四散</p>
<div class="flex gap-1.5">
<div class="w-1/3 impl rounded p-2 text-center self-stretch">src/read<br><span class="text-amber-300">深·有测试</span><br><span class="text-red-300">1 个消费者</span></div>
<div class="w-2/3 grid grid-cols-2 gap-1">
<div class="bg-red-50 border border-red-300 rounded p-1.5 text-center">ExecutionProcess<br>手写 5 个 fetch 槽</div>
<div class="bg-red-50 border border-red-300 rounded p-1.5 text-center">DecisionProcess<br>手写样板</div>
<div class="bg-red-50 border border-red-300 rounded p-1.5 text-center">ConfigSnapshots<br>手写样板</div>
<div class="bg-red-50 border border-red-300 rounded p-1.5 text-center">TaskQueueMonitor<br>手写样板</div>
</div>
</div>
</div>
<div>
<p class="text-center font-semibold text-emerald-600 mb-2">After · 资源接缝统一供给</p>
<div class="iface rounded p-2 text-center text-slate-800">useReadResource(slot, adapter) — 竞态/轮询/静默刷新内置</div>
<div class="grid grid-cols-3 gap-1 mt-1.5">
<div class="bg-slate-200 rounded p-1 text-center">列表页</div>
<div class="bg-slate-200 rounded p-1 text-center">5 个 drawer 标签</div>
<div class="bg-slate-200 rounded p-1 text-center">活动报告</div>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- ============ 候选 5 ============ -->
<section class="bg-white rounded-xl shadow overflow-hidden">
<div class="p-6 border-b border-slate-200 flex items-start justify-between gap-4">
<div>
<h2 class="text-2xl font-bold">⑤ api.ts 单文件按域拆分</h2>
<p class="text-slate-500 mt-1 font-mono text-sm">frontend/web/src/api.ts909 行 · 12 域)</p>
</div>
<span class="shrink-0 px-3 py-1 rounded-full text-sm font-semibold border bg-slate-200 text-slate-600 border-slate-300">Speculative</span>
</div>
<div class="p-6 grid md:grid-cols-2 gap-8">
<div class="space-y-4 text-sm leading-relaxed">
<div>
<h3 class="font-semibold text-slate-900 mb-1">Files</h3>
<p class="text-slate-600"><code>src/api.ts</code> — auth、targets、scenarios、modelConfigs、runs、reports、stats、exploration、campaigns、intelligentEvals16 个端点、files全部类型内联。</p>
</div>
<div>
<h3 class="font-semibold text-slate-900 mb-1">Problem</h3>
<p>v1.2 已点名的残留浅点。单文件本身不深不浅——axios 拦截器统一错误是真实深度——但 12 域同居迫使每次改动载入全部类型;报告 Markdown 下载的 DOM 副作用835843住在"接口定义单一出口"里属越界。注意:它是<strong>locality 问题而非 depth 问题</strong>,单独拆不产生 leverage。</p>
</div>
<div>
<h3 class="font-semibold text-slate-900 mb-1">Solution</h3>
<p>保留 <code>api/index.ts</code> 作为拦截器与 axios 实例的唯一住处(现有唯一出口语义不丢),各域拆为 <code>api/intelligentEvals.ts</code>Blob 导出仪式与候选④合并到同一个下载工具。</p>
</div>
<div>
<h3 class="font-semibold text-slate-900 mb-1">Benefits</h3>
<p>导航与 diff 噪声下降;域类型就近。无行为变化、无测试变化——因此只做搭车项,不单独立项。</p>
</div>
</div>
<div>
<h3 class="font-semibold text-slate-900 mb-3 text-sm">Before / After</h3>
<div class="text-xs">
<div class="border-2 border-slate-400 rounded p-3 mb-3">
<p class="text-center font-mono mb-2">api.ts — 909 行</p>
<div class="flex flex-wrap gap-1 justify-center">
<span class="bg-slate-200 rounded px-1.5 py-0.5">auth</span><span class="bg-slate-200 rounded px-1.5 py-0.5">targets</span><span class="bg-slate-200 rounded px-1.5 py-0.5">scenarios</span><span class="bg-slate-200 rounded px-1.5 py-0.5">modelConfigs</span><span class="bg-slate-200 rounded px-1.5 py-0.5">runs</span><span class="bg-slate-200 rounded px-1.5 py-0.5">reports</span><span class="bg-slate-200 rounded px-1.5 py-0.5">stats</span><span class="bg-slate-200 rounded px-1.5 py-0.5">exploration</span><span class="bg-slate-200 rounded px-1.5 py-0.5">campaigns</span><span class="bg-amber-100 rounded px-1.5 py-0.5">intelligentEvals +DOM 副作用</span><span class="bg-slate-200 rounded px-1.5 py-0.5">files</span>
</div>
</div>
<div class="text-center text-2xl text-slate-400 my-1"></div>
<div class="grid grid-cols-2 gap-1.5">
<div class="iface rounded p-1.5 text-center text-slate-800">api/index.ts<br>实例 + 拦截器</div>
<div class="bg-slate-200 rounded p-1.5 text-center">api/&lt;domain&gt;.ts ×11</div>
</div>
</div>
</div>
</div>
</section>
<!-- ============ Top ============ -->
<section class="bg-slate-900 text-slate-100 rounded-xl shadow p-8">
<h2 class="text-2xl font-bold mb-3">Top recommendation — 先做 ②</h2>
<p class="text-slate-300 leading-relaxed max-w-4xl">
<strong class="text-emerald-400">候选②(智能评估可见性接缝)应当第一个做。</strong>
理由有三:其一,逻辑删除是一周前刚落地的新功能,其领域知识<strong>正在扩散</strong>——三处独立实现 + 路由直 import ORM 表 + 任务监控已实际泄漏已删评估,每晚一天收敛成本更高;其二,它是五个候选里<strong>爆炸半径最小</strong>的——纯收敛、零行为变化、已有 +100 行集成测试做行为锁;其三,它顺带把快照序列化与 expired 标注移出路由,巩固 v1.2 已确立的"路由只做 HTTP 翻译"纪律。
</p>
<p class="text-slate-300 leading-relaxed max-w-4xl mt-3">
紧随其后做 <strong class="text-emerald-400">候选①</strong>(结算序列——真有两个 adapter接缝是真的③⑤ 作为搭车项,④ 作为前端独立战役(涉及组件改造与补测试,体量最大)。
</p>
<p class="text-slate-500 text-sm mt-5">词汇module / interface / implementation / depth / seam / adapter / leverage / localitycodebase-design领域名词取自 CONTEXT.md。</p>
</section>
</main>
</body>
</html>