Audits click paths in UI components to detect state interaction defects where functions cancel each other out or produce wrong final state. Use when systematic debugging misses issues or after shared state refactors.
How this skill is triggered — by the user, by Claude, or both
Slash command
/everything-claude-code:click-path-auditThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
发现静态代码阅读容易遗漏的缺陷:状态交互副作用、顺序调用之间的竞态条件,以及相互静默撤销的处理函数。
发现静态代码阅读容易遗漏的缺陷:状态交互副作用、顺序调用之间的竞态条件,以及相互静默撤销的处理函数。
传统调试检查的是:
但它不检查:
真实案例:一个"新邮件"按钮调用了 setComposeMode(true) 然后 selectThread(null)。两个函数单独都正常工作。但 selectThread 有一个副作用会重置 composeMode: false。按钮什么也没做。系统性调试找到了 54 个缺陷 — 这个被遗漏了。
对目标区域中的每个交互触点:
1. 识别处理函数(onClick, onSubmit, onChange 等)
2. 按顺序追踪处理函数中的每个函数调用
3. 对每个函数调用:
a. 它读取了什么状态?
b. 它写入了什么状态?
c. 它对共享状态有副作用吗?
d. 它是否作为副作用重置/清除了某些状态?
4. 检查:后面的调用是否撤销了前面调用的状态变更?
5. 检查:最终状态是否符合用户从按钮标签期望的结果?
6. 检查:是否存在竞态条件(异步调用以错误顺序解决)?
在审计任何触点之前,构建每个状态存储操作的副作用映射:
对范围内的每个 Zustand 存储 / React context:
对每个 action/setter:
- 它设置了哪些字段?
- 它是否作为副作用重置了其他字段?
- 文档:actionName → {sets: [...], resets: [...]}
这是关键参考。"新邮件"缺陷在不了解 selectThread 重置 composeMode 的情况下是不可见的。
输出格式:
存储:emailStore
setComposeMode(bool) → sets: {composeMode}
selectThread(thread|null) → sets: {selectedThread, selectedThreadId, messages, drafts, selectedDraft, summary} RESETS: {composeMode: false, composeData: null, redraftOpen: false}
setDraftGenerating(bool) → sets: {draftGenerating}
...
危险重置(清除了不属于自己状态的操作):
selectThread → 重置 composeMode(由 setComposeMode 拥有)
reset → 重置所有内容
对目标区域中的每个按钮/开关/表单提交:
触点:[组件:行号] 中的 [按钮标签]
处理函数:onClick → {
调用 1: functionA() → sets {X: true}
调用 2: functionB() → sets {Y: null} RESETS {X: false} ← 冲突
}
预期:用户看到 [按钮标签承诺的内容描述]
实际:X 为 false 因为 functionB 重置了它
结论:缺陷 — [描述]
检查以下每种缺陷模式:
handler() {
setState_A(true) // 设置 X = true
setState_B(null) // 副作用:重置 X = false
}
// 结果:X 为 false。第一次调用毫无意义。
handler() {
fetchA().then(() => setState({ loading: false }))
fetchB().then(() => setState({ loading: true }))
}
// 结果:最终 loading 状态取决于哪个先解决
const [count, setCount] = useState(0)
const handler = useCallback(() => {
setCount(count + 1) // 捕获了过期的 count
setCount(count + 1) // 同样的过期 count — 只增加了 1 而非 2
}, [count])
// 按钮显示"保存"但处理函数只验证,从未真正保存
// 按钮显示"删除"但处理函数只设置了标志,没有调用 API
// 按钮显示"发送"但 API 端点已被移除/损坏
handler() {
if (someState) { // someState 在此处始终为 false
doTheActualThing() // 永远不会到达
}
}
// 按钮设置 stateX = true
// 一个 useEffect 监视 stateX 并将其重置为 false
// 用户看不到任何变化
对发现的每个缺陷:
CLICK-PATH-NNN: [严重程度: 严重/高/中/低]
触点:[文件:行号] 中的 [按钮标签]
模式:[顺序撤销 / 异步竞态 / 过期闭包 / 缺失转换 / 死路径 / useEffect 干扰]
处理函数:[函数名或内联]
追踪:
1. [调用] → sets {field: value}
2. [调用] → RESETS {field: value} ← 冲突
预期:[用户期望什么]
实际:[实际发生了什么]
修复:[具体修复方案]
此审计成本较高。适当限定范围:
智能体 1:映射所有状态存储(步骤 1)— 这是所有其他智能体的共享上下文
智能体 2:仪表板(任务、笔记、日志、想法)
智能体 3:聊天(DanteChatColumn, JustChatPage)
智能体 4:邮件(ThreadList, DraftArea, EmailsPage)
智能体 5:项目(ProjectsPage, ProjectOverviewTab, NewProjectWizard)
智能体 6:CRM(所有子标签)
智能体 7:个人资料、设置、保险库、通知
智能体 8:管理套件(所有页面)
智能体 1 必须先完成。其输出是所有其他智能体的输入。
/superpowers:systematic-debugging 之后运行(它找到其他 54 种缺陷类型)/superpowers:verification-before-completion 之前运行(它验证修复是否有效)/superpowers:test-driven-development — 此处发现的每个缺陷都应该有一个测试ThreadList.tsx "新邮件"按钮:
onClick={() => {
useEmailStore.getState().setComposeMode(true) // ✓ 设置 composeMode = true
useEmailStore.getState().selectThread(null) // ✗ 重置 composeMode = false
}}
存储定义:
selectThread: (thread) => set({
selectedThread: thread,
selectedThreadId: thread?.id ?? null,
messages: [],
drafts: [],
selectedDraft: null,
summary: null,
composeMode: false, // ← 这个静默重置杀死了按钮
composeData: null,
redraftOpen: false,
})
系统性调试遗漏了它,因为:
点击路径审计捕获了它,因为:
selectThread 重置 composeModenpx claudepluginhub aaione/everything-claude-code-zhAudits UI buttons and touchpoints by tracing state changes in handlers to find canceling side effects, race conditions, and inconsistent final states after refactors or for user-reported bugs.
Traces user-facing button/touchpoint state change sequences to find bugs where functions cancel each other out or leave UI inconsistent. Use after systematic debugging fails or after shared state refactors.
Audits UI code for missing loading, empty, and error states in async operations and data-driven components. Finds gaps and implements fixes using existing app patterns.