/** * 纠偏第二批 · 历史经验加工界面源码守卫(BR-48 / BR-49 / BR-50、AC-42/50/51/52)。 * * 这是**源码断言**,不是浏览器端到端测试(docs/v2/06-validation.md §2)。 * 它锁住四类可机械核对的约束: * * 1. **入口独立**:模块有自己的路由与导航项,不是旧页的第 7 个页签(BR-50)。 * 2. **来源徽标真的被用**:`originBadge` 必须被消费,且 .origin-* 样式与图标同时存在。 * ← 这条是补既有漏洞:此前该函数零调用方、无任何 CSS,而守卫只 grep 库文件字符串, * 于是"测试通过但功能不存在"。 * 3. **失败如实呈现**:E-28 未完成原因必须渲染,不得只显示成功态。 * 4. **不诱导违规**:同一身份既编辑又发布时不得出现发布按钮(自批由后端强制,界面不应提供)。 */ const assert = require("node:assert/strict"); const fs = require("node:fs"); const path = require("node:path"); const root = path.resolve(__dirname, ".."); const read = (file) => fs.readFileSync(path.join(root, file), "utf8"); const page = read("src/app/experience-center/page.tsx"); const panel = read("src/components/xingbang/ExperienceCenter.tsx"); const nav = read("src/components/xingbang/AgentNav.tsx"); const lib = read("src/lib/prescreen-run.ts"); const css = read("src/app/data-access/workspace.css"); // 1. 独立入口(BR-50:三个模块各有独立入口,不得只在旧页下叠加面板) assert.ok(fs.existsSync(path.join(root, "src/app/experience-center/page.tsx")), "历史经验加工应有独立路由"); assert.match(page, / css.includes(`border-left-style:${style}`)); assert.equal(borderStyles.length, 4, "四种来源应使用不同的左边框样式,保证去色后仍可区分"); // 3. 失败如实呈现:E-28 未完成原因必须渲染(AC-50 后半句) assert.match(panel, /degradations/, "提炼记录必须渲染降级/未完成原因"); assert.match(panel, /不产生任何候选草稿|不会用一个固定返回值冒充提炼成功/, "界面须说明模型不可用时不产生候选"); assert.match(panel, /item\.code/, "未完成原因必须带错误码,便于定位"); // 4. 不自批:同一身份不得看到自己的发布按钮(BR-42 / AC-43) assert.match(panel, /mayPublish/, "发布按钮必须经过「不自批」判定"); assert.match(panel, /card\.edited_by !== identity\?\.id|edited_by !== identity/, "不自批判据必须比较编辑人与当前身份"); assert.match(panel, /发布需要独立审核人/, "被隐藏发布按钮时应说明原因,而不是静默消失"); // 5. 系统沙盘/预审的既有禁令继续有效:这里也不得出现任何概率数值或演示情景表 for (const [name, source] of [["panel", panel], ["page", page]]) { assert.ok(!/0\.(42|58|51|64)\b/.test(source), `${name} 不得硬编码演示概率值`); assert.ok(!/"(00|10|01|11)"\s*:/.test(source), `${name} 不得复制演示情景表`); assert.ok(!/probability\s*[:=]\s*[0-9]/.test(source), `${name} 不得写入任何概率数值`); } // 6. 加工动作必须落在已定义的端点上,不自行拼 SQL 或绕过服务端 for (const endpoint of ["case-timeline", "knowledge-extractions", "knowledge-candidates", "review-plans"]) { assert.ok(panel.includes(endpoint), `加工中心应通过 ${endpoint} 端点读写`); } assert.match(panel, /PRESCREEN/, "必须走既有 prescreen 命名空间"); console.log("experience-center-ui: PASS");