You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: .opencode/commands/investigate.md
+97-32Lines changed: 97 additions & 32 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -3,51 +3,84 @@ description: Investigate a bug from a Sentry issue or error description, biasing
3
3
subtask: false
4
4
---
5
5
6
-
Load the `test-driven-investigation`, `investigation-notes`, `find-and-run-tests`, `parent-project-skills`, and `dad-jokes` skills, then investigate: $ARGUMENTS
6
+
Load the `test-driven-investigation`, `investigation-notes`, `find-and-run-tests`,
7
+
`parent-project-skills`, and `dad-jokes` skills, then investigate: $ARGUMENTS
7
8
8
9
## Prerequisites
9
10
10
-
This command uses Sentry MCP tools when given a Sentry issue ID or URL. The Sentry MCP connection requires a user-specific `X-Sentry-Token` header configured in `~/.config/opencode/opencode.json` under `mcp.sentry.headers`. If the Sentry tools fail with auth errors, tell the user to check their token configuration and stop — do not guess at issue details.
11
+
Use the Sentry MCP tools when given a Sentry issue ID or URL. The Sentry MCP connection requires a
12
+
user-specific `X-Sentry-Token` header configured in `~/.config/opencode/opencode.json` under
13
+
`mcp.sentry.headers`. If the Sentry tools fail with auth errors, tell the user to check their token
14
+
configuration and stop — do not guess at issue details.
11
15
12
16
## Parsing the argument
13
17
14
18
The argument can be:
15
19
16
20
-**A Sentry issue ID** (e.g., `6181478`) — fetch from Sentry
17
21
-**A Sentry short ID** (e.g., `EDGEWORKER-RUNTIME-4MS`) — fetch from Sentry
18
-
-**A Sentry URL** (e.g., `https://sentry.io/organizations/.../issues/...`) — extract the issue ID, fetch from Sentry
19
-
-**A plain text description** (e.g., `"concurrent write()s not allowed" in kj/compat/http.c++`) — skip Sentry, go straight to orientation
22
+
-**A Sentry URL** (e.g., `https://sentry.io/organizations/.../issues/...`) — extract the issue ID,
23
+
fetch from Sentry
24
+
-**A plain text description** (e.g., `"concurrent write()s not allowed" in kj/compat/http.c++`) —
25
+
skip Sentry, go straight to orientation
20
26
21
27
## Steps
22
28
29
+
### 0. Create a tracking document
30
+
31
+
Create a tracking document in the `investigation-notes` tool to keep track of hypotheses, code read,
32
+
and test results. **Always** actively consult and update this document throughout to avoid losing
33
+
insights, going in circles, or forgetting what you've tried. See the "Investigation Notes" section
34
+
below for format and rules.
35
+
23
36
### 1. Extract the error
24
37
25
38
**If Sentry issue:**
26
39
27
40
1. Fetch the issue details with `sentry_get_sentry_issue`.
28
-
2. Fetch the most recent event with `sentry_list_sentry_issue_events` (limit 1), then `sentry_get_sentry_event` to get the full stack trace.
41
+
2. Fetch the most recent event with `sentry_list_sentry_issue_events` (limit 1), then
42
+
`sentry_get_sentry_event` to get the full stack trace.
29
43
3. Extract:
30
44
- The **error message** (assertion text, exception message, crash description)
31
45
- The **assertion/crash site** (file and line from the top of the stack)
32
-
- The **entry point** (the outermost workerd/KJ/capnp frame in the stack — where the operation started)
46
+
- The **entry point** (the outermost workerd/KJ/capnp frame in the stack — where the operation
47
+
started)
48
+
- The **time range** of occurrences (when it started, if it's increasing in rate, etc.)
49
+
- Identify the issue **status**: is it new, regressed, or longstanding
33
50
34
51
**If plain text:** Parse the error message and file reference from the description.
35
52
36
-
**Output to user:** The error message, crash site, and entry point. One short paragraph. Do not go deeper yet.
53
+
**Output to user:** The error message, crash site, and entry point, time range, and status.
54
+
One short paragraph. Do not go deeper yet.
37
55
38
56
### 2. Orient
39
57
40
58
Find three things:
41
59
42
-
1.**The crash site source.** Read the assertion/crash line and its immediate context (~50 lines). Understand what invariant was violated and what state would cause it. If the crash is in a C++ class method, **use the `cross-reference` tool** to quickly locate the header, implementation files, JSG registration, and test files for that class.
60
+
1.**The crash site source.** Read the assertion/crash line and its immediate context (~50 lines).
61
+
Understand what invariant was violated and what state would cause it. If the crash is in a C++
62
+
class method, **use the `cross-reference` tool** to quickly locate the header, implementation
63
+
files, JSG registration, and test files for that class.
64
+
65
+
2.**Recent changes.** If the incident being investigated started, re-occurred, or increased in rate
66
+
recently, look at the git history around the crash site to see if recent changes may have caused
67
+
the bug. Use `git blame` to find when the crash line or the code around it was last modified, and
68
+
`git log` to see recent commits in that file.
43
69
44
-
2.**The test file.** Use `/find-test` on the source file containing the crash site (the cross-reference output may already list relevant test files). If no test exists, identify the nearest test file in the same directory.
70
+
3.**The test file.** Use `/find-test` on the source file containing the crash site (the
71
+
cross-reference output may already list relevant test files). If no test exists, identify the
72
+
nearest test file in the same directory.
45
73
46
-
3.**Existing feature tests.** Search for existing tests that exercise the _feature_ involved in the bug — not just tests near the crash site file. The crash may be in `pipeline.c++` but the relevant working test may be an integration test in a completely different directory. These existing tests encode setup, verification, and framework patterns you need. They are your starting template.
74
+
4.**Existing feature tests.** Search for existing tests that exercise the _feature_ involved in the
75
+
bug — not just tests near the crash site file. The crash may be in `pipeline.c++` but the relevant
76
+
working test may be an integration test in a completely different directory. These existing tests
77
+
encode setup, verification, and framework patterns you need. They are your starting template.
47
78
48
-
4.**The build command.** Construct the exact `bazel test` invocation to run a single test case from that test file.
79
+
5.**The build command.** Construct the exact `bazel test` invocation to run a single test case from
80
+
that test file.
49
81
50
-
**Output to user:** The crash site with a one-sentence explanation of the invariant, the test file path, and the build command.
82
+
**Output to user:** The crash site with a one-sentence explanation of the invariant, the test file
83
+
path, and the build command.
51
84
52
85
### 3. Hypothesize
53
86
@@ -57,43 +90,64 @@ Form a hypothesis in the format:
57
90
58
91
This does not need to be correct. It needs to be testable. State it to the user.
59
92
60
-
Ask for clarification or additional details if you cannot form a hypothesis with the information you have. But do not ask for more information just to delay writing a test.
93
+
Ask for clarification or additional details if you cannot form a hypothesis with the information
94
+
you have. But do not ask for more information just to delay writing a test.
61
95
62
96
### 4. Write the test
63
97
64
-
**Start from an existing test if one exists** (from step 2.3). Clone it and modify the single variable that your hypothesis targets (disable an autogate, change a config flag, alter the setup). This is almost always faster and more correct than writing from scratch, because existing tests already have the right verification (subrequest checks, expected log patterns, shutdown handling).
98
+
**Start from an existing test if one exists** (from step 2.3). Clone it and modify the single
99
+
variable that your hypothesis targets (disable an autogate, change a config flag, alter the setup).
100
+
This is almost always faster and more correct than writing from scratch, because existing tests
101
+
already have the right verification (subrequest checks, expected log patterns, shutdown handling).
65
102
66
103
If no existing test is suitable, write a new one that:
67
104
68
105
- Sets up the minimum state to reach the crash site
69
106
- Performs the operation described in the hypothesis
70
-
-**Includes observable verification** — the test must check that the feature actually ran, not just that nothing crashed. Use subrequest expectations, check for feature-specific log lines, or verify side effects.
107
+
-**Includes observable verification** — the test must check that the feature actually ran, not
108
+
just that nothing crashed. Use subrequest expectations, check for feature-specific log lines, or
109
+
verify side effects.
71
110
- Asserts the expected behavior (what _should_ happen if the bug didn't exist)
72
111
73
112
Keep it short. Prefer public API. Do not try to reproduce the full production call stack.
74
113
75
-
### 5. Run the test
114
+
Do not interrupt your flow to investigate tangents while writing the test. If you
115
+
realize you need to understand something else to write the test, make a note of it
116
+
and move on — you can investigate it in the next iteration if the test doesn't
117
+
reproduce the bug.
76
118
77
-
Build and run using the command from step 2. **Start the build immediately.** Do not read more code before starting the build.
119
+
### 5. Run the test
78
120
79
-
While waiting for the build:
121
+
Build and run using the command from step 2. **Start the build immediately.** Do not read more code
122
+
before starting the build.
80
123
81
-
- Read code that would inform the **next** test iteration if this one doesn't reproduce the bug
82
-
- Do NOT use the wait time to second-guess the current test
124
+
Using parallel sub-agents, waiting for the build, read code that would inform the **next** test
125
+
iteration if this one doesn't reproduce the bug
83
126
84
127
### 6. Validate and iterate
85
128
86
-
**After every test run, first:** Update the tracking document (if using one). Then check the test output for evidence the code path was exercised — feature-specific log lines, subrequests, RPC calls. A test that passes with no evidence the feature ran is not a valid result.
129
+
After every test run:
130
+
131
+
1.**Always** update the tracking document (if using one)
132
+
2.**Always** check the test output for evidence the code path was exercised — feature-specific log
133
+
lines, subrequests, RPC calls. A test that passes with no evidence the feature ran is not a valid
134
+
result.
87
135
88
136
Based on the result:
89
137
90
-
-**Test fails as expected** → the mechanism is confirmed. Report findings to the user. Read code with purpose to find the fix, not to find the bug.
91
-
-**Test passes with evidence the feature ran** → hypothesis was wrong. Adjust the hypothesis, update the test, run again. Tell the user what you learned.
92
-
-**Test passes with NO evidence the feature ran** → the test is not exercising the code path. Do not read more source code to explain why. Fix the test first — compare it against existing working tests to find what's missing.
93
-
-**Test doesn't compile** → fix the compilation error and rerun. This is not a setback, it's a normal part of the process.
138
+
-**Test fails as expected** → the mechanism is confirmed. Report findings to the user. Read code
139
+
with purpose to find the fix, not to find the bug.
140
+
-**Test passes with evidence the feature ran** → hypothesis was wrong. Adjust the hypothesis,
141
+
update the test, run again. Tell the user what you learned.
142
+
-**Test passes with NO evidence the feature ran** → the test is not exercising the code path. Do
143
+
not read more source code to explain why. Fix the test first — compare it against existing working
144
+
tests to find what's missing.
145
+
-**Test doesn't compile** → fix the compilation error and rerun. This is not a setback, it's a
146
+
normal part of the process.
94
147
-**Test crashes differently** → follow the new trail but note the divergence. Tell the user.
95
148
96
-
Repeat until the bug mechanism is confirmed or you've exhausted reasonable hypotheses (at which point, report what you've tried and what you've ruled out).
149
+
Repeat until the bug mechanism is confirmed or you've exhausted reasonable hypotheses (at which
150
+
point, report what you've tried and what you've ruled out).
97
151
98
152
### 7. Report
99
153
@@ -106,10 +160,21 @@ When the mechanism is confirmed, output:
106
160
107
161
## Rules
108
162
109
-
-**Work in parallel whenever possible.** Don't wait for the build to finish before reading code that would inform the next test iteration. Use the build time to maximize your learning and progress. Investigate multiple hypotheses in parallel if you can, but do not let this delay writing and running tests.
110
-
-**Do not spend more too much time reading code before the first test is written and building.** If you hit 15 tool calls, write whatever test you can with your current understanding.
111
-
-**Do not re-read the same function more than twice.** If you catch yourself doing this, write a test immediately.
112
-
-**Do not try to trace the full call stack before writing a test.** The test will tell you if your understanding is correct.
163
+
-**Always work in parallel whenever possible.** Don't wait for the build to finish before reading
164
+
code that would inform the next test iteration. Use the build time to maximize your learning and
165
+
progress. Investigate multiple hypotheses in parallel if you can, but do not let this delay
166
+
writing and running tests.
167
+
-**Do not keep endlessly reading code before the first test is written and building.** If you hit
168
+
15 tool calls, write whatever test you can with your current understanding.
169
+
-**Do not re-read the same function more than twice.** If you catch yourself doing this, update
170
+
the tracking document to record findings and write a test immediately.
171
+
-**Do not trace the full call stack before writing a test.** The test will tell you if your
172
+
understanding is correct.
113
173
-**Every hypothesis must be tested, not just reasoned about.**
114
-
-**Update the tracking document with each iteration.** If a tracking document is being used, update the hypotheses, code read, and test results sections so you have a clear record of your investigation process. Particularly after compaction, if the tracking document is outdated, update it before coninuing to the next step.
115
-
-**Never** miss an opportunity for a good dad joke (using the `dad-jokes` skill). Don't overdo it, but don't avoid them either. When summarizing, **always** preserve any jokes from the subagent output, and **always** including the intro prefix ("Here's a dad joke for you:", etc.) so the user knows it's intentional.
174
+
-**Update the tracking document with each iteration.** If a tracking document is being used, update
175
+
the hypotheses, code read, and test results sections so you have a clear record of your
176
+
investigation process. After compaction, **always** update the tracking document before continuing
177
+
to the next step.
178
+
-**Never** miss an opportunity for a good dad joke (using the `dad-jokes` skill). Don't overdo it.
179
+
When summarizing, **always** preserve any jokes from the subagent output, and **always** including
180
+
the intro prefix ("Here's a dad joke for you:", etc.) so the user knows it's intentional.
description: Mandatory rules for running bazel tests during development. Load this skill before running any bazel test command, especially when validating fixes or verifying regression tests. Prevents false confidence from cached results, filter flags that silently match nothing, and partial test runs that miss breakage.
4
+
---
5
+
6
+
# Bazel Test Hygiene
7
+
8
+
## The Three Rules
9
+
10
+
### 1. Always disable caching
11
+
12
+
```bash
13
+
bazel test //... --nocache_test_results
14
+
```
15
+
16
+
**Why:** Bazel's action cache can serve stale test binaries even after you edit source files. Without `--nocache_test_results`, you may be running the OLD binary and seeing OLD results. This is not hypothetical — it has caused real false-positive/false-negative confusion in this repo.
17
+
18
+
**Always include `--nocache_test_results`.** No exceptions.
19
+
20
+
### 2. Keep it simple — no filter flags
21
+
22
+
Do NOT use `--test_arg='-f'` or similar filter flags to run individual test cases.
23
+
24
+
**Why:** KJ test's `-f` flag silently passes when zero tests match. If you typo the filter or the test name changes, bazel reports "PASSED" with zero tests actually run. This gives completely false confidence.
25
+
26
+
**Run the full test target.** If you need to check a specific test, look for its name in the full output. If the full suite is too slow, run the specific test _target_ (e.g., `//src/workerd/api:streams/standard-test@`), not a filtered subset within a target.
27
+
28
+
### 3. Run the full suite before claiming done
29
+
30
+
A single test target passing does not mean you haven't broken something else. Fixes to shared code (queue.c++, standard.c++, common.h) can break tests in completely different directories.
31
+
32
+
**Before claiming any fix is complete:**
33
+
34
+
```bash
35
+
bazel test //... --nocache_test_results
36
+
```
37
+
38
+
Check the final summary line: `Executed N out of N tests: N tests pass.` All N must match. If any test fails, the fix is not done.
39
+
40
+
## Red-Green Verification for Regression Tests
41
+
42
+
When writing a regression test for a bug fix, you MUST verify the test actually catches the bug:
43
+
44
+
1.**Green:** Run `bazel test //... --nocache_test_results` — all tests pass (fix in place)
45
+
2.**Red:** Remove the fix, run `bazel test //... --nocache_test_results` — the new test(s) MUST fail
46
+
3.**Green:** Restore the fix, run `bazel test //... --nocache_test_results` — all tests pass again
47
+
48
+
If step 2 passes (test doesn't fail without the fix), the test is not testing what you think. Go back and fix the test.
49
+
50
+
**Do the red-green on the full suite**, not just the one target. This catches two problems at once: (a) the regression test actually detects the bug, and (b) the fix doesn't break anything else.
0 commit comments