AgentSkillsCN

trace-to-root

通过自下而上的数据追溯,系统性地排查症状背后的根源。借助 HelixDB 构建关系图,再配合 Repo Prompt 进行深入分析与检查。当遇到 bug 或意外行为时,可启动此调试流程。

SKILL.md
--- frontmatter
name: trace-to-root
description: Systematic debugging by tracing data backwards from symptom to root cause. Uses HelixDB for relationships, Repo Prompt for inspection. Trigger when investigating bugs or unexpected behavior.

Root Cause Tracing

Purpose

Find the actual source of bugs by tracing data flow backwards. Bugs are symptoms; this finds the disease.

When to Use

  • Component renders wrong data
  • Test failing unexpectedly
  • API returning unexpected shape
  • "It worked before" situations
  • Integration appears broken

Prerequisites

  • Territory mapped (or at least anchor identified)
  • Symptom clearly identified (what's wrong, where it appears)
  • HelixDB + Repo Prompt connected

Protocol

Step 1: Locate Symptom

Identify the exact expression that's wrong:

code
read_file(path: "<symptom_file>", start_line: N, limit: 30)

Document:

  • File and line number
  • Variable or expression
  • Expected value vs actual value

Step 2: Find Data Source (HelixDB)

If symptom is a prop:

code
helix: get_references("<ComponentName>")

→ Shows where component is rendered, what props passed

If symptom is from hook/function:

code
helix: get_definitions("<hook_or_function>")

→ Shows implementation

If symptom is from context/state:

code
helix: search_code("<context_name> provider", limit: 5)

→ Shows where state originates

Step 3: Walk the Chain (Iterative)

For each link discovered:

Read the handoff point:

code
read_file(path: "<source_file>", start_line: N, limit: 30)

Check for transformation bugs:

PatternRiskExample
Field renamingData lostskuPartsparts
Defensive codeSilent failure?., ||, ??
Type assertionsType mismatch maskedas any, as Type
Computed valuesLogic errorisManual = !!sku
Default valuesOverride intended valuevalue ?? defaultValue

Document each hop:

code
API response
  → convex/products.ts:generateSkuPreview (transforms)
  → Products.tsx:useQuery (receives)
  → SkuPillEditor (consumes via props)

Step 4: Identify Disconnect

The bug lives where the contract breaks:

  • Shape changes unexpectedly
  • Transformation drops/corrupts data
  • Assumption violated
  • Types say X, runtime says Y

Step 5: Verify Hypothesis

Check producer output:

code
get_code_structure(scope: "paths", paths: ["<producer_file>"])

Check consumer expectation:

code
read_file(path: "<consumer_file>", start_line: N, limit: 20)

Compare fields, types, optionality.


Output Format

markdown
## Root Cause Trace: [Bug Description]

### Symptom
| Property | Value |
|----------|-------|
| File | SkuPillEditor.tsx |
| Line | 45 |
| Expression | `isManuallyEdited` |
| Expected | false (auto-generated SKU) |
| Actual | true |

### Data Flow Trace

| Step | File:Line | Action | Data Shape |
|------|-----------|--------|------------|
| 1 | convex/products.ts:67 | generateSkuPreview returns | `{ generatedSku, skuParts }` |
| 2 | Products.tsx:123 | useQuery receives | `{ generatedSku, skuParts }` |
| 3 | Products.tsx:145 | computes isManuallyEdited | `!!formData.sku` ← **BUG** |
| 4 | Products.tsx:189 | passes to SkuPillEditor | `isManuallyEdited=true` |

### Root Cause
| Property | Value |
|----------|-------|
| Location | Products.tsx:145 |
| Expression | `isManuallyEdited = !!formData.sku` |
| Problem | Treats any non-empty SKU as manually edited |
| Fix | Compare `formData.sku !== skuPreview?.generatedSku` |

### Verification
- [ ] Producer returns correct shape
- [ ] Fix applied at root cause (not symptom)
- [ ] Downstream consumers unaffected by fix

Common Bug Patterns

PatternWhy It BreaksFix
!!valueEmpty string is falsy but validCheck against explicit sentinel
value?.fieldSwallows undefined silentlyFail explicitly or default intentionally
as anyBypasses type checkingRemove cast, fix actual type
data.field when optionalRuntime error on undefinedAdd existence check
Wrong comparison== vs ===, string vs numberUse strict equality, normalize types

Limitations

  • Cannot trace runtime-only data (API responses not in code)
  • Dynamic property access (obj[key]) hard to trace
  • Async timing bugs may not show in static trace
  • State mutations outside React/framework patterns may be invisible

Next Actions After Tracing

  1. Fix at root cause, not symptom
  2. Run blast-radius if fix changes a contract
  3. Run verify-seams after fix applied
  4. Consider extract-contract if pattern could recur