investigate

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese
<!-- AUTO-GENERATED from SKILL.md.tmpl — do not edit directly --> <!-- Regenerate: bun run gen:skill-docs -->
<!-- 由SKILL.md.tmpl自动生成——请勿直接编辑 --> <!-- 重新生成:bun run gen:skill-docs -->

Preamble (run first)

前置步骤(首先执行)

bash
_UPD=$(~/.claude/skills/gstack/bin/gstack-update-check 2>/dev/null || .claude/skills/gstack/bin/gstack-update-check 2>/dev/null || true)
[ -n "$_UPD" ] && echo "$_UPD" || true
mkdir -p ~/.gstack/sessions
touch ~/.gstack/sessions/"$PPID"
_SESSIONS=$(find ~/.gstack/sessions -mmin -120 -type f 2>/dev/null | wc -l | tr -d ' ')
find ~/.gstack/sessions -mmin +120 -type f -delete 2>/dev/null || true
_CONTRIB=$(~/.claude/skills/gstack/bin/gstack-config get gstack_contributor 2>/dev/null || true)
_PROACTIVE=$(~/.claude/skills/gstack/bin/gstack-config get proactive 2>/dev/null || echo "true")
_BRANCH=$(git branch --show-current 2>/dev/null || echo "unknown")
echo "BRANCH: $_BRANCH"
echo "PROACTIVE: $_PROACTIVE"
_LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no")
echo "LAKE_INTRO: $_LAKE_SEEN"
_TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true)
_TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no")
_TEL_START=$(date +%s)
_SESSION_ID="$$-$(date +%s)"
echo "TELEMETRY: ${_TEL:-off}"
echo "TEL_PROMPTED: $_TEL_PROMPTED"
mkdir -p ~/.gstack/analytics
echo '{"skill":"investigate","ts":"'$(date -u +%Y-%m-%dT%H:%M:%SZ)'","repo":"'$(basename "$(git rev-parse --show-toplevel 2>/dev/null)" 2>/dev/null || echo "unknown")'"}'  >> ~/.gstack/analytics/skill-usage.jsonl 2>/dev/null || true
for _PF in ~/.gstack/analytics/.pending-*; do [ -f "$_PF" ] && ~/.claude/skills/gstack/bin/gstack-telemetry-log --event-type skill_run --skill _pending_finalize --outcome unknown --session-id "$_SESSION_ID" 2>/dev/null || true; break; done
If
PROACTIVE
is
"false"
, do not proactively suggest gstack skills — only invoke them when the user explicitly asks. The user opted out of proactive suggestions.
If output shows
UPGRADE_AVAILABLE <old> <new>
: read
~/.claude/skills/gstack/gstack-upgrade/SKILL.md
and follow the "Inline upgrade flow" (auto-upgrade if configured, otherwise AskUserQuestion with 4 options, write snooze state if declined). If
JUST_UPGRADED <from> <to>
: tell user "Running gstack v{to} (just updated!)" and continue.
If
LAKE_INTRO
is
no
: Before continuing, introduce the Completeness Principle. Tell the user: "gstack follows the Boil the Lake principle — always do the complete thing when AI makes the marginal cost near-zero. Read more: https://garryslist.org/posts/boil-the-ocean" Then offer to open the essay in their default browser:
bash
open https://garryslist.org/posts/boil-the-ocean
touch ~/.gstack/.completeness-intro-seen
Only run
open
if the user says yes. Always run
touch
to mark as seen. This only happens once.
If
TEL_PROMPTED
is
no
AND
LAKE_INTRO
is
yes
: After the lake intro is handled, ask the user about telemetry. Use AskUserQuestion:
Help gstack get better! Community mode shares usage data (which skills you use, how long they take, crash info) with a stable device ID so we can track trends and fix bugs faster. No code, file paths, or repo names are ever sent. Change anytime with
gstack-config set telemetry off
.
Options:
  • A) Help gstack get better! (recommended)
  • B) No thanks
If A: run
~/.claude/skills/gstack/bin/gstack-config set telemetry community
If B: ask a follow-up AskUserQuestion:
How about anonymous mode? We just learn that someone used gstack — no unique ID, no way to connect sessions. Just a counter that helps us know if anyone's out there.
Options:
  • A) Sure, anonymous is fine
  • B) No thanks, fully off
If B→A: run
~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous
If B→B: run
~/.claude/skills/gstack/bin/gstack-config set telemetry off
Always run:
bash
touch ~/.gstack/.telemetry-prompted
This only happens once. If
TEL_PROMPTED
is
yes
, skip this entirely.
bash
_UPD=$(~/.claude/skills/gstack/bin/gstack-update-check 2>/dev/null || .claude/skills/gstack/bin/gstack-update-check 2>/dev/null || true)
[ -n "$_UPD" ] && echo "$_UPD" || true
mkdir -p ~/.gstack/sessions
touch ~/.gstack/sessions/"$PPID"
_SESSIONS=$(find ~/.gstack/sessions -mmin -120 -type f 2>/dev/null | wc -l | tr -d ' ')
find ~/.gstack/sessions -mmin +120 -type f -delete 2>/dev/null || true
_CONTRIB=$(~/.claude/skills/gstack/bin/gstack-config get gstack_contributor 2>/dev/null || true)
_PROACTIVE=$(~/.claude/skills/gstack/bin/gstack-config get proactive 2>/dev/null || echo "true")
_BRANCH=$(git branch --show-current 2>/dev/null || echo "unknown")
echo "BRANCH: $_BRANCH"
echo "PROACTIVE: $_PROACTIVE"
_LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no")
echo "LAKE_INTRO: $_LAKE_SEEN"
_TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true)
_TEL_PROMPTED=$([ -f ~/.gstack/.telemetry-prompted ] && echo "yes" || echo "no")
_TEL_START=$(date +%s)
_SESSION_ID="$$-$(date +%s)"
echo "TELEMETRY: ${_TEL:-off}"
echo "TEL_PROMPTED: $_TEL_PROMPTED"
mkdir -p ~/.gstack/analytics
echo '{"skill":"investigate","ts":"'$(date -u +%Y-%m-%dT%H:%M:%SZ)'","repo":"'$(basename "$(git rev-parse --show-toplevel 2>/dev/null)" 2>/dev/null || echo "unknown")'"}'  >> ~/.gstack/analytics/skill-usage.jsonl 2>/dev/null || true
for _PF in ~/.gstack/analytics/.pending-*; do [ -f "$_PF" ] && ~/.claude/skills/gstack/bin/gstack-telemetry-log --event-type skill_run --skill _pending_finalize --outcome unknown --session-id "$_SESSION_ID" 2>/dev/null || true; break; done
如果
PROACTIVE
的值为
"false"
,请勿主动推荐gstack技能——仅在用户明确要求时调用。用户已选择退出主动推荐。
如果输出显示
UPGRADE_AVAILABLE <old> <new>
:请阅读
~/.claude/skills/gstack/gstack-upgrade/SKILL.md
并遵循“内联升级流程”(如果已配置自动升级则自动执行,否则通过AskUserQuestion提供4个选项,若用户拒绝则记录 snooze 状态)。如果显示
JUST_UPGRADED <from> <to>
:告知用户“正在运行gstack v{to}(刚刚完成更新!)”并继续后续操作。
如果
LAKE_INTRO
的值为
no
:在继续之前,先介绍完整性原则。告知用户:“gstack遵循‘煮沸湖泊’原则——当AI使得边际成本趋近于零时,始终完成完整的工作。了解更多:https://garryslist.org/posts/boil-the-ocean” 然后询问用户是否要在默认浏览器中打开该文章:
bash
open https://garryslist.org/posts/boil-the-ocean
touch ~/.gstack/.completeness-intro-seen
仅在用户同意时执行
open
命令。无论用户是否同意,都要执行
touch
命令标记为已查看。此操作仅执行一次。
如果
TEL_PROMPTED
的值为
no
LAKE_INTRO
的值为
yes
:在处理完湖泊原则介绍后,询问用户关于遥测的问题。使用AskUserQuestion:
帮助gstack变得更好!社区模式会共享使用数据(您使用的技能、耗时、崩溃信息)以及一个稳定的设备ID,以便我们跟踪趋势并更快修复bug。我们绝不会发送任何代码、文件路径或仓库名称。您可随时通过
gstack-config set telemetry off
更改设置。
选项:
  • A) 帮助gstack变得更好!(推荐)
  • B) 不用了,谢谢
如果选择A:执行
~/.claude/skills/gstack/bin/gstack-config set telemetry community
如果选择B:继续询问以下问题(使用AskUserQuestion):
那匿名模式呢?我们只会了解到有人使用了gstack——不会使用唯一ID,也无法关联会话。仅通过计数器了解是否有用户在使用。
选项:
  • A) 好的,匿名模式可以
  • B) 不用了,完全关闭
如果B→A:执行
~/.claude/skills/gstack/bin/gstack-config set telemetry anonymous
如果B→B:执行
~/.claude/skills/gstack/bin/gstack-config set telemetry off
无论选择哪个选项,都要执行:
bash
touch ~/.gstack/.telemetry-prompted
此操作仅执行一次。如果
TEL_PROMPTED
的值为
yes
,则完全跳过此步骤。

AskUserQuestion Format

AskUserQuestion格式

ALWAYS follow this structure for every AskUserQuestion call:
  1. Re-ground: State the project, the current branch (use the
    _BRANCH
    value printed by the preamble — NOT any branch from conversation history or gitStatus), and the current plan/task. (1-2 sentences)
  2. Simplify: Explain the problem in plain English a smart 16-year-old could follow. No raw function names, no internal jargon, no implementation details. Use concrete examples and analogies. Say what it DOES, not what it's called.
  3. Recommend:
    RECOMMENDATION: Choose [X] because [one-line reason]
    — always prefer the complete option over shortcuts (see Completeness Principle). Include
    Completeness: X/10
    for each option. Calibration: 10 = complete implementation (all edge cases, full coverage), 7 = covers happy path but skips some edges, 3 = shortcut that defers significant work. If both options are 8+, pick the higher; if one is ≤5, flag it.
  4. Options: Lettered options:
    A) ... B) ... C) ...
    — when an option involves effort, show both scales:
    (human: ~X / CC: ~Y)
Assume the user hasn't looked at this window in 20 minutes and doesn't have the code open. If you'd need to read the source to understand your own explanation, it's too complex.
Per-skill instructions may add additional formatting rules on top of this baseline.
所有AskUserQuestion调用必须遵循以下结构:
  1. 重新梳理背景: 说明项目、当前分支(使用前置步骤中输出的
    _BRANCH
    值——不要使用对话历史或gitStatus中的分支)以及当前计划/任务。(1-2句话)
  2. 简化说明: 用16岁聪明人能理解的简单语言解释问题。不要使用原始函数名、内部术语或实现细节。使用具体示例和类比。说明问题的表现,而非专业名称。
  3. 推荐方案:
    RECOMMENDATION: 选择[X],因为[一句话理由]
    —— 始终优先选择完整方案而非捷径(参见完整性原则)。为每个选项标注
    Completeness: X/10
    。评分标准:10 = 完整实现(覆盖所有边缘情况、全场景),7 = 覆盖正常流程但部分边缘情况未处理,3 = 捷径方案,会推迟大量后续工作。如果两个选项评分都≥8,选择评分更高的;如果有选项评分≤5,需特别标注。
  4. 选项: 带字母的选项:
    A) ... B) ... C) ...
    —— 当选项涉及工作量时,同时显示两种耗时:
    (人工:~X / CC: ~Y)
假设用户已经20分钟没看这个窗口,且没有打开代码。如果您需要阅读源代码才能理解自己的解释,说明解释过于复杂。
特定技能的说明可能会在此基础格式上添加额外的规则。

Completeness Principle — Boil the Lake

完整性原则——煮沸湖泊

AI-assisted coding makes the marginal cost of completeness near-zero. When you present options:
  • If Option A is the complete implementation (full parity, all edge cases, 100% coverage) and Option B is a shortcut that saves modest effort — always recommend A. The delta between 80 lines and 150 lines is meaningless with CC+gstack. "Good enough" is the wrong instinct when "complete" costs minutes more.
  • Lake vs. ocean: A "lake" is boilable — 100% test coverage for a module, full feature implementation, handling all edge cases, complete error paths. An "ocean" is not — rewriting an entire system from scratch, adding features to dependencies you don't control, multi-quarter platform migrations. Recommend boiling lakes. Flag oceans as out of scope.
  • When estimating effort, always show both scales: human team time and CC+gstack time. The compression ratio varies by task type — use this reference:
Task typeHuman teamCC+gstackCompression
Boilerplate / scaffolding2 days15 min~100x
Test writing1 day15 min~50x
Feature implementation1 week30 min~30x
Bug fix + regression test4 hours15 min~20x
Architecture / design2 days4 hours~5x
Research / exploration1 day3 hours~3x
  • This principle applies to test coverage, error handling, documentation, edge cases, and feature completeness. Don't skip the last 10% to "save time" — with AI, that 10% costs seconds.
Anti-patterns — DON'T do this:
  • BAD: "Choose B — it covers 90% of the value with less code." (If A is only 70 lines more, choose A.)
  • BAD: "We can skip edge case handling to save time." (Edge case handling costs minutes with CC.)
  • BAD: "Let's defer test coverage to a follow-up PR." (Tests are the cheapest lake to boil.)
  • BAD: Quoting only human-team effort: "This would take 2 weeks." (Say: "2 weeks human / ~1 hour CC.")
AI辅助编码使得完成完整工作的边际成本趋近于零。当您提供选项时:
  • 如果选项A是完整实现(完全兼容、覆盖所有边缘情况、100%场景覆盖),而选项B是节省少量工作量的捷径——始终推荐A。在CC+gstack的帮助下,80行代码和150行代码的差异毫无意义。当“完整”仅需多花几分钟时,“足够好”是错误的直觉。
  • 湖泊vs海洋: “湖泊”是可以煮沸的——模块的100%测试覆盖、完整功能实现、处理所有边缘情况、完善的错误路径。“海洋”则不行——重写整个系统、为无法控制的依赖添加功能、耗时数季度的平台迁移。推荐煮沸湖泊,将海洋标记为超出范围。
  • 估算工作量时,始终同时显示两种耗时: 团队人工耗时和CC+gstack耗时。压缩比因任务类型而异——请参考以下标准:
任务类型团队人工CC+gstack压缩比
模板代码/脚手架2天15分钟~100x
测试编写1天15分钟~50x
功能实现30分钟~30x
Bug修复+回归测试4小时15分钟~20x
架构/设计2天4小时~5x
研究/探索1天3小时~3x
  • 此原则适用于测试覆盖、错误处理、文档、边缘情况和功能完整性。不要为了“节省时间”而跳过最后10%的工作——借助AI,这10%仅需几秒钟。
反模式——请勿这样做:
  • 错误:“选择B——它用更少的代码覆盖了90%的价值。”(如果A仅多70行代码,选择A。)
  • 错误:“我们可以跳过边缘情况处理来节省时间。”(借助CC,边缘情况处理仅需几分钟。)
  • 错误:“我们把测试覆盖推迟到后续PR中。”(测试是最容易“煮沸”的湖泊。)
  • 错误:仅引用团队人工耗时:“这需要2周时间。”(应该说:“人工2周 / CC约1小时。”)

Search Before Building

先搜索再构建

Before building infrastructure, unfamiliar patterns, or anything the runtime might have a built-in — search first. Read
~/.claude/skills/gstack/ETHOS.md
for the full philosophy.
Three layers of knowledge:
  • Layer 1 (tried and true — in distribution). Don't reinvent the wheel. But the cost of checking is near-zero, and once in a while, questioning the tried-and-true is where brilliance occurs.
  • Layer 2 (new and popular — search for these). But scrutinize: humans are subject to mania. Search results are inputs to your thinking, not answers.
  • Layer 3 (first principles — prize these above all). Original observations derived from reasoning about the specific problem. The most valuable of all.
Eureka moment: When first-principles reasoning reveals conventional wisdom is wrong, name it: "EUREKA: Everyone does X because [assumption]. But [evidence] shows this is wrong. Y is better because [reasoning]."
Log eureka moments:
bash
jq -n --arg ts "$(date -u +%Y-%m-%dT%H:%M:%SZ)" --arg skill "SKILL_NAME" --arg branch "$(git branch --show-current 2>/dev/null)" --arg insight "ONE_LINE_SUMMARY" '{ts:$ts,skill:$skill,branch:$branch,insight:$insight}' >> ~/.gstack/analytics/eureka.jsonl 2>/dev/null || true
Replace SKILL_NAME and ONE_LINE_SUMMARY. Runs inline — don't stop the workflow.
WebSearch fallback: If WebSearch is unavailable, skip the search step and note: "Search unavailable — proceeding with in-distribution knowledge only."
在构建基础设施、不熟悉的模式或任何运行时可能已有内置实现的功能之前——先搜索。请阅读
~/.gstack/skills/gstack/ETHOS.md
了解完整理念。
三层知识体系:
  • 第一层(久经考验——已发布):不要重复造轮子。但验证的成本几乎为零,偶尔质疑既定方案可能会带来突破性的创新。
  • 第二层(新兴流行——需搜索):但要仔细甄别:人类容易跟风。搜索结果是思考的输入,而非答案。
  • 第三层(第一性原理——最有价值):从特定问题的推理中得出的原创观察。是所有知识中最有价值的。
突破性时刻: 当第一性原理推理揭示传统认知错误时,请明确指出: “EUREKA:每个人都做X是因为[假设]。但[证据]表明这是错误的。Y更好,因为[推理]。”
记录突破性时刻:
bash
jq -n --arg ts "$(date -u +%Y-%m-%dT%H:%M:%SZ)" --arg skill "SKILL_NAME" --arg branch "$(git branch --show-current 2>/dev/null)" --arg insight "ONE_LINE_SUMMARY" '{ts:$ts,skill:$skill,branch:$branch,insight:$insight}' >> ~/.gstack/analytics/eureka.jsonl 2>/dev/null || true
替换SKILL_NAME和ONE_LINE_SUMMARY。此命令需内联执行——不要中断工作流。
WebSearch备选方案: 如果WebSearch不可用,跳过搜索步骤并注明:“搜索不可用——仅使用已发布的知识继续。”

Contributor Mode

贡献者模式

If
_CONTRIB
is
true
: you are in contributor mode. You're a gstack user who also helps make it better.
At the end of each major workflow step (not after every single command), reflect on the gstack tooling you used. Rate your experience 0 to 10. If it wasn't a 10, think about why. If there is an obvious, actionable bug OR an insightful, interesting thing that could have been done better by gstack code or skill markdown — file a field report. Maybe our contributor will help make us better!
Calibration — this is the bar: For example,
$B js "await fetch(...)"
used to fail with
SyntaxError: await is only valid in async functions
because gstack didn't wrap expressions in async context. Small, but the input was reasonable and gstack should have handled it — that's the kind of thing worth filing. Things less consequential than this, ignore.
NOT worth filing: user's app bugs, network errors to user's URL, auth failures on user's site, user's own JS logic bugs.
To file: write
~/.gstack/contributor-logs/{slug}.md
with all sections below (do not truncate — include every section through the Date/Version footer):
undefined
如果
_CONTRIB
的值为
true
:您处于贡献者模式。您是gstack用户,同时也参与gstack的改进。
在每个主要工作流步骤结束时(不是每个命令之后),反思您使用的gstack工具。为您的体验评分(0-10分)。如果评分未达到10分,请思考原因。如果存在明显的、可操作的bug,或者gstack的代码或技能markdown有可以改进的地方——提交现场报告。我们的贡献者可能会帮助我们变得更好!
评分标准参考: 例如,
$B js "await fetch(...)"
曾因gstack未将表达式包裹在async上下文中而失败,报错
SyntaxError: await is only valid in async functions
。这是一个小问题,但用户的输入是合理的,gstack本应处理这种情况——这类问题值得提交报告。比这更轻微的问题可以忽略。
不值得提交的情况: 用户应用的bug、用户URL的网络错误、用户网站的认证失败、用户自己的JS逻辑bug。
提交报告: 编写
~/.gstack/contributor-logs/{slug}.md
文件,包含以下所有部分(不要截断——包括日期/版本页脚之前的所有部分):
undefined

{Title}

{标题}

Hey gstack team — ran into this while using /{skill-name}:
What I was trying to do: {what the user/agent was attempting} What happened instead: {what actually happened} My rating: {0-10} — {one sentence on why it wasn't a 10}
嘿gstack团队——我在使用/{skill-name}时遇到了这个问题:
我尝试做的事情: {用户/agent的操作意图} 实际发生的情况: {实际结果} 我的评分: {0-10} —— {一句话说明未给10分的原因}

Steps to reproduce

复现步骤

  1. {step}
  1. {步骤}

Raw output

原始输出

{paste the actual error or unexpected output here}
{粘贴实际错误或意外输出}

What would make this a 10

如何达到10分体验

{one sentence: what gstack should have done differently}
Date: {YYYY-MM-DD} | Version: {gstack version} | Skill: /{skill}

Slug: lowercase, hyphens, max 60 chars (e.g. `browse-js-no-await`). Skip if file already exists. Max 3 reports per session. File inline and continue — don't stop the workflow. Tell user: "Filed gstack field report: {title}"
{一句话说明gstack应该做出的改进}
日期: {YYYY-MM-DD} | 版本: {gstack版本} | 技能: /{skill}

Slug:小写、用连字符连接、最多60个字符(例如`browse-js-no-await`)。如果文件已存在则跳过。每个会话最多提交3份报告。内联执行此操作并继续——不要中断工作流。告知用户:“已提交gstack现场报告:{标题}”

Completion Status Protocol

完成状态协议

When completing a skill workflow, report status using one of:
  • DONE — All steps completed successfully. Evidence provided for each claim.
  • DONE_WITH_CONCERNS — Completed, but with issues the user should know about. List each concern.
  • BLOCKED — Cannot proceed. State what is blocking and what was tried.
  • NEEDS_CONTEXT — Missing information required to continue. State exactly what you need.
当技能工作流完成时,使用以下之一报告状态:
  • DONE —— 所有步骤成功完成。每个结论都有证据支持。
  • DONE_WITH_CONCERNS —— 已完成,但存在用户需要了解的问题。列出每个问题。
  • BLOCKED —— 无法继续。说明阻塞原因和已尝试的操作。
  • NEEDS_CONTEXT —— 缺少继续所需的信息。明确说明需要的内容。

Escalation

升级处理

It is always OK to stop and say "this is too hard for me" or "I'm not confident in this result."
Bad work is worse than no work. You will not be penalized for escalating.
  • If you have attempted a task 3 times without success, STOP and escalate.
  • If you are uncertain about a security-sensitive change, STOP and escalate.
  • If the scope of work exceeds what you can verify, STOP and escalate.
Escalation format:
STATUS: BLOCKED | NEEDS_CONTEXT
REASON: [1-2 sentences]
ATTEMPTED: [what you tried]
RECOMMENDATION: [what the user should do next]
您可以随时停止并说“这个对我来说太难了”或“我对结果没有信心”。
糟糕的工作比不做更糟。您不会因升级处理而受到惩罚。
  • 如果您尝试某项任务3次均未成功,请停止并升级处理。
  • 如果您对安全敏感的更改不确定,请停止并升级处理。
  • 如果工作范围超出您的验证能力,请停止并升级处理。
升级处理格式:
STATUS: BLOCKED | NEEDS_CONTEXT
REASON: [1-2句话]
ATTEMPTED: [已尝试的操作]
RECOMMENDATION: [用户下一步应采取的行动]

Telemetry (run last)

遥测(最后执行)

After the skill workflow completes (success, error, or abort), log the telemetry event. Determine the skill name from the
name:
field in this file's YAML frontmatter. Determine the outcome from the workflow result (success if completed normally, error if it failed, abort if the user interrupted).
PLAN MODE EXCEPTION — ALWAYS RUN: This command writes telemetry to
~/.gstack/analytics/
(user config directory, not project files). The skill preamble already writes to the same directory — this is the same pattern. Skipping this command loses session duration and outcome data.
Run this bash:
bash
_TEL_END=$(date +%s)
_TEL_DUR=$(( _TEL_END - _TEL_START ))
rm -f ~/.gstack/analytics/.pending-"$_SESSION_ID" 2>/dev/null || true
~/.claude/skills/gstack/bin/gstack-telemetry-log \
  --skill "SKILL_NAME" --duration "$_TEL_DUR" --outcome "OUTCOME" \
  --used-browse "USED_BROWSE" --session-id "$_SESSION_ID" 2>/dev/null &
Replace
SKILL_NAME
with the actual skill name from frontmatter,
OUTCOME
with success/error/abort, and
USED_BROWSE
with true/false based on whether
$B
was used. If you cannot determine the outcome, use "unknown". This runs in the background and never blocks the user.
当技能工作流完成(成功、错误或中止)后,记录遥测事件。从本文件的YAML前置字段
name:
中确定技能名称。根据工作流结果确定结果(正常完成则为success,失败则为error,用户中断则为abort)。
计划模式例外——必须执行: 此命令将遥测数据写入
~/.gstack/analytics/
(用户配置目录,而非项目文件)。技能的前置步骤已写入同一目录——遵循相同的模式。跳过此命令会丢失会话时长和结果数据。
执行以下bash命令:
bash
_TEL_END=$(date +%s)
_TEL_DUR=$(( _TEL_END - _TEL_START ))
rm -f ~/.gstack/analytics/.pending-"$_SESSION_ID" 2>/dev/null || true
~/.claude/skills/gstack/bin/gstack-telemetry-log \
  --skill "SKILL_NAME" --duration "$_TEL_DUR" --outcome "OUTCOME" \
  --used-browse "USED_BROWSE" --session-id "$_SESSION_ID" 2>/dev/null &
SKILL_NAME
替换为前置字段中的实际技能名称,
OUTCOME
替换为success/error/abort,
USED_BROWSE
根据是否使用了
$B
替换为true/false。如果无法确定结果,使用"unknown"。此命令在后台运行,不会阻塞用户操作。

Systematic Debugging

系统化调试

Iron Law

铁则

NO FIXES WITHOUT ROOT CAUSE INVESTIGATION FIRST.
Fixing symptoms creates whack-a-mole debugging. Every fix that doesn't address root cause makes the next bug harder to find. Find the root cause, then fix it.

未完成根本原因调查绝不修复。
修复症状会导致“打地鼠”式的调试。每一个未解决根本原因的修复都会让下一个bug更难找到。先找到根本原因,再进行修复。

Phase 1: Root Cause Investigation

阶段1:根本原因调查

Gather context before forming any hypothesis.
  1. Collect symptoms: Read the error messages, stack traces, and reproduction steps. If the user hasn't provided enough context, ask ONE question at a time via AskUserQuestion.
  2. Read the code: Trace the code path from the symptom back to potential causes. Use Grep to find all references, Read to understand the logic.
  3. Check recent changes:
    bash
    git log --oneline -20 -- <affected-files>
    Was this working before? What changed? A regression means the root cause is in the diff.
  4. Reproduce: Can you trigger the bug deterministically? If not, gather more evidence before proceeding.
Output: "Root cause hypothesis: ..." — a specific, testable claim about what is wrong and why.

在形成任何假设之前,先收集上下文信息。
  1. 收集症状: 阅读错误消息、堆栈跟踪和复现步骤。如果用户未提供足够的上下文,通过AskUserQuestion一次提出一个问题。
  2. 阅读代码: 从症状回溯到潜在原因的代码路径。使用Grep查找所有引用,Read理解逻辑。
  3. 检查最近的更改:
    bash
    git log --oneline -20 -- <affected-files>
    之前是否正常工作?发生了什么变化?回归问题意味着根本原因在差异中。
  4. 复现问题: 您能否确定性地触发这个bug?如果不能,在继续之前收集更多证据。
输出:“根本原因假设:...” —— 关于问题所在及原因的具体、可测试的陈述。

Scope Lock

范围锁定

After forming your root cause hypothesis, lock edits to the affected module to prevent scope creep.
bash
[ -x "${CLAUDE_SKILL_DIR}/../freeze/bin/check-freeze.sh" ] && echo "FREEZE_AVAILABLE" || echo "FREEZE_UNAVAILABLE"
If FREEZE_AVAILABLE: Identify the narrowest directory containing the affected files. Write it to the freeze state file:
bash
STATE_DIR="${CLAUDE_PLUGIN_DATA:-$HOME/.gstack}"
mkdir -p "$STATE_DIR"
echo "<detected-directory>/" > "$STATE_DIR/freeze-dir.txt"
echo "Debug scope locked to: <detected-directory>/"
Substitute
<detected-directory>
with the actual directory path (e.g.,
src/auth/
). Tell the user: "Edits restricted to
<dir>/
for this debug session. This prevents changes to unrelated code. Run
/unfreeze
to remove the restriction."
If the bug spans the entire repo or the scope is genuinely unclear, skip the lock and note why.
If FREEZE_UNAVAILABLE: Skip scope lock. Edits are unrestricted.

形成根本原因假设后,锁定受影响模块的编辑权限,防止范围蔓延。
bash
[ -x "${CLAUDE_SKILL_DIR}/../freeze/bin/check-freeze.sh" ] && echo "FREEZE_AVAILABLE" || echo "FREEZE_UNAVAILABLE"
如果FREEZE_AVAILABLE: 确定包含受影响文件的最窄目录。将其写入冻结状态文件:
bash
STATE_DIR="${CLAUDE_PLUGIN_DATA:-$HOME/.gstack}"
mkdir -p "$STATE_DIR"
echo "<detected-directory>/" > "$STATE_DIR/freeze-dir.txt"
echo "Debug scope locked to: <detected-directory>/"
<detected-directory>
替换为实际目录路径(例如
src/auth/
)。告知用户:“本次调试会话的编辑权限限制在
<dir>/
目录内。这可以防止对无关代码进行更改。运行
/unfreeze
可解除限制。”
如果bug影响整个仓库,或者范围确实不明确,跳过锁定并注明原因。
如果FREEZE_UNAVAILABLE: 跳过范围锁定。编辑权限不受限制。

Phase 2: Pattern Analysis

阶段2:模式分析

Check if this bug matches a known pattern:
PatternSignatureWhere to look
Race conditionIntermittent, timing-dependentConcurrent access to shared state
Nil/null propagationNoMethodError, TypeErrorMissing guards on optional values
State corruptionInconsistent data, partial updatesTransactions, callbacks, hooks
Integration failureTimeout, unexpected responseExternal API calls, service boundaries
Configuration driftWorks locally, fails in staging/prodEnv vars, feature flags, DB state
Stale cacheShows old data, fixes on cache clearRedis, CDN, browser cache, Turbo
Also check:
  • TODOS.md
    for related known issues
  • git log
    for prior fixes in the same area — recurring bugs in the same files are an architectural smell, not a coincidence
External pattern search: If the bug doesn't match a known pattern above, WebSearch for:
  • "{framework} {generic error type}" — sanitize first: strip hostnames, IPs, file paths, SQL, customer data. Search the error category, not the raw message.
  • "{library} {component} known issues"
If WebSearch is unavailable, skip this search and proceed with hypothesis testing. If a documented solution or known dependency bug surfaces, present it as a candidate hypothesis in Phase 3.

检查此bug是否匹配已知模式:
模式特征排查方向
竞态条件间歇性、依赖时序共享状态的并发访问
空值传播NoMethodError、TypeError可选值缺少防护检查
状态损坏数据不一致、部分更新事务、回调、钩子
集成失败超时、意外响应外部API调用、服务边界
配置漂移本地正常、 staging/生产环境失败环境变量、功能标志、数据库状态
缓存过期显示旧数据、清除缓存后恢复Redis、CDN、浏览器缓存、Turbo
同时检查:
  • TODOS.md
    中的相关已知问题
  • git log
    中同一区域的过往修复——同一文件反复出现bug是架构问题的信号,而非巧合
外部模式搜索: 如果此bug与上述已知模式均不匹配,使用WebSearch搜索:
  • "{framework} {通用错误类型}" —— 先脱敏: 去除主机名、IP、文件路径、SQL、客户数据。搜索错误类别,而非原始消息。
  • "{library} {component} known issues"
如果WebSearch不可用,跳过此搜索步骤并继续假设测试。如果找到已记录的解决方案或已知依赖bug,将其作为阶段3的候选假设提出。

Phase 3: Hypothesis Testing

阶段3:假设测试

Before writing ANY fix, verify your hypothesis.
  1. Confirm the hypothesis: Add a temporary log statement, assertion, or debug output at the suspected root cause. Run the reproduction. Does the evidence match?
  2. If the hypothesis is wrong: Before forming the next hypothesis, consider searching for the error. Sanitize first — strip hostnames, IPs, file paths, SQL fragments, customer identifiers, and any internal/proprietary data from the error message. Search only the generic error type and framework context: "{component} {sanitized error type} {framework version}". If the error message is too specific to sanitize safely, skip the search. If WebSearch is unavailable, skip and proceed. Then return to Phase 1. Gather more evidence. Do not guess.
  3. 3-strike rule: If 3 hypotheses fail, STOP. Use AskUserQuestion:
    3 hypotheses tested, none match. This may be an architectural issue
    rather than a simple bug.
    
    A) Continue investigating — I have a new hypothesis: [describe]
    B) Escalate for human review — this needs someone who knows the system
    C) Add logging and wait — instrument the area and catch it next time
Red flags — if you see any of these, slow down:
  • "Quick fix for now" — there is no "for now." Fix it right or escalate.
  • Proposing a fix before tracing data flow — you're guessing.
  • Each fix reveals a new problem elsewhere — wrong layer, not wrong code.

在编写任何修复之前,先验证您的假设。
  1. 验证假设: 在疑似根本原因处添加临时日志语句、断言或调试输出。执行复现操作。证据是否与假设匹配?
  2. 如果假设错误: 在形成下一个假设之前,考虑搜索错误信息。先脱敏——从错误消息中去除主机名、IP、文件路径、SQL片段、客户标识符和任何内部/专有数据。仅搜索通用错误类型和框架上下文:“{component} {脱敏后的错误类型} {framework版本}”。如果错误消息过于具体无法安全脱敏,跳过搜索如果WebSearch不可用,跳过并继续。然后返回阶段1,收集更多证据。不要猜测。
  3. 三次失败规则: 如果3个假设均失败,停止。使用AskUserQuestion:
    已测试3个假设,均不匹配。这可能是架构问题,而非简单的bug。
    
    A) 继续调查——我有一个新的假设:[描述]
    B) 升级处理请人工审核——这需要了解系统的人员处理
    C) 添加日志等待——对此区域进行埋点,下次出现时捕获
危险信号——如果出现以下情况,请放慢速度:
  • “先临时修复一下”——没有“临时”。要么正确修复,要么升级处理。
  • 在追踪数据流之前就提出修复方案——您在猜测。
  • 每次修复都会在其他地方引发新问题——修复的层级错误,而非代码错误。

Phase 4: Implementation

阶段4:实施修复

Once root cause is confirmed:
  1. Fix the root cause, not the symptom. The smallest change that eliminates the actual problem.
  2. Minimal diff: Fewest files touched, fewest lines changed. Resist the urge to refactor adjacent code.
  3. Write a regression test that:
    • Fails without the fix (proves the test is meaningful)
    • Passes with the fix (proves the fix works)
  4. Run the full test suite. Paste the output. No regressions allowed.
  5. If the fix touches >5 files: Use AskUserQuestion to flag the blast radius:
    This fix touches N files. That's a large blast radius for a bug fix.
    A) Proceed — the root cause genuinely spans these files
    B) Split — fix the critical path now, defer the rest
    C) Rethink — maybe there's a more targeted approach

一旦确认根本原因:
  1. 修复根本原因,而非症状。 用最小的更改消除实际问题。
  2. 最小差异: 触及最少的文件、更改最少的代码行数。克制重构相邻代码的冲动。
  3. 编写回归测试,要求:
    • 无修复时失败(证明测试有意义)
    • 有修复时通过(证明修复有效)
  4. 运行完整的测试套件。 粘贴输出结果。不允许出现回归问题。
  5. 如果修复触及超过5个文件: 通过AskUserQuestion告知用户影响范围:
    此修复触及N个文件。对于bug修复来说,影响范围过大。
    
    A) 继续——根本原因确实涉及这些文件
    B) 拆分——先修复关键路径推迟其他部分
    C) 重新思考——可能有更针对性的方案

Phase 5: Verification & Report

阶段5:验证与报告

Fresh verification: Reproduce the original bug scenario and confirm it's fixed. This is not optional.
Run the test suite and paste the output.
Output a structured debug report:
DEBUG REPORT
════════════════════════════════════════
Symptom:         [what the user observed]
Root cause:      [what was actually wrong]
Fix:             [what was changed, with file:line references]
Evidence:        [test output, reproduction attempt showing fix works]
Regression test: [file:line of the new test]
Related:         [TODOS.md items, prior bugs in same area, architectural notes]
Status:          DONE | DONE_WITH_CONCERNS | BLOCKED
════════════════════════════════════════

重新验证: 复现原始bug场景并确认已修复。此步骤为必选项。
运行测试套件并粘贴输出结果。
输出结构化的调试报告:
DEBUG报告
════════════════════════════════════════
症状:         [用户观察到的现象]
根本原因:      [实际存在的问题]
修复:             [更改内容,包含文件:行号引用]
证据:        [测试输出、显示修复有效的复现尝试]
回归测试: [新测试的文件:行号]
相关信息:         [TODOS.md中的条目、同一区域的过往bug、架构说明]
状态:          DONE | DONE_WITH_CONCERNS | BLOCKED
════════════════════════════════════════

Important Rules

重要规则

  • 3+ failed fix attempts → STOP and question the architecture. Wrong architecture, not failed hypothesis.
  • Never apply a fix you cannot verify. If you can't reproduce and confirm, don't ship it.
  • Never say "this should fix it." Verify and prove it. Run the tests.
  • If fix touches >5 files → AskUserQuestion about blast radius before proceeding.
  • Completion status:
    • DONE — root cause found, fix applied, regression test written, all tests pass
    • DONE_WITH_CONCERNS — fixed but cannot fully verify (e.g., intermittent bug, requires staging)
    • BLOCKED — root cause unclear after investigation, escalated
  • 3次以上修复失败→停止并质疑架构。 是架构错误,而非假设失败。
  • 绝不应用无法验证的修复。 如果您无法复现并确认修复有效,不要发布。
  • 绝不说“这个应该能修复问题”。 要验证并证明。运行测试。
  • 如果修复触及超过5个文件→通过AskUserQuestion询问影响范围后再继续。
  • 完成状态:
    • DONE —— 找到根本原因、应用修复、编写回归测试、所有测试通过
    • DONE_WITH_CONCERNS —— 已修复但无法完全验证(例如间歇性bug、需要staging环境)
    • BLOCKED —— 调查后仍不清楚根本原因,已升级处理