一键导入
investigate
// Investigate bugs — single-issue deep root cause analysis or batch parallel investigation from a report or issue list
// Investigate bugs — single-issue deep root cause analysis or batch parallel investigation from a report or issue list
| name | investigate |
| description | Investigate bugs — single-issue deep root cause analysis or batch parallel investigation from a report or issue list |
Perform structured root cause analysis of bugs. Operates in two modes: single-issue deep investigation or batch parallel investigation across multiple issues.
/live-exercise when the trace alone won't close the caseThis skill is the static-tracing layer: read code, form a hypothesis, point at a likely cause. For many bugs that's enough — finish here. But if the bug is reproducible in a running instance AND any of the following apply, escalate to /live-exercise after the trace to validate the theory, add temporary logging and observe it, or iterate fix → re-verify:
Pattern: trace as far as the code alone takes you, identify the candidate cause(s), then hand off to /live-exercise to confirm or refute live. Don't skip the trace — but don't keep tracing past the point where running it would be cheaper.
Stay entirely here for: pure-logic bugs, parser/algorithm correctness, build/config errors, well-isolated functions where the trace is short, or when no running instance is available.
/investigate <symptom or issue reference> # Single deep investigation
/investigate <number> <number> [number...] # Batch parallel investigation
/investigate --from-report [path] [--verdict "..."] [--max 10] # Batch from triage report
--from-report — Reads a triage decisions JSON. If path omitted, uses most recent *-DECISIONS.json in .work/triage/reports/.--verdict — Filter report to specific verdict(s). Defaults to Valid - Needs Triage. Comma-separated. Only applies with --from-report.--max — Maximum parallel investigations. Defaults to 10. Only applies to batch mode.Single mode — invoked with one issue number or a symptom description. Performs a deep, thorough investigation in the current agent context. Best for focused debugging.
Batch mode — invoked with 2+ issue numbers or --from-report. Spawns parallel subagents, each performing an independent investigation. Produces report files. Best for processing a queue of issues.
If the issue is older than 1 year, perform a quick relevance check before the full investigation:
Glob or Grepgit log --since="<issue creation date>" -- <relevant files> for significant changes### Relevance Assessment
[One of:
- "Code path still exists — issue may still be relevant"
- "Code path no longer exists — [file(s)] deleted/removed since issue was filed"
- "Feature area significantly refactored — [summary of changes since issue creation]"
- "Unable to map issue to specific code paths — proceeding with investigation"]
If the code path no longer exists, note this prominently and consider whether the investigation should continue or if the issue should be recommended for closure.
src/system/decorators/ if behavior is unclearsrc/env/node/ and src/env/browser/ pathssrc/env/node/git/sub-providers/ and src/git/sub-providers/Before presenting findings, assess where the diagnosis came from:
Be honest about this. Both are valuable — confirming a reporter's analysis is useful — but the reader should know what the investigation actually contributed.
## Investigation: [Symptom]
### Symptom
[What goes wrong]
### Source Attribution
[One of: "Independent analysis from code tracing" | "Confirms reporter's diagnosis — the issue included [specific detail: code references / file paths / root cause hypothesis] which this investigation verified against current code" | "Mixed — [explain what came from the issue vs. independent tracing]"]
### Code Path
[Entry point] -> [Function 1] -> [Function 2 (@gate)] -> [Function 3]
### Root Cause
[Cause with file:line evidence]
### Alternative Causes Considered
1. [Alternative] — ruled out because [evidence]
### Proposed Fix
[Minimal change to address root cause]
### Impact
- Files to modify: [list]
- Call sites checked: [count]
- Platform paths verified: Node.js [yes/no], Browser [yes/no]
Present findings and proposed fix. Wait for user confirmation before implementing.
Direct mode (2+ issue numbers):
Use the provided issue numbers directly. Proceed to Stage 1.
From-report mode (--from-report):
*-DECISIONS.json in .work/triage/reports/)--verdict filter AND where the issue is a bug (check recommendedLabels or the corresponding markdown report for type info)--max, take the first N and note how many were skippedFor each qualifying issue, use the GitHub CLI to fetch the full issue body and comments:
gh issue view <number> --repo <repo> --json title,body,comments,labels,state,author,createdAt,updatedAt
The repo slug comes from the decisions JSON's corresponding evidence pack, or default to gitkraken/vscode-gitlens.
For each issue, spawn a subagent (using the Agent tool) with:
subagent_type: general-purposeRun subagents in parallel where possible. Each subagent operates independently.
Gather all subagent results and produce report files:
File: .work/triage/reports/YYYY-MM-DD-INVESTIGATION-REPORT.md
# Investigation Report — YYYY-MM-DD
Source: <decisions file path or "direct">
Issues investigated: N
Issues with findings: N
Issues inconclusive: N
---
## Findings
### [#NNNN — Title](https://github.com/<owner>/<repo>/issues/NNNN)
- **Author**: @username (team) | @username
- **Triage verdict**: <original verdict from triage, or "N/A" for direct mode>
- **Investigation result**: Confirmed Bug | Likely Fixed | Cannot Reproduce from Description | Inconclusive | Insufficient Information
- **Confidence**: High | Medium | Low
- **Source attribution**: Independent analysis | Confirms reporter's diagnosis | Mixed
- **Estimated effort**: Small (hours) | Medium (1-3 days) | Large (3+ days) | Unknown
- **Risk level**: Low | Medium | High | Unknown
#### Symptom
<restated from issue>
#### Code Path
<entry point> -> <function chain with file:line references>
#### Root Cause Analysis
<findings or "insufficient information to determine">
#### Alternative Causes Considered
1. <alternative> — ruled out because <evidence>
#### Recommendation
<what to do next — fix approach, request specific info from reporter, close, etc.>
---
## Inconclusive Issues
Issues where investigation could not reach a meaningful conclusion:
- [#NNNN — Title](https://github.com/<owner>/<repo>/issues/NNNN) — <reason: insufficient repro info | vague description | external dependency | etc.>
---
## Classification Matrix
Buckets confirmed/likely bugs by estimated effort and risk to aid prioritization:
| Issue | Effort | Risk | Summary |
| ----- | ------ | ---- | ----------------------------- |
| #NNNN | Small | Low | <one-line description of fix> |
| #NNNN | Medium | High | <one-line description of fix> |
**Effort guide**: Small = isolated change, hours of work; Medium = multiple files/systems, 1-3 days; Large = architectural or cross-cutting, 3+ days.
**Risk guide**: Low = safe, localized change; Medium = touches shared code or has edge cases; High = could regress other features or affects critical paths.
### Quick Wins (Small effort, Low/Medium risk)
- #NNNN — <title>
### Needs Planning (Medium/Large effort or High risk)
- #NNNN — <title> — <why it needs planning>
---
## Summary
- **Confirmed bugs**: N (list issue numbers)
- **Likely already fixed**: N (list issue numbers)
- **Inconclusive**: N (list issue numbers)
- **Skipped (over max)**: N
Write the markdown file and report its path to the user.
Also produce a machine-readable companion file: .work/triage/reports/YYYY-MM-DD-INVESTIGATION-DECISIONS.json
{
"reportId": "<uuid>",
"sourceDecisionsFile": "<path to triage decisions that triggered this, or null for direct mode>",
"generatedAt": "<ISO timestamp>",
"investigations": [
{
"issueNumber": 1234,
"result": "Confirmed Bug | Likely Fixed | Cannot Reproduce | Inconclusive | Insufficient Information",
"confidence": "High | Medium | Low",
"sourceAttribution": "Independent | Confirms Reporter | Mixed",
"estimatedEffort": "Small | Medium | Large | Unknown",
"riskLevel": "Low | Medium | High | Unknown",
"rootCauseSummary": "...",
"proposedFix": "...",
"affectedFiles": ["src/path/to/file.ts"],
"blockedBy": null | "vscode" | "git" | "cli" | "language-server" | "other",
"blockedDetail": "...",
"recommendation": "Fix | Request Info | Close | Needs Planning | Blocked"
}
]
}
Generate a UUID for reportId. Write both files and confirm their paths to the user.
@gate() first@info()/@debug()/@trace(). Check @gate() (promise never resolving) or the actual async operation first.@gate() and @sequentialize(): @gate() returns the SAME promise to concurrent callers. @sequentialize() QUEUES calls. These solve different problems..is() static method with reason discriminator: PushError.is(ex, 'noUpstream'), not instanceof + ex.message.includes(...).@env/ abstraction layer.getScopedLogger() returns stale scope after await in browser. Capture the scope before the first await.errors: throw so catch blocks handle them).This skill can be used standalone or as part of the issue workflow pipeline:
/triage recent → /investigate --from-report → /prioritize --from-report → /update-issues
/triage 5096 → /investigate 5096 → /prioritize 5096 → /update-issues
/investigate 5096 5084 (standalone batch)
/investigate #5096 (standalone single)
Upstream: --from-report consumes triage decisions JSON from /triage.
Downstream: /prioritize --from-report consumes the investigation decisions JSON. /update-issues can also consume it directly.
Source files: src/system/decorators/
@info() / @debug() / @trace() — Logging (log.ts)Same decorator at different log levels. Wraps methods to log entry/exit with timing and scope tracking.
Options (LogOptions):
args — false to suppress, or function for custom formattingexit — true to log return value, or function for custom exit stringonlyExit — Suppress entry log; { after: N } only logs if duration > N mstiming — false to disable; { warnAfter: N } overrides slow threshold (default 500ms)when — Conditional: skip logging entirely if returns falseKey behavior:
.then() — does NOT await themScopedLogger for async context trackinggetScopedLogger() constraints:
await in method body (browser uses counter-based fallback unreliable after await)@info()/@debug()/@trace()@gitlens/scoped-logger-usage enforces bothAsyncLocalStorage for reliable cross-async scope@gate() — Concurrent Call Deduplication (gate.ts)Returns the SAME promise to concurrent callers. Only one invocation runs at a time per instance (or per grouping key).
Options (GateOptions):
timeout — Default: 300000ms (5 minutes)rejectOnTimeout — Default: true. When false, retries instead of rejectingKey behavior:
$gate$methodName property.finally() when promise settlesop/gate/deadlock)CancellationError (or retries if rejectOnTimeout: false)getGroupingKey creates independent gates per keyCommon hang pattern: If a gated method hangs, check what the promise is waiting for. Is there a circular dependency? Is a nested gated call waiting on the outer gate?
@memoize() — Result Caching (memoize.ts)Caches return value permanently on instance via Object.defineProperty (non-writable, non-configurable).
Options (MemoizeOptions):
resolver — Custom cache key generator from argumentsversion — 'providers' for version-keyed invalidationKey behavior:
$memoize$methodNameinvalidateMemoized('providers') bumps counter causing cache missObject.hasOwn(this, prop) before computing@sequentialize() — Sequential Execution Queue (sequentialize.ts)Queues async calls to execute one at a time (unlike @gate() which deduplicates).
Options (SequentializeOptions):
getDedupingKey — Consecutive calls with same key share result while waitinggetQueueKey — Creates independent parallel queues per keyKey behavior:
.then() — each waits for previous to completegetQueueKey, all calls share single queuegetQueueKey, different keys execute in parallelExecution order is bottom-up (outermost runs first):
@debug() // Runs 1st: creates scope, logs entry/exit
@gate() // Runs 2nd: deduplicates concurrent calls
async method() { ... }
Debugging priority:
@gate() — hangs, timeouts, deadlocks@memoize() — stale data, cached rejectionsUse when starting feature work that needs isolation from current workspace or before executing implementation plans - creates isolated git worktrees following GitLens conventions
Use whenever any UI-bearing work touches a running instance — building or fixing a feature, ship-gating, auditing, OR debugging visible bugs (flaky behavior, intermittent rendering, "sometimes does X" reports, hover/focus/animation glitches, layout overflow). Keep a running instance in the loop and exercise it as a user would. Adaptive depth from tactical fix-loop to ship-gate audit. Not for pure-logic diff review.
Use for one-off / single-question inspection of the running GitLens extension — examining UI state, reading logs, checking feature flags, dispatching a command, or asking "what does the live DOM look like right now". Reference for `vscode-inspector` MCP primitives. For iterative debug-and-fix loops on UI bugs (sweep → fix → re-verify), use `/live-exercise` instead.
Use when you want to iterate on a feature interactively with the user watching a running instance — pair-programming rhythm for UI-heavy work, redesigns, copy tightening, layout exploration, or any "let me just show you what I want" session. Not for systematic audit (/live-exercise) or perf-tuning (/live-perf).
Use when you want to measure and improve the performance of a feature in the running extension, hunt regressions, or perf-tune before shipping. Standalone for perf-tuning an existing feature; also invoked by /live-exercise Phase 7. Not for static code review without measurement.
Use to audit a component, file, or directory for WCAG 2.1 AA accessibility compliance. Detects ARIA anti-patterns, missing semantics, keyboard gaps, and color-only information. Safety-first — refuses to emit fixes that would create a new accessibility bug. Scope is always explicit; do not use for page-level flow or cross-program planning.