Skip to content

Instantly share code, notes, and snippets.

@AGDholo
Created July 12, 2026 07:42
Show Gist options
  • Select an option

  • Save AGDholo/abea4fc6fdc3056c6faf4566a606f211 to your computer and use it in GitHub Desktop.

Select an option

Save AGDholo/abea4fc6fdc3056c6faf4566a606f211 to your computer and use it in GitHub Desktop.
agd-bug-repro-fix
---
name: agd-bug-repro-fix
description: Yanlee 的真实缺陷复现、强制最小 demo 隔离、证据驱动根因定位、分阶段暂停汇报、真实代码修复和真实浏览器复测工作流。用于 TransferAI/Luni/app shell 中用户要求先复现、用 Codex 内置浏览器验证、做 demo 页面复现、只报告根因后再修、或处理登录态、权限、缓存、状态流、默认值、降级策略等跨层缺陷。
---
# AGD Bug Repro Fix
## 核心
把用户报告当症状,不当结论。先复现,再用证据定位 owner 和事实源,最后只在真实代码里修根因。
根因必须由真实证据支持:Codex 内置 `@浏览器` 的真实操作、页面可见状态、请求、日志、埋点、数据库或本地状态。读代码只能提出假设,不能单独当根因结论。
禁止把“让症状暂时消失”当修好。延时、忽略下一次事件、拖拽后删 class、重复写状态、临时开关和调用点拦截都属于补丁信号;一旦出现,必须停止实现并重新检查职责、事件顺序和状态所有权。
## 工作流
1. 读规则和真实代码。
- 先读仓库 `AGENTS.md`、`agd-user-preferences`、相关子目录说明和本次涉及的 route、feature、component、hook、store、API。
- 需要浏览器时先用 Codex 内置 `@浏览器` 真实复现,不用其他浏览器通道或脚本浏览器替代。
- 需要第三方库当前行为时,先确认锁文件中的真实版本和本机安装源码,再按官方文档、官方源码、GitHub issue / discussion / PR、社区成熟实践的顺序取证。
- 对照官方实现时,不只比较函数名;必须比较 DOM 层级、事件触发时机、受控状态、portal、focus、owner 和清理责任。
2. 复现真实问题。
- 用用户给的真实 URL、账号、操作顺序和可见页面状态复现。
- 记录页面可见状态、请求、日志、埋点、缓存、登录态和失败条件。
- 复现不了就说清差哪一步,别靠截图猜。
3. 做最小 demo。
- demo 必须复用真实组件、hook、store、policy 或 API,不写一套假逻辑。
- UI / 视觉类 demo 不能看截图手写假页面、假遮挡、假 opacity、假 z-index、假 mask。必须复用真实组件、真实样式、真实 DOM 层级、真实 portal container、真实滚动/裁切/层叠关系。
- 浮层、菜单、popover、modal、tooltip、滚动 fade、mask、overflow、z-index、position、pseudo element 这类问题,demo 必须搬运真实 owner 的触发器和内容组件,并复刻真实 portal 宿主、兄弟顺序和 stacking context。只要菜单内容、尺寸、层级或遮挡形态和真实页面不同,就算 demo 失败。
- 有 `ref` 参与 portal container 时,demo 必须等 ref 挂载后再渲染触发器或让真实组件完成一次同等重渲染;ref 为空导致 portal fallback 到 body 的 demo 无效。
- demo 必须只暴露当前问题的最小状态切换和最少输入。
- 先让 demo 稳定复现失败。
- demo 复现完成后必须停下来汇报:复现步骤、证据、根因判断、怀疑的 owner、下一步 demo 修复计划。
- 等用户明确继续后,才修 demo。
- demo 修好后必须再次停下来汇报:改了哪里、为什么能证明根因、demo 复测结果、准备如何映射到真实代码。
- 等用户明确继续后,才把同一个根因修复落到真实代码。
- 真实代码修好后删除临时 demo 和路由,除非用户明确要保留。
4. 把症状抽象成可迁移的根因。
- 先写一句通用根因假设,再用证据验证或推翻它。
- 优先看运行证据:真实浏览器状态、控制台错误、网络请求、服务端日志、客户端日志、埋点事件、存储和数据库状态。
- 读代码用于解释证据链,不要靠“看起来像”直接下结论。
- 按 `route -> page -> feature -> component -> hook/store -> shared policy/API` 追到最上游 owner。
- 改 owner 前,用 `rg` 查所有调用方和兄弟入口。
- 强制做主路径复用审计:找到同能力最成熟、已稳定运行的入口,对照状态 owner、控制面、请求字段、transport、错误/停止/成功终态和持久化边界。输出一张复用表,明确“直接复用”“共享层抽取”“允许分叉”;缺少这张表时不得给修复方案。
- 新入口与成熟入口只允许在用户意图、业务上下文、输出合同和展示层分叉。模型、推理、权限、计费、请求规范化、重试、错误转换和终态收口必须复用,不得各自维护。
- 优先修共享事实源;只有局部入口独有时,才在局部修。
- 写出参与方的契约表:谁接收原始事件、谁拥有状态、谁提交终态、谁负责清理。两个参与方不得同时拥有同一个事件或状态。
- 浏览器事件冲突必须记录真实事件顺序。例如 `mousedown -> dragstart -> drop -> dragend -> click` 中,不能在后置事件里修补前置事件已经写错的状态。
- 第一版修法若需要再加延时、事件屏蔽或额外布尔值才能通过,视为根因判断失败;撤回实验修法,回到官方契约和 owner 重新定位。
5. 修真实代码。
- 从 owner 和职责边界根治:让每个库只管理自己的契约。例如拖拽库管理拖拽源和生命周期,菜单库只管理明确的菜单触发,不让两者争用同一个原始手势。
- 优先把缺陷入口接回成熟主路径的共享控制面和运行时契约;不要复制主路径代码,也不要靠后端默认值掩盖入口缺失字段。后端默认只做校验、归一化和安全兜底。
- 实现前再次核对复用表。若改动仍新增第二套 transport、模型/推理状态、错误监听或完成条件,说明方案未根治,停止实现并重新抽取共享层。
- 正式修法必须能解释为什么错误状态不再产生,而不是解释错误产生后如何被清掉。
- 优先恢复或适配官方结构,删除影子状态、双写、兼容分支和症状清理;不要为了缩小 diff 保留错误架构。
- 状态边界要显式建模:未知、未登录、无权限、已登录、有权限不能共用同一份派生数据。
- 权限和产品规则要有单一事实源:客户端只能展示、禁用或表达用户意图,不能自作主路径裁决。
- 默认值必须满足最低权限用户;高权限值只能由权限事实源显式放行。
- 降级必须保留语义:可降级才降级,不可用就切到允许的 fallback。
- 缓存只能加速事实源,不能在边界变化后继续当事实源。
- 产品常量写代码事实源,不为不变规则新增环境变量。
6. 验证最小但真实。
- 先跑 demo 验证,再跑真实页面验证。
- 用 Codex 内置 `@浏览器` 看页面可见状态,不只看 URL。
- UI / 视觉类缺陷必须用真实浏览器截图确认“肉眼同款失败”,不能只用 DOM 结构、computed style 或代码推断宣称复现成功。
- 浮层/层叠类缺陷还要记录 `getBoundingClientRect`、ancestor chain、`position`、`overflow`、`z-index`、`mask-image`、pseudo element 样式和 `elementsFromPoint`;这些证据用于解释截图,不替代截图。
- 权限、状态机、共享 policy 要补定点测试;纯 UI 视觉不硬补测试。
- 路由变更跑路由生成;共享契约改动跑相关测试;不要默认全量 build。
- 测试失败若是无关旧问题,要给出具体文件、行号和错误。
7. 汇报。
- 先说是否修好。
- 点名根因函数、证据来源和真实修复文件。
- 列出真实复现、demo 复现、demo 复测、真实复测和命令验证。
- 说明 demo 是否已删除、是否提交、是否推送。
## 暂停点
必须暂停两次:
1. demo 复现后暂停。只汇报证据和根因,不修 demo,等待用户继续。
2. demo 修好后暂停。只汇报 demo 修复和证据,不修真实代码,等待用户继续。
用户明确说继续、修 demo、修真实代码、完全落地,才进入下一阶段。
## 例子
### 认证缓存泄漏
症状:退出登录后,页面或 sidebar 还显示上一个用户的数据。
泛化根因:未授权状态仍消费授权缓存。
demo:复用真实 workspace hook,做一个登录态切换页;切到未登录时,旧项目仍显示即复现成功。
修法:修派生状态或 shared hook,让未登录状态硬切空;不要只在 sidebar 里隐藏。
### 权限默认值漂移
症状:免费用户默认拿到高权限模型、套餐、工具或能力,菜单虽然显示限制,但运行时仍可用。
泛化根因:默认值、菜单状态、服务端 normalize 和运行时准入没有共用同一个权限事实源。
demo:复用真实模型列表、权限 policy 和选择器;用免费用户打开后,默认值或可选项越权即复现成功。
修法:修共享权限 policy;默认值选最低权限可用项;UI、API 和 runtime 都消费同一个 policy。
### 浮层被 fade 或 mask 盖住
症状:菜单、model picker、permission popover 等浮层在真实页面里被一条横向渐变、滚动 mask、composer 背景或 pseudo element 盖住。
泛化根因:浮层 portal 宿主、滚动容器、兄弟顺序和 stacking context 与触发器所在区域耦合;只看菜单组件本身或重写一个静态菜单会漏掉真实遮挡层。
demo:复用真实触发器、真实菜单内容、真实 dropdown/popover 基础组件和真实 `scroll-edge-fade-*` / `scroll-fade-*` 样式;portal container 必须和真实页面同层级。如果 demo 里列表缺项、整体被裁切、遮挡位置不对、或者靠手写白带才像截图,都算复现失败。
修法:先在 demo 中用最小层级改动证明是 portal 宿主或 stacking context 问题,再把同一个 owner 的修复映射回真实代码;不要在每个菜单调用点各写一个 z-index 补丁。
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment