fix(v2): 浏览器端到端验证——修掉模块页在浏览器里渲染不出内容的缺陷

首次用真实 Chrome 打开 /trajectory-center(新增可选脚本 scripts/browser-e2e.cjs),
暴露 5 个源码守卫与生产构建都看不出的缺陷,全部修复:

1. 三个模块页读 `list.items`,而 /projects 返回的是 {projects, identity}——
   项目列表恒为空,prescreen-workbench / experience-center / trajectory-center
   整页渲染不出任何面板,只显示"当前身份没有可访问的项目"这种看着正常的空态。
   (第二/三批引入)改为 list.projects。
2. TrajectoryPanel 没被传 identity,canRecord 恒假 → 会议结果录入表单永不出现。
3. ImprovementPanel 草稿下拉以组件 id 作 key/value,同一组件多版本草稿时撞 React key,
   且选不准要发布哪一版;改以 `组件id@版本` 为键值。
4. JSX 文本里的 `**强调**` 会原样显示星号(JSX 不渲染 Markdown),共 9 处;
   改为 <b>(字符串上下文处直接去掉标记)。
5. 深色导航模块名被 flex 压缩折行("AI 预审"断成两行);
   加 flex:0 0 auto + white-space:nowrap。

另修一个既有测试脆弱点:test_trajectory.py 的更正用例断言"哪条排前面",
两条记录同刻度时排序翻转,曾让 verify.py 偶发失败;改为断言"两条都在、更正指向旧记录"。

回归防线:第 5 项补进 test_module_shell_ui.cjs 源码断言;
test_ui_readability.cjs 的导航字号断言改为不把 min-height 钉在规则首位。

验证:scripts/verify.py 14/14 PASS(backend-unit 572 项),
证据 test-evidence/20261001-030127-ff59d7e/;scripts/browser-e2e.cjs 19/19 PASS
(截图在 test-evidence/e2e-batch4/)。该 E2E 脚本刻意不接入 verify.py。

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
2026-10-01 03:04:18 +08:00
co-authored by Claude Code
parent ff59d7e8f1
commit 4720d72965
14 changed files with 294 additions and 44 deletions
+4 -4
View File
@@ -128,7 +128,7 @@ export default function ExperienceCenter({project, identity, send}: any) {
<section className="xb-panel xb-wide">
<h2>① 来源:历史过程时间线</h2>
<p>时间线由项目材料**确定性**恢复,不调用模型、不编造经过。只有最终报告时会标"过程材料不完整",不生成虚构的问询顺序。</p>
<p>时间线由项目材料<b>确定性</b>恢复,不调用模型、不编造经过。只有最终报告时会标"过程材料不完整",不生成虚构的问询顺序。</p>
<div className="xb-actions">
<button className="ra-button" disabled={busy} onClick={buildTimeline}><RefreshCw size={15}/>从项目材料重建时间线</button>
{timeline && <span className="ra-badge">{timeline.status === "partial" ? "过程材料不完整" : "已恢复"} · {events.length} 个事件</span>}
@@ -153,7 +153,7 @@ export default function ExperienceCenter({project, identity, send}: any) {
<section className="xb-panel xb-wide">
<h2>② 提炼:用真实模型生成候选</h2>
<p>提炼会**实际调用**已配置的模型。模型不可用时明确记为未完成(E-28),并且**不产生任何候选草稿**——这里不会用一个固定返回值冒充提炼成功。</p>
<p>提炼会<b>实际调用</b>已配置的模型。模型不可用时明确记为未完成(E-28),并且<b>不产生任何候选草稿</b>——这里不会用一个固定返回值冒充提炼成功。</p>
<label className="ra-field"><span>提炼要求(可选,只约束本次加工,不成为正式制度)</span>
<input value={requirement} disabled={busy} placeholder="例如:重点整理现金流与利润不一致的核查方法"
onChange={(e) => setRequirement(e.target.value)}/>
@@ -177,7 +177,7 @@ export default function ExperienceCenter({project, identity, send}: any) {
<section className="xb-panel xb-wide">
<h2>③ 候选:专家修订、评测与发布</h2>
<p>修订只产生草稿,不直接生效;发布需要先通过隔离评测,并由**另一位**有发布资格的人操作。已发布版本不可覆盖,修订会升版本并保留父版本。</p>
<p>修订只产生草稿,不直接生效;发布需要先通过隔离评测,并由<b>另一位</b>有发布资格的人操作。已发布版本不可覆盖,修订会升版本并保留父版本。</p>
{!candidates.length && <div className="ra-empty"><h2>尚无知识候选</h2><p>先提炼或人工新增一张候选卡片。</p></div>}
{candidates.map((card: any) => <div className="xb-finding" key={card.id}>
@@ -237,7 +237,7 @@ export default function ExperienceCenter({project, identity, send}: any) {
<section className="xb-panel xb-wide">
<h2>④ 方案:让卡片真正影响后续核查</h2>
<p>卡片只有在被选入**已发布方案**后才会影响运行;运行结果会冻结并记录卡片版本,核查项可追溯到 <code>卡片id@版本</code>。</p>
<p>卡片只有在被选入<b>已发布方案</b>后才会影响运行;运行结果会冻结并记录卡片版本,核查项可追溯到 <code>卡片id@版本</code>。</p>
{!plans.length && <p className="ra-note">还没有项目自建方案。在上方已发布卡片上点"选入新方案"即可装配。</p>}
{plans.map((plan: any) => <div className="xb-finding" key={`${plan.id}@${plan.version}`}>
<div>