Files
novalon-website/docs/acceptance/qa-tracker.md
T
zhangxiang a0328a623f chore(qa): 验收台账与证据入库 + 构建/部署配置同步
- docs/acceptance/qa-tracker.md:跨周期缺陷单一真源台账(§7=第五轮)。
- 周期 1/2 + iPhone SE/axe 验收证据目录、ACCEPTANCE_REVIEW 快照入库。
- 同步 README/CONTEXT/CLAUDE/DESIGN/testing/deployment/lessons-learned 口径;
  next.config/Dockerfile/nginx/Jenkinsfile/docker-compose/sentry/prisma 对齐
  standalone 产物装配与部署形态。
2026-09-28 10:48:09 +08:00

49 KiB
Raw Blame History

QA 问题跟踪台账(系统性质量保障 · 单一真源)

  • 分支:refactor/optimize-ui HEAD:f543e47(本台账所引用的全部修复仍只存在于工作树,未提交)
  • 工作树状态(2026-09-25 实测):git status --porcelain = 363 条(47 条未跟踪)
  • 上游报告:
    • 周期 1:docs/acceptance/2026-09-23-gates/final-verdict.md(发现 N-1…N-33;对 2026-09-21 阻断 A-/R-/B-* 的闭环)
    • 周期 2:docs/acceptance/2026-09-23-cycle2/final-verdict.md(新增表现层/领域层轴:A-1…A-4、C-1、P-*、D-1(defect)、L-1…L-5、Sentry 接线;决策清单 D-1…D-11)
  • 本台账的作用:把上述分散编号统一到一处,作为「问题跟踪机制」的执行面;不重复两份报告的证据叙述,只登记状态 + 归属阶段 + 闭合阻塞项。
  • 编号消歧:周期 2 的缺陷 D-1(detail-trust-section)与决策清单 D-1(入库)同名,本台账分别记为 DEF-D1(缺陷)与 AUTH-D1(决策/授权项)。

0. 验收判定(对齐 objective 五阶段)

objective 阶段 交付物 状态
1 代码审查 两份周期报告 + 本台账 §1 已达成(多轴、subagent + 主线逐条复核)
2 测试 门禁实测表(周期 1 §1 / 周期 2 §0)+ docs/testing.md 已达成(可自主执行的门禁全部出数;写库/基线/线上/全量变异等需授权项见 §3)
3 修复 + 跟踪机制 本台账(单一真源) 机制已建立;修复的可复现性未达成(未入库)
4 优化 性能(Lighthouse 9/9=100、a11y 节点计数、限流键、死资源清理)+ 安全(提权/XSS/越权/令牌/开放重定向) 已达成,余留项见 §2/§3
5 验收确认 本报告 + 门禁凭据 未达「可判验收通过」——唯一阻断为交付形态(AUTH-D1 未入库),非代码质量

结论不变(承接周期 1「有条件通过」/周期 2「未达可判验收通过」):技术面已闭环并有实测凭据;验收不能判完成的唯一实质原因是 §3 AUTH-D1(约 363 条改动未提交,评审者/CI/下一位开发者无法复现本台账任何结论)。

2026-09-28 更新:第三/四/五轮(§4/§5/§7)在此结论上继续累积修复(第五轮再修 S-21/S-22/Q-10②/S-3 两个 P2 + 12 个 P3,全带判别测试与门禁凭据),未提交的工作树现 394 条——AUTH-D1 仍是唯一硬阻断。

1. 本台账建立时的独立复核(trust-but-verify,2026-09-25)

对最高后果的 12 项「已修」声明做了只读源码复核(读当前工作树,未采信报告自述),结论:

ID 声明 复核结果 证据(本次亲读)
N-18 draft/disable 开放重定向防护 CONFIRMED src/lib/cms/internal-redirect.ts:8;disable/route.ts:13-21 先校验后副作用
N-19 admin/stats 越权读取 CONFIRMED src/app/api/admin/stats/route.ts:11 用 requirePermission('content-model','read')
N-20 停用账号令牌仍可用 CONFIRMED src/lib/permissions.ts:41-45 读 User.status,早于 :52 的 super_admin 短路
N-25 限流 XFF 伪造绕过 CONFIRMED src/lib/client-ip.ts:14-23 优先 x-real-ip、XFF 取最右;contact/route.ts:4,51 消费
N-22 安全头门禁恒不成立 CONFIRMED check-security-headers.ts:63-78,101,128-132 cookie 状态按 flag 推导并计入退出码;缺 CSP=fail;HSTS 分 http/https
N-1 JSON-LD </script> 注入 CONFIRMED src/components/seo/structured-data.tsx:8-9 jsonLd() 转义 </>,8 个 sink 全用
DEF-A1..A4 后台编辑器定位/守卫 CONFIRMED admin/content/[modelCode]/[itemId]/page.tsx id 过滤 + itemNotFound(:691) + canEdit(:252,736,917) 收口
C-1 案例页缺键整页崩溃 CONFIRMED(边界归一) 归一在唯一 importer (marketing)/cases/[slug]/client.tsx:22,30-35,恰在未受信任 CMS 强转处;报告所称组件文件为归属笔误,非漏洞(见 §2.2 REG-C1)
L-5 媒体派生命名冲突 CONFIRMED src/lib/media/image-processor.ts:75 追加 Math.random() 后缀
L-1 admin-api 吞掉 4xx/5xx CONFIRMED src/lib/admin-api.ts:85-102 解密后按 res.ok 抛错
N-4/5/6 保存/发布状态通道 CONFIRMED 保存载荷无 status;发布走 runWorkflow;POST 拒非 draft
DEF-D1 指标前导符号错位 CONFIRMED detail-trust-section.tsx:26-48 用 [^0-9.] 否定类 + prefix/suffix 分列

Sentry 接线亦复核为真:src/instrumentation.ts、src/instrumentation-client.ts 存在且 import @sentry/nextjs;next.config.mjs:131 export default withSentryConfig(nextConfig)。 覆盖扫描(非定点复核):src/+scripts/ 内无条件 status:'pass' as const = 0;\|\| echo = 12(均在 CI/部署 shell 的信息性回退,非门禁判据);e2e/*.spec.ts 内 if (.count()>0) 守卫 = 11 处(周期 1/2 已逐条定性为视口/角色合法分支,见 N-27)。

2. 缺陷登记(按闭合状态分组)

图例 · 状态:FIXED-UNCOMMITTED=已修且§1或原报告有 RED/GREEN 凭据,但未入库;DECISION=待产品/设计裁定;AUTH=待单独授权动作;RECORDED=已知、诚实披露、本轮不动。

2.1 已修复(代码在工作树内,含 §1 复核标记)

ID 级别 类别 摘要 状态 凭据
N-18/19/20/25 P1 安全 开放重定向 / 越权读取 / 停用账号令牌 / 限流绕过 FIXED-UNCOMMITTED §1 全部 CONFIRMED + 原报告 RED 实测
N-22 P1 门禁可信度 安全头门禁恒不成立断言 FIXED-UNCOMMITTED §1 CONFIRMED + 双向对照
N-1 P1 安全 JSON-LD 存储型 XSS 面 FIXED-UNCOMMITTED §1 CONFIRMED
N-4/5/6/7 P0/P1 功能 后台保存必 400 / 发布必失效 / 状态死控件 / 状态回写 FIXED-UNCOMMITTED page.test.tsx
N-9 P0 门禁可信度 standalone 产物缺 dist/static(CSS 404) FIXED-UNCOMMITTED postbuild 落地
N-11 P2 性能/BP /contact CSP 违规(Zod eval 探测) FIXED-UNCOMMITTED z.config({jitless}) + Lighthouse A/B
N-12 P1 门禁可信度 补测自身把 rAF 变只读致套件静默不跑 FIXED-UNCOMMITTED 隔离复跑
N-17 P2 测试诚实性 security-headers 裸 return 伪装通过 FIXED-UNCOMMITTED 68 passed + 4 skipped
N-24②③④ P2 门禁可信度 404 即就绪 / 不受支持的 next start / pr-checklist 空转 FIXED-UNCOMMITTED 双向对照
N-27(部分) P2 测试装配 零断言用例 / expect()||expect() JS bug / 死选择器 FIXED-UNCOMMITTED 四 project 实测
N-30(删兜底) P1 内容零编造 两处凭空 40% 兜底已删(含反转被锁死的测试) FIXED-UNCOMMITTED 23→23 通过
N-31 / N-33(部分) P2 文档一致性 不可执行命令 / 假阈值 / 口径回填 FIXED-UNCOMMITTED 机械比对
A-1..A-15, R-1..R-5, B-1/3/4/7 P0-P2 安全/功能/规范/UI 2026-09-21 阻断项 FIXED-UNCOMMITTED 周期 1 §2
DEF-A1..A4, C-1, P-1/4/5, DEF-D1, L-1, L-5 P1-P2 表现/领域层 后台编辑器数据损毁 / 案例页崩溃 / 滑动 / 进度条 / 前导符号 / 错误吞没 / 命名冲突 FIXED-UNCOMMITTED 周期 2 §1;C-1 见 §2.2 REG-C1
Sentry 接线 P1 可观测性 「声明未接线」→ 已接(含 Turbopack 约定文件) FIXED-UNCOMMITTED 周期 2 §1.3;§1 复核存在
N-24① P2 门禁可信度 axe 逐页状态断言(期望集感知) FIXED-UNCOMMITTED 周期 2 §3.7 双向对照

2.2 待产品 / 设计决策(代码侧不该替业务作答)

ID 级别 事项 入口
REG-C1 P3(已复核,非活跃缺陷) C-1 归一在 cases/[slug]/client.tsx:22,30-35(唯一 importer),位置正确:恰在未受信任的 CMS 强转 item.data as unknown as CaseStudyData 边界处 ?? ''/?? [] 一次归一,case-detail-page.tsx 消费已定型 props 可信任(无第二个真实调用方)。周期 2 报告把它记在组件文件属归属笔误,非漏洞;不在组件内加冗余守卫(违反"不为不可能发生的场景加校验") 仅更正周期 2 §1.2 的 file:line 归属
DEC-N21 P2→潜伏 'content-item' 幻影 modelCode:周期 2 §5.3 以源码推翻「越权」定性,实为 fail-closed;真风险是将来被补进种子即成跨模型读取闸口。建议「缺 modelCode ⇒ 400」 admin/items/route.ts:79
DEC-N21b P2 /admin 无服务端 gating(仅客户端跳转),HTML 外壳无会话也下发;数据 API 已守卫 无 middleware.ts
DEC-N30 P1 四条互斥 SLA(工作日 2h / <4h / 48h / <2h·7×24)留哪一条 周期 1 §8.2 / 周期 2 §5.2
DEC-D5 P1 /products/erp-upgrade 在线数字(99.2%/40%+/从5天到1天)在活组件 erp-upgrade-content-v2.tsx:63,69,77,无 basis 无 MetricsBasisNote,且该路由无视觉基线 周期 2 §5.1
DEC-D7 P2 news 正文字段声明 richtext 而 renderField 无该分支(能力缺口) 周期 2 §5.3
DEC-P2-motion P2 动效门禁 23 处判红(20 缓动曲线 + 2 裸时长 + --transition-gentle:1000ms):改代码 or 承认为设计例外 周期 2 §3.5
DEC-L3 P3 client-ip.ts 头部信任无条件;直暴露(非 nginx)时限流可被 X-Real-IP 自报绕过(须与部署协同,勿单独改) 周期 2 §5.3
DEC-L4 P3 对称加密密钥来自公开 bundle 的 NEXT_PUBLIC_ENCRYPTION_SECRET ⇒ 仅混淆无机密性,文档口径不得当安全控制引用 crypto.ts:36
DEC-P-2 P3 死码族删除(loading-state 是 brand-token 唯一白名单豁免 N-8;另有 hero-section-v2/insight-card/industry-grid/三份 product-card/breadcrumb/micro-interactions/PullToRefresh 等) 周期 2 §5.3
DEC-N4-N23 P1 安全头门禁默认打线上 novalon.cn 而非本分支产物(声明与行为相反);改法涉 CI/test:all 语义 周期 1 N-23

2.3 待授权动作(阻塞验收;须逐项明文批准)

ID 动作 命令 为何阻塞
AUTH-D1 入库 / PR(验收唯一硬阻断) 先 git fetch origin dev 取真值 → 裁定双向分叉(周期 1 记 30↔31,两端同标题异 hash)重复提交对 → 按 5 组分笔提交 → Gitea PR(过 check-pr-checklist.sh) 约 363 条改动只在工作树 ⇒ 本台账/两份报告结论均不可复现。⚠ 分叉非快进整理,须先 fetch 再判
AUTH-D2 重跑 seed npm run db:seed 使 L-2(seed 权限过期)修复对数据生效;现网 dev.db 仍为旧权限行
AUTH-D3 视觉基线写入 npx playwright test visual-regression.spec.ts --update-snapshots 20 例缺参照恒红 + erp-upgrade/about/brand/cases/[slug] 三路由从无基线;追认现状需人工核看 85 张差异
AUTH-D4 写库 E2E 完整 npm run test / test:e2e:prod(差 cms-workflow+user-journey 共 11 例) 真写 prisma/dev.db;只读边界已实证,此 11 例是唯一未执行的功能层
AUTH-D9 Sentry 实投递 真实 DSN 起服务验证事件与 source map 上传 接线惰性有码路证据已足,但投递未线上验证
AUTH-D10 全量变异测试 去 --inPlace(config 默认沙箱)跑 mutate 全集 成本/磁盘(峰值 1.7G 曾致 ENOSPC,周期 2 §3.9);须 ≥2G 余量与无并发门禁窗口
AUTH-D11 门禁证据落盘 check:axe 默认 OUT 按日期分目录(同步 Jenkinsfile);docs/acceptance/** 是否纳入版本控制 现固定目录互相覆盖证据且未跟踪(周期 2 §3.9)

2.4 已知不稳定清单(禁止用 retry / 放宽阈值「修」)

  • mobile-user-journeys UJ-10(firefox,隔离复跑通过)、website-acceptance:111 响应式(隔离通过)、@accessibility webkit 四例(周期 1 N-32,隔离不复现)。同属并发 / 墙钟族(周期 1 N-28:同一代码三轮失败数 8→1→5)。墙钟型用例(p4:31、p4:68)不该进共享并发门禁。

3. 提交前强制提醒(承接 memory 纪律)

  • 提交只加自己的路径,勿 git add -A:prisma/dev.db-shm/-wal 未被 .gitignore 覆盖(周期 1 §7),git add -A 会把 SQLite 边车与陈旧 dev.db/data.db(周期 2 §3.9)扫入。
  • 破坏性 / 共享状态动作(fetch/rebase/commit/push/merge/seed/写库 E2E/写基线/force-push)须单独明文授权,不夹带在常规变更里。
  • 会话结束前披露工作树状态(本台账 §0/§2.3 AUTH-D1 即披露)。

4. 第三轮审查轴(2026-09-25 本会话,subagent 并行 + 主线逐条复核)

两条并行 subagent:① 全部 src/app/api/** 路由处理器安全/正确性审计;② src/lib/**+src/components/** 逻辑缺陷狩猎。均要求 CONFIRMED 附 file:line + 触发条件,并给出已知项围栏以防重报。主线未照抄任何一条子代理结论:定点复核 → 对拟修复项做 RED→GREEN。

4.1 主线已复核确认 + 已修 + RED 测试(工作树内,未提交)

ID 级别 缺陷 触发/影响 修复 RED→GREEN 凭据
Q-1 P1 登出未清除服务端 httpOnly cookie:auth-context.tsx logout() 只清 localStorage;但 login 经 setTokenCookie 写 novalon_token(24h)/novalon_refresh(7d),而 authenticateRequest(auth.ts:74) 回退读 cookie。/api/auth/logout 路由存在却从无调用者 ⇒ 点「登出」后全站受守卫 API 仍凭 cookie 放行至多 24h/7d 后台「登出」是假登出;共享/被盗机器上会话延续 logout() 先 POST /api/auth/logout(触发 clearTokenCookie),网络失败也清本地并跳转 新增 auth-context.test.tsx(2 例):断言 fetch 到 /api/auth/logout+POST 与网络失败仍清理;改前 1 failed(fetch 0 calls)→ 改后 2 passed
Q-2 P2 缩略图格式伪标:image-processor.ts thumbnail 声明 ext 'webp'(buildDerivative(..., 'webp', ...))但缓冲只 .resize().toBuffer() 未调 .webp() ⇒ PNG/JPEG 上传的 -thumbnail.webp 实为原格式字节,Content-Type 与内容不符、零 WebP 压缩收益 落盘文件内容 ≠ 扩展名/MIME;source type 消费方受影响 缩略图管道加 .webp({quality:80}) 既有测试只断路径/尺寸、从不验格式(覆盖空洞);新增例断 sharp(thumb.buffer).metadata().format==='webp'(PNG/JPEG 双输入);改前 Received:"png" → 改后 media 4 套件/60 例全通过
Q-3 P2 登录端点无限流:contact 有 IP 限流但 POST /api/auth/login 无任何节流 ⇒ 匿名者可无限驱动 cost-10 bcrypt(CPU DoS)+ 离线式撞库 凭据填充 / CPU 耗尽 抽出可复用 src/lib/rate-limit.ts(时钟可注入 + reset(),放进覆盖率棘轮内),登录按 IP max:10/15min 且判定在 bcrypt 之前;contact 重构复用同一实现(消除副本) 新增 rate-limit.test.ts 4 例(边界/独立 key/窗口过期/reset)+ 扩展 login/route.test.ts 一例:前 10 次 200、第 11 次 429 且 verifyPassword 仍只 10 次(证限流省掉 bcrypt);4/4 + 全 login/contact/auth 73 例通过,type-check EXIT=0,改动文件 eslint --quiet 0 error
Q-4 P2 停用账号令牌在 6 个内联 role handler 仍全权(N-20 同类,绕开已收口的 checkUserPermission):admin/users GET/POST/PUT/DELETE 与 admin/roles GET/PUT 用 authenticateRequest(仅验签名,不看 User.status)+ 内联 userRole 检查。⇒ 被停用但持 ≤24h 有效令牌的 super_admin 仍能列/建/改/删用户、重写权限矩阵 停用/离职管理员的残留令牌保留完整后台写权 抽出可复用 authenticateActiveRequest(request)(permissions.ts,prisma.user.count({id,status:1}) 判活),6 个 handler 全部改用它并在角色检查/任何写入前 fail-closed 在 users/route.test.ts 与 roles/route.test.ts 各加 2 例(停用超管 → 401 且 user.create/user.update/$transaction/permission.* 均未触达);既有 30+ 例在默认存活下保持通过 ⇒ admin users/roles/permissions 3 套件/54 例全绿,type-check EXIT=0,5 改动文件 eslint --quiet 0 error
Q-5 P2 响应式网格被 StaggerReveal 单子吞成单列:content/sections.tsx 的 TechStackShowcase/DataProofSection 把 grid md:grid-cols-N 挂在外层 div,而该 div 的唯一子元素是 StaggerReveal(渲染一个 motion.div,再为每卡片包 motion.div)⇒ 网格只有 1 个网格项,卡片在 md/lg 断点堆成单列、gap/space-y 失效;FAQSection 的 space-y-3 同理被吞。这些组件是活的(product-detail-content-v3.tsx:335,343,357 渲染产品详情页)。正确写法见 l3-signals-slot.tsx:109-119(网格类挂 StaggerReveal,其注释即记此坑) 产品详情页技术栈/数据佐证/FAQ 桌面端单列,UX 退化 把网格/间距类移到 StaggerReveal className,删除多余外层 grid div(FAQ 仅移 space-y-3,保留 col-span 外层) 在 sections.test.tsx 加 3 例,断言 [class*="grid-cols-3"]/grid-cols-4/space-y-3 元素的直接子元素数 == 条目数(旧结构下恒为 1 ⇒ RED);sections.test 28 例全通过,type-check EXIT=0,eslint --quiet 0 error
Q-7 P3 列表路由分页参数未校验(NaN→500 + 无界 take):admin/items GET 用 parseInt(searchParams.get('page') || '1') ⇒ ?page=abc→NaN→skip:NaN→真库 Prisma 抛错→500(应安全回落);?pageSize=99999→无界 take(任何 read 权限者可整表拉取大 data JSON)。admin/users GET 有 Math.max/min 夹取但 Math.max(1,NaN) 仍是 NaN ⇒ 同类未愈 500 崩溃 + 无界读取 抽出可复用 src/lib/pagination.ts parsePagination(sp,{defaultPageSize,maxPageSize})(NaN/0/负数→默认,超上限→夹取,取整),items + users 两路都接入(max 100) pagination.test.ts 6 例(缺省/合法/非数字回退/夹取/取整,含"移除即崩"的核心 NaN 面)+ items/route.test.ts 1 例(?page=abc&pageSize=99999 ⇒ 200 且 findMany({skip:0,take:100}),旧码为 skip:NaN/take:NaN ⇒ RED)。pagination 6 + items 38 + users 18 全通过,type-check EXIT=0,改动文件 eslint --quiet 0 error
Q-8 P3 内容 ID 存在性枚举 oracle:admin/items PUT/DELETE 与 admin/items/[id]/workflow POST 都先 contentItem.findUnique→notFound('内容不存在') 再 requirePermission ⇒ 匿名调用者可用「404=该 ID 存在 vs 401/403=权限屏障」枚举有效内容 ID(无写入先于鉴权,纯信息泄露面) 未鉴权可枚举内容 ID 三个 handler 均在存在性探针之前加 if (!authenticateRequest(request)) return unauthorized();(先认证→再 404→再 per-model 权限),关闭匿名枚举;记残留:已登录但无该模型权限者仍能分辨 404/403(把 notFound 与 forbidden 合流需改契约,未做) items 2 例 + workflow 1 例:匿名 PUT/DELETE/workflow ⇒ 401 且 findUnique 未被调用(证探针在认证门之后);两测试文件补 jest.mock('@/lib/auth') 默认有效会话使既有授权用例不受影响 ⇒ items+workflow+pagination 3 套件/47 例全通过,type-check EXIT=0,5 改动文件 eslint --quiet 0 error
Q-10a P3 ui/button.tsx 涟漪 id 用 Date.now():同毫秒两次点击 ⇒ 重复 React key + 清理 filter(r=>r.id!==id) 会一次删掉同 id 的多条涟漪;且 600ms setTimeout 卸载时从不清除(setState-after-unmount / 定时器泄漏)。Button 是全站在用组件 真实浏览器下重复 key 告警 + 卸载后定时器泄漏 涟漪 id 改自增 useRef 计数器(保证唯一);定时器收入 useRef 数组,useEffect 卸载时 clearTimeout 全部 诚实标注:真正判别性(重复 key)在本环境不可测——做过 RED 探针(还原 Date.now() 后断言仍绿),因 Jest 跑 production React 构建、dev key 告警被剥离,React 18 也不再就 setState-after-unmount 告警。故只补被改代码路径的行为用例(点击→涟漪出现→600ms→清除,能捕获"永不清除/不出现"类回归),不谎称它是缺陷锁。button 21 例通过,type-check EXIT=0,eslint --quiet 0 error
Q-10c P3(隐私/同意 fail-open) analytics.ts getStoredPreferences 把 JSON.parse(...) as CookiePreferences 原样透传,无字段校验:而 updateConsentDetailed 用 preferences.analytics ? 'granted':'denied' 判定 ⇒ 被篡改/写坏的 localStorage(如 {"analytics":"yes","marketing":1},或数组/数字等非对象)会以真值非布尔意外授予 analytics/ad 同意 同意管理可被污染存储绕过(GDPR/隐私面) 新增 sanitizePreferences(raw):四个开关严格 === true 才算同意(否则 false),necessary 恒真,timestamp 仅数字保留;getStoredPreferences 走它 2 例真判别(未修即 RED:旧码原样返回 'yes'/1,断言 false 必红):truthy 非布尔→false、非对象载荷→全 false 且 necessary 恒真;既有有效对象用例({necessary:true,analytics:false,marketing:true,functionality:true})经 toEqual 仍通过 ⇒ analytics 31 例全通过,type-check EXIT=0,eslint --quiet 0 error
Q-10b P3 api-crypto.ts 用客户端 content-length 判定是否有请求体:hasBody = contentLength && parseInt(contentLength) > 0。加密的 POST/PUT/PATCH 若走分块传输(无 content-length 头,或该头被省略/伪造为 0)⇒ 被判「无 body」跳过解密,密文 {data:"..."} 原样交给 handler(isEncrypted:true 但体未解),handler .json() 拿到信封而非真实字段 加密通道在分块/缺头时静默不解密(功能正确性/健壮性) 改按 HTTP 方法判体存在:method ∈ {POST,PUT,PATCH} 即尝试读体+解密(空体自然落回原路径),不再信 content-length 新 1 例真判别(RED 探针实测:还原 content-length 版 ⇒ 该例判红;恢复 ⇒ 通过):加密 POST 无 content-length ⇒ 断言 mockDecrypt 被调用且 handler 收到解密体;既有 26 例(全部 method+content-length 配对)不受影响 ⇒ api-crypto 27 例通过,type-check EXIT=0,eslint --quiet 0 error
Q-9 P3 admin/media 多文件上传无原子性:上传循环内 ① 某文件超 10MB 直接 return validationError,但前面文件已 uploadMedia 落盘+入库;② 某文件在 uploadMedia 内被 magic-byte/类型策略拒(抛 UploadPolicyError,外层 catch 返 400)同样留下前面已写入的文件 ⇒ 请求返回错误却已产生孤儿媒体资产(磁盘 + MediaAsset 行),无返回、无清理路径 半途失败留下孤儿资产(磁盘/DB 泄漏 + 计费/存储面) 把尺寸校验提到任何写入之前(整批预检);上传循环包 try,失败时对本请求已成功的 results 逐个 deleteMedia 回滚再返回错误 新 2 例真判别(旧码必 RED):① 第二个文件抛 UploadPolicyError ⇒ 断言 mockDeleteMedia('asset-1') 被调用(旧码无回滚 ⇒ 不调用);② 批次含一个超限文件 ⇒ 断言 mockUploadMedia 从未被调用(预检在任何写入前拒整批)。既有单/多文件成功用例仍通过 ⇒ media route 14 例通过,type-check EXIT=0,eslint --quiet 0 error

4.2 子代理上报、主线尚未逐一复核(登记为待验证,不当作已确认,不据此宣称已修)

ID 级别 摘要 位置(子代理所引) 主线状态
Q-4 P2 待复核 6 个内联 role 数组的 handler — 已复核确认为真缺陷并已修(见 §4.1 Q-4):status 维度缺位属实,role 授予逻辑本身仍正确
Q-5 P2 待复核 外层 grid/space 被 StaggerReveal 单子吞成单列 content/sections.tsx 已复核确认为真缺陷并已修(见 §4.1 Q-5):3 处组件为活代码(产品详情页),已把网格类挂回 StaggerReveal 并加 3 例结构断言
Q-10 P3 四条子代理上报:① api-crypto.ts hasBody 信任客户端 content-length;② workflow.ts:84 updateMany+auditLog.create 非 $transaction;③ analytics.ts:33 同意偏好无字段校验;④ button.tsx ripple Date.now() 键碰撞 + 卸载不清 timeout 各处 ④=Q-10a、③=Q-10c、①=Q-10b 均已修(见 §4.1,各带判别测试)。仅 ② 未做:修法需 interactive $transaction(async tx=>…)(update→读回→审计有数据依赖),会牵动 workflow 路由测试的 prisma mock 边界,风险高于其 P3 权重,暂缓并附精确配方
Q-6 P2 detail-product-value.tsx:73-91 render 体内 setDisplayValue + requestAnimationFrame(StrictMode/重渲染派生多串未取消动画) 组件 detail-product-value.tsx 待复核:grep 显示该组件仅被 products/erp-upgrade-v3/page.tsx 引用,而周期 2 判定 erp-upgrade-v3 为死路由 ⇒ 若确死则非在线缺陷,仅登记;render 副作用面仍宜在组件复用时修
Q-7 P3 待复核 admin/items/users GET 分页未校验 — 已复核确认为真缺陷并已修(见 §4.1 Q-7):新增 parsePagination 复用件,items + users 两路接入,6+1 例覆盖
Q-8 P3 待复核 内容 ID 存在性 oracle — 已复核确认为真缺陷并已修(见 §4.1 Q-8):三 handler 认证前置于存在性探针,3 例证 findUnique 不被匿名触达
Q-9 P3 待复核 多文件上传中途失败留孤儿 — 已复核确认为真缺陷并已修(见 §4.1 Q-9):整批尺寸预检 + 失败回滚已成功文件,2 例真判别

4.3 主线证伪的子代理结论(不修,防把假发现写进代码/文档)

  • Q-FP-1:子代理称 detail-product-value.tsx:69 parseFloat(value.replace(/[^0-9.]/g,'')) 把 "1,000+" 变成 1(千倍低估)。不成立——[^0-9.] 会删掉逗号、保留数字与点,"1,000+"→"1000."→parseFloat=1000,正确。故该解析点不是缺陷(其 render-副作用面另见 Q-6,属不同问题,仍待复核)。

本轮验证层级诚实说明:type-check 为全程序 tsc --noEmit 且 EXIT=0(覆盖 Q-1/2/3 全部改动);受影响单元套件(auth/login/contact/media/rate-limit)73 例全通过;改动文件 eslint --quiet 0 error。但全量 test:coverage(1725 例)本轮未重跑,且 Q-1(表现层登出)与 Q-3(登录 API 行为)不在任何已跑过的 E2E 子集里 ⇒ 其生产目标凭据待 AUTH-D1 入库 + AUTH-D4 后统一复跑。Q-2(media 派生)真 sharp 单测覆盖格式,最直接。Q-4 的凭据层级:6 个 handler 的存活判定由 admin/users+admin/roles 路由级 jest(mock prisma.user.count)端到端覆盖(默认存活 30+ 例仍绿 + 停用 4 例判 401/零写入),属单测层,非 E2E;其"移除 helper ⇒ 停用令牌被放行"的 RED 逻辑由"旧码走 authenticateRequest 不看 status、新 mock 的 count 遂成死参数、断言 401 必红"反证。验收判定不变:新增修复同样只在主工作树,AUTH-D1 仍是唯一硬阻断。

4.4 本会话全量回归证据(2026-09-25,覆盖 Q-1…Q-5/Q-7/Q-8 全部改动之后)

门禁 命令 结果
全量单元 npm run test:unit 142 套件 / 1760 例全通过,0 失败(较周期 2 的 137/1725 净增 5 套件 35 例,全为本会话新增 RED 测试;无一处回归)
覆盖率棘轮 npm run test:coverage EXIT=0,阈值全达标:global 85.96 stmts / 87.57 branch / 81.38 funcs / 85.96 lines(门限 75/82/75/75 未下调);本会话新增 src/lib/pagination.ts、src/lib/rate-limit.ts 各 100/100/100/100(在 collectCoverageFrom 的 src/lib/** 内,随棘轮受约束)
真库集成层 npm run test:integration:real EXIT=0,4 套件 / 23 例全通过;一次性 /tmp/novalon-itest.db,teardown 守卫实测 prisma/dev.db、dev.db、data.db 的 inode+size+mtime 与运行前完全一致 ⇒ 本会话对 permissions.ts(新增 authenticateActiveRequest)与 users/roles/items/workflow 鉴权路由的改动在真库鉴权层无回归,且未污染开发库
静态 a11y(对比度/令牌) npm run check:contrast + check:brand-token 两者 EXIT=0:contrast 44/44 令牌配对满足 WCAG 2.1 AA;brand-token 扫描 406 文件 0 违规(1 处已知白名单降级 = loading-state.tsx 死组件,见 N-8/D-8)⇒ 本会话改动无对比度/品牌令牌回归
生产构建 + 装配 npm run build(含 postbuild 拷贝) EXIT=0,dist/standalone/{server.js,dist/static,public} 三项齐备(ASSEMBLY_OK)⇒ 本会话对 api-crypto/permissions/users·roles·items·workflow·media 路由的服务端改动可干净构建(N-9 前提成立);产物 heading-hierarchy-report.json 等落盘物均被 .gitignore 覆盖,不脏提交面
标题层级(产物上) npm run check:headings(自起 standalone 扫 10 页) EXIT=0:10 页全通过、0 问题 ⇒ 与 contrast/brand-token 合起来 完整 check:a11y 三件套在本会话构建产物上全绿(不再仅沿用周期 1/2 结论)
Lighthouse(产物上) npm run lighthouse(lhci autorun 自起 standalone) EXIT=0:对 9 URL × 3 次运行 = 27 次跑的全部断言通过(含本会话前几轮新加的 inspector-issues minScore 断言)⇒ 性能/a11y/BP/SEO 门禁在当前源码产物上仍达标

| 类型检查 | npm run type-check(全程序 tsc) | EXIT=0 | | Lint | npm run lint | 0 error / 104 warning(与周期 2 口径 104 完全一致 ⇒ 本会话新文件 rate-limit.ts/pagination.ts 等零新增债) |

说明:本会话已在含全部 Q 修复 + S-1 修复的最终树上重跑并 EXIT=0:test:unit(1758)、test:coverage(阈值棘轮)、test:integration:real(23)、check:contrast/check:brand-token/check:headings(完整 check:a11y)、npm run build+装配、npm run lighthouse;type-check/lint 全程 EXIT=0。仍未在本会话重跑:全站 check:axe(需自起 standalone + crawl-routes 清单,端口/残留进程需专管)、生产目标 E2E(注意 npm run test:e2e:prod 不排除写库 spec,跑它即触发 AUTH-D4)、视觉只读比对(Q-5/S 系列改了布局,需 AUTH-D3 重基线)。周期 1/2 的这三项结论仍登记于各自报告。

5. 第四轮审查轴(2026-09-25,2 路并行 subagent:src/app/** 页面 + 余下 src/components/**)

两条只读 subagent 分别扫前几轮只 grep 未逐行读过的面。主线未照抄任何一条:S-1 我逐行核实并修复;其余登记为「待主线复核」,其中标注与前序已知项同机制的(Q-5/C-1 新点位)优先,因为修法现成。

5.1 主线已核实 + 已修(工作树内,未提交)

ID 级别 缺陷 触发/影响 修复 凭据
S-1 P2 首页 CMS 数组未逐条守卫 ⇒ 整页 RSC 崩溃:home-content-v15.tsx 的 ServicesSection 只在 :510 校验 services[0].subtitle,随后 :546 service.highlights.map(无 ?./Array.isArray,而 :552 metrics 却有 && 守卫);CasesSection 的 spotlight :789 用 ?. 但 restCases :828 caseItem.metrics.slice 未守卫 发布任一缺 highlights/metrics 的服务或案例 ⇒ 流量最高的首页 500 到 error.tsx 两处改 Array.isArray(x) ? x : [] 逐条守卫(与既有 ?. 惯例一致) type-check EXIT=0、eslint --quiet 0 error(改动文件);纯渲染守卫,行为对合法数据不变

5.2 子代理上报、待主线逐一复核(不当作已确认/已修)

ID 级别 位置 摘要 复核优先级/备注
S-2 P2 products/product-detail-content-v3.tsx:178,231 + solutions/solution-detail-content-v3.tsx:121,168,223,278 grid/space-y 挂在外层 div、唯一子为裸 StaggerReveal ⇒ /products/[id]、/solutions/[id] 桌面端塌成单列(Q-5 同机制的新点位) 已复核+已修(6 处):同文件 :132 已是正确写法可佐证。安全修法——把网格/间距类移到 StaggerReveal className、外层 <div> 留作无类包裹(不删闭合标签,规避 Q-5 那次改动风险)。content-v3 三套件 25 例通过 + type-check EXIT=0 + eslint --quiet 0 error。需 AUTH-D3 视觉重基线确认像素
S-6 P3 误报 cases/[slug]/page.tsx:27-34 generateMetadata 绕过 C-1 归一 主线核实为误报,未改:generateMetadata 已用 data.challenge?.substring / data.metrics?.map,对缺键的保护与 client.tsx 的 ?? [] 同级,并非"绕过 C-1"。唯一残余是类型错误值(如 metrics 存成字符串),但那对 client 路径同样会崩,属通用运行时类型校验缺失(非元数据专属崩溃),不在本轮改
S-3 P2 about/page.tsx、contact/page.tsx、products/erp-upgrade/page.tsx 无 export const revalidate,且 /api/cms/revalidate 未映射这些模型 ⇒ 构建后发布新内容永不刷新(并含「revalidateTag 因 data-server.ts:37 用 React cache() 而非 unstable_cache 实为 no-op」的重断言) 高但涉渲染配置/缓存语义,须逐条核 next 行为再定改否(可能引 ISR/构建变化)
S-4 P2 home-content-v15.tsx:32-43(用于 :510-516) FALLBACK_SERVICES 兜底含 40%/6个月 等无 basis 的数字,N-30 类第三处残留,违背零编造 中:修法=删兜底 metrics(与 N-30 一致);属内容口径,宜确认后改
S-5 P2 待复核 detail/detail-hero.tsx:171-184 + micro-interactions.tsx:148-153 <a href><PressableButton/></a>,而 PressableButton 渲 <motion.button> ⇒ button 嵌进 a(无效交互嵌套) 已复核+已修:根因在 PressableButton 的 href 分支本就产 <a><button>。改为有 href 时渲单个 motion.a(承载按钮样式),detail-hero 去掉外层 <a> 直接传 href;onClick/样式保留,导航语义不变。新增 micro-interactions.test.tsx 2 例真判别(旧码 querySelector('button') 非 null ⇒ RED;且发现 detail.test.tsx mock 掉了 PressableButton,故测真组件须单列)
S-7 P3 services/[id]/solutions/[id]/products/[id]/news/[slug] 的 page dynamic='force-dynamic' 与 generateStaticParams/revalidate 冲突 ⇒ SSG 产物永不服务,注释与单测给假信心 中:涉渲染模式口径,须核 next16 行为再定
S-8 P3 待复核 hero-particle-field.tsx:287-290 onVisibility 未判相交态即 start() ⇒ 离屏 canvas rAF 空转 已复核+已修:加 intersecting 跟踪(IO 回调置位),onVisibility 改为「可见且 intersecting」才启动,与 :271 契约对齐。凭现有 hero-particle-field 三套件/36 例(含 reduced-motion 降级、unmount 停环)无回归 + type-check/lint 绿;未加专测(jsdom 下 visibilitychange+IO 离屏组合难做判别性 RED,诚实标注)。首页活组件(home-content-v15)
S-9 P3 待复核 back-to-top.tsx:12-20;detail-trust-section.tsx:18-65 AnimatedCounter 挂载未初始同步;裸 rAF 计数不查 useReducedMotion 两处均已修:back-to-top effect 内补 handleScroll() 初始同步;AnimatedCounter 在 shouldReduceMotion 时直接落终值不跑 rAF(useReducedMotion 自绘,因 MotionConfig 不管裸 rAF)。back-to-top by-construction(jsdom scrollY 只读难判别,未加专测,诚实标注);AnimatedCounter 由 detail.test 27 例 + 全量 test:unit 142/1760 + type-check/lint 绿佐证无回归
S-10 P3 admin/content/[modelCode]/page.tsx:210 状态误标(review→「已归档」);admin/roles/page.tsx:59-79 effect 依赖 selectedRole 覆未保存编辑;admin/users/page.tsx:85 搜索无防抖/序号守卫(content/[modelCode] 已修,此处未);admin/media/page.tsx:38,131 单 fileInputRef 挂两个 input ⇒ 顶部按钮重选同文件不触发 onChange;admin/page.tsx:108/media/page.tsx:40 吞错显示「空」非报错;admin/login/page.tsx label 无 htmlFor、密码切换钮无 aria-label 后台多处 P3(错标/竞态/吞错/a11y 标签) 中:逐条小修,部分与既有模式(防抖/seq)现成可搬

诚实边界:S-2…S-10 为 subagent 上报,我尚未逐行独立复核,不作「已确认/已修」主张;S-1 是我本轮亲自核实并修复的唯一项。子代理另排除了 cta-section(零 importer,其「30 分钟内响应」是 DEC-N30 的第 5 条 SLA 变体,仅附记)、Radix 包装件、slider(零消费者)等——同样待我复核后再采信。

6. 会话收尾与续工交接(2026-09-25,subagent 架构系统性 QA)

本文件(qa-tracker.md)即 objective 阶段3 要求的「问题跟踪机制」单一真源;§4 为第三轮(API+lib/组件)、§5 为第四轮(src/app 页面 + 余下组件)审查轴。

6.1 本会话已完成(均在工作树,未提交)

  • 已核实并修复的缺陷(含判别性测试):Q-1、Q-2、Q-3、Q-4、Q-5、Q-7、Q-8、Q-9、Q-10a、Q-10b、Q-10c、S-1、S-2(6 点位)、S-5;S-8、S-9 经检查修复(诚实标注:jsdom 无法做判别性 RED,仅 by-construction + 现有套件/类型门禁)。
  • 主线证伪、未改的子代理断言:1,000+→1 解析(实为 1000,正确)、C-1 归属笔误、S-6(metadata 已 ?. 守卫,非绕过 C-1)。
  • 自纠:一次 Edit 误删既有测试体(已复原);一次写了不能失败的假测试(已换成诚实版);一次 §4.4 表格被打断+留陈旧说明(已合并修正)。

6.2 本会话门禁证据(最终树,全部 EXIT=0,见 §4.4 表)

test:unit 142 套件/1760 例 · test:coverage(阈值未下调,新 lib 100%)· test:integration:real(23,dev.db 指纹未变)· 完整 check:a11y(contrast 44/44 · headings 10/10 · brand-token 0 违规)· npm run build+standalone 装配 · npm run lighthouse(9 URL×3)· type-check · lint 0 error/104 warning。

6.3 工作树披露(最高优先,勿静默留给下一个人)

git status --porcelain = 378 条(54 未跟踪),HEAD 仍 f543e47。⇒ 两轮 + 本会话全部修复只在工作树,未提交/未 PR ⇒ 不可审、不可复现、不可 CI 验证。这是 objective 阶段5「可交付」未达成的唯一实质原因。

2026-09-28 第五轮后刷新:git status --porcelain = 394 条(55 未跟踪),HEAD 仍 f543e47。本轮净增 16 条改动/新文件(含新测试文件 src/app/__tests__/cms-page-revalidate.test.ts)。结论不变。

6.4 续工:待授权动作(逐项明文批准后才动;见 §2.3 / 周期报告 §5)

  1. AUTH-D1 入库/PR(解锁验收):先 git fetch origin dev 取真值 → 裁定 origin/dev↔HEAD 双向分叉的重复提交对 → 按「表现层/后台编辑器/Sentry/测试装配/文档口径 + 本会话 Q/S」分笔提交 → 过 scripts/check-pr-checklist.sh → Gitea PR。git add 按路径,禁 -A:.gitignore 未挡 prisma/dev.db-shm/-wal,-A 会带入 SQLite 边车。
  2. AUTH-D4 写库 E2E(11 例,真写 dev.db;⚠ npm run test:e2e:prod 不排除写库 spec,跑它即写库)。
  3. AUTH-D3 视觉基线:Q-5/S-2/S-5 改了布局,产品/方案/案例详情页需人工核看后 --update-snapshots。
  4. AUTH-D2 seed:使周期2 L-2 权限修复对数据生效。

6.5 续工:待复核/待决策的登记项(不阻断验收)

S-3(about/contact/erp-upgrade 无 revalidate + revalidateTag no-op,涉渲染配置)、S-7(force-dynamic vs generateStaticParams)、S-4(FALLBACK_SERVICES 无 basis 数字,宜按 N-30 删)、S-10(后台状态误标/搜索竞态/媒体双 input ref 冲突/登录表单 label 关联)、S-9 子项(detail-trust 裸 rAF 未查 reduced-motion)、以及周期1/2 遗留的 D-1…D-11 / DEC-* 决策项。

7. 第五轮审查轴(2026-09-27…28 会话,4 路并行 subagent + 主线逐条复核/修复)

承接 §6.5 的续工清单:S-3/S-4/S-7/S-10/Q-6/Q-10② + 未逐行覆盖的余下面(hooks、lib/cms 渲染器、seo/analytics 组件、marketing 残余页面)。主线未照抄任何子代理结论:逐条亲读源码复核后再修,修复均带判别性测试(RED→GREEN 实测)。

7.1 主线已复核并修复(工作树内,未提交)

ID 级别 缺陷(主线核实后口径) 修复 RED→GREEN 凭据
S-21(=DEC-D7 落地) P2 renderField 无 richtext 分支 ⇒ news 正文/legal 正文落 default 单行 input[type=text],浏览器 value 消毒剥掉全部 \n,编辑一次即静默损毁段落(详情页 whitespace-pre-line 渲染) richtext 走 textarea(rows=12);顺带收敛出作用域读写机制 新增 3 例读写保真测试;改前 Expected TEXTAREA, Received INPUT 判红 → 改后编辑器套件 22/22
S-22 P3 array/object 子字段编辑器读写顶层 formData[field.name]:编辑写不进数组,却把 label/value 垃圾顶层键混进保存载荷(假成功) array 改整体 JSON 编辑(复用 JsonEditor);object 子字段以 scope{parent,write} 读写父对象并合并回写 同上:改前 getByLabelText('指标') 无 TEXTAREA / 作者 值为空 判红;改后载荷断言 metrics 回写数组、无泄漏顶层键
Q-10② P2 workflow.ts 状态更新→读回→审计三条独立写:审计失败时状态已落库但无审计,调用方收 500 误以为流转未发生 交互式 prisma.$transaction(async tx …) 包住 CAS→读回→审计;通知保持在事务外(不回滚不上抛的既有语义不变) 测试 mock 增加带快照回滚的 $transaction 桩(数组形态直接判红防退化);升级既有「审计失败 fatal」例为回滚断言:改前 storedItem 停在 published 判红 → 改后 28/28;真库集成层 test:integration:real 23/23 EXIT=0(dev.db 指纹守卫通过)
S-3 P2 /about、/contact、/products/erp-upgrade 无 revalidate 导出且 revalidate 路由无映射 ⇒ 构建后发布的 CMS 内容永不刷新(子代理实证:三页在 prerender-manifest 为 static + initialRevalidateSeconds:false)。附带断言 revalidateTag 全程 no-op 成立(全站无 unstable_cache/'use cache'/fetch tags 消费点,React cache() 仅请求内去重) 三页加 export const revalidate = 3600(与其余 14 页同档)+ 路由补 about-page/contact-page/product→/products/erp-upgrade 三条映射(推送即秒级失效,3600 为无推送兜底) 新增 6 例(3 route 映射 + 3 页 revalidate 导出,新文件 src/app/__tests__/cms-page-revalidate.test.ts):改前 6 例全判红 → 改后 25/25;产物级实证:重建后 dist/prerender-manifest.json 三页 initialRevalidateSeconds=3600
S-10 六条 P3×6 ①列表状态列把 review/archived 误标「已归档」②roles 的 fetchRoles 依赖 selectedRole,切角色 refetch 覆盖未保存编辑 ③users 搜索逐键打后端且无 seq 守卫(乱序响应覆盖新结果)④media 双 input 同挂一个 ref(重选同文件不触发 onChange)⑤admin 首页/media/zones 吞错显「空」(假绿)⑥login/zones/users 弹窗 label 无 htmlFor、密码显隐钮无可访问名 ①四态 STATUS_LABELS 映射 ②fetchRoles 依赖清零 + `setSelectedRole(prev=>prev
S-11/S-12/S-13/S-15 P3 zones 吞错显空 / notifications 翻页无 seq 守卫 / roles 矩阵 super_admin 全显「未授权」与「拥有所有权限」文案矛盾 / zones·users label 关联(S-10 同族扩散) 与 S-10 一并修(error 横幅、fetchSeqRef、super_admin 整行按已授权呈现、htmlFor) 同上
S-23 P3 ui/animated-counter.tsx displayValue = start ? count : value:未入视口直显终值,IO 异步首回调后跳回 0 再爬升(先给答案再数) displayValue = shouldReduceMotion ? value : count(useCountUp 未启用期本就停在起点 0) 新 1 例(IO 桩驱动):改前判红(旧码未相交即显 500)→ 改后 6/6;既有用例改 startOnView={false} 语义不变
S-24 P3 PerformanceTracker CLS 累加器在 observer 回调内:分批到达的 layout-shift 每批只报增量,GA 收到的永不是会话总 CLS 累加器提到回调外,每批上报累计值 新 1 例双批次断言 [≈100, ≈150](旧码第二批报 50 ⇒ RED 由形状显然)→ 改后 17/17
Q-6 P3 detail-product-value.tsx MetricCard render 体内 setState+rAF:探针实证每帧 setState 触发重渲染又 spawn 一条从 0 开始的动画链且从不 cancel,假时钟下大字永远停在 '0';卸载后帧链继续排队 动画收入 useEffect,cleanup cancelAnimationFrame;NaN 回退同 effect 新 1 例(faithful rAF 桩:cancel 真撤销排队):改前判红(旧实现卸载后 sched 继续增长)→ 改后 28/28。注:第一版测试命中 benefits 同名文本属假绿,已被探针推翻重写(诚实记录)

7.2 主线复核后的定性变更(不改代码,只改台账口径)

ID 原登记 复核结论
Q-6 路由定性 「erp-upgrade-v3 死路由 ⇒ 若非活码仅登记」 定性修正:不是死路由,是零入口孤儿路由(不在 sitemap、src 内零内部链接,但静态可直达且有真实渲染)。缺陷本身属实已修(见 §7.1),影响面限直达 URL
S-4 「FALLBACK_SERVICES 无 basis 数字,N-30 类残留,宜删」 降为 DECISION(DEC-S4):子代理实证 fallback 与 CMS 数据走同一渲染 map,:562 对每张卡(含 fallback)渲染 <MetricsBasisNote basis={weakestBasis(…)}>,未声明 basis 一律保守落 target 角注 ⇒ 并非裸奔编造,与 N-30(虚构佐证)不同类。残余问题:硬编码数字本身无出处 + fallback 触发条件(CMS service 缺失/首条无 subtitle)。是否删数字属内容口径,留业务裁定
S-7 「force-dynamic + generateStaticParams 冲突 ⇒ SSG 产物永不服务」 CONFIRMED 但判为设计取舍(子代理引 bundled docs caching-without-cache-components.md:97 + prerender-manifest 实证四路由不在产物中;页内注释表明有意为之:硬 404 + 新内容首请求可见)。不自动改渲染模式,登记为 DECISION(承 DEC-N21b 同级)
S-14 clipboard 无 catch 随 S-10 批修(.catch + toast.error),SUSPECTED 定级不变

7.3 子代理上报、主线证伪或不修(防假发现入库)

  • MetricCard parseFloat('1,000+')→1 类解析问题在本组件不成立([^0-9.]/ 保留数字与点),与 §4.3 Q-FP-1 同族。
  • hooks 面(use-focus-trap/use-swipe-gesture/use-reduced-motion/useCountUp)、analytics 其余 tracker、structured-data、lib/cms 其余模块:子代理逐文件扫描后无新缺陷上报(含监听清理、capture 分工、XSS sink 检查均通过)。
  • 死码新增:CookieSettingsButton(零 importer,连带「重开偏好面板不与已存同意同步」的潜在缺陷一并挂账)、getInitialShowConsent 三分支恒 false(死但无害)。

7.4 本轮收尾门禁(2026-09-28 最终树)

门禁 结果
type-check EXIT=0(一次 tsc 报错为 Q-6 测试 mock 类型断言丢失 .mock,已修后复跑绿)
lint 0 error / 105 warning(与 AGENTS.md 口径一致 ⇒ 本轮零新增债)
test:coverage EXIT=0,143 套件 / 1772 例全通过(较 §6.2 净增 1 套件 12 例,全为本轮判别测试)
test:integration:real EXIT=0,4 套件 / 23 例,dev.db/data.db inode+size+mtime 守卫通过(workflow $transaction 改动在真 SQLite 无回归)
check:contrast / brand-token / headings 44/44 · 0 违规 · 10/10 页,均 EXIT=0
build + standalone 装配 EXIT=0,ASSEMBLY_OK;prerender-manifest 实证三页 ISR=3600(S-3 产物级)
lighthouse EXIT=0,9 URL × 3 次 = 27 run 全部断言通过(lhci autorun 自起 standalone :3200)