Dashboard › calm-forest › Session ses_286762ab
ses_286762abfffeZ3bofHyPvtOPIgWe have a bunch of "unexpected fetch call to" warnings in our unit tests: https://github.com/getsentry/cli/actions/runs/24265638656/job/70864771196
We should really fix these. <system-reminder> Plan mode is active. The user indicated that they do not want you to execute yet -- you MUST NOT make any edits (with the exception of the plan file mentioned below), run any non-readonly tools (including changing configs or making commits), or otherwise make any changes to the system. This supersedes any other instructions you have received.
No plan file exists yet. You should create your plan at /home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/calm-forest/.opencode/plans/1775860569408-mighty-cactus.md using the write tool. You should build your plan incrementally by writing to or editing this file. NOTE that this is the only file you are allowed to edit - other than this you are only allowed to take READ-ONLY actions.
Goal: Gain a comprehensive understanding of the user's request by reading through code and asking them questions. Critical: In this phase you should only use the explore subagent type.
Focus on understanding the user's request and the code associated with their request
Launch up to 3 explore agents IN PARALLEL (single message, multiple tool calls) to efficiently explore the codebase.
The user wants me to fix "unexpected fetch call to" warnings in their unit tests. Let me first look at the CI logs to understand what's happening, and then explore the codebase to understand the test infrastructure.
Let me start by fetching the CI logs and exploring the test setup in parallel. I'll start by understanding the CI warnings and the test infrastructure. Let me explore in parallel.
task_id: ses_2867601f5ffeG0Opw1WdwW7e3d (for resuming to continue this task if needed)
<task_result>
I now have a comprehensive understanding. Here is my complete analysis:
---
## Where the "unexpected fetch call" warning is defined/generated
**File:** `/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/calm-forest/test/preload.ts` (lines 121-128)
This is the sole origin of the warning. The preload script is loaded before every test file via `bunfig.toml`:
```toml
[test]
preload = ["./test/preload.ts"]
```
The relevant code (lines 109-131):
```typescript
const originalFetch = globalThis.fetch;
const mockFetch = async (input: RequestInfo | URL, _init?: RequestInit) => {
const url = getUrlFromInput(input);
console.error(`[TEST] Unexpected fetch call to: ${url}`);
console.error(
"[TEST] Tests should mock fetch or use SENTRY_TEST_* credentials for real API calls"
);
throw new Error(`Unmocked fetch call to: ...
task_id: ses_28675eda7ffe5XC6FyVaEtpJNa (for resuming to continue this task if needed)
<task_result>
Now I have a comprehensive picture. Here is my full report:
---
## Test Infrastructure Analysis for Sentry CLI
### 1. The Full Fetch/API Call Chain (Commands → HTTP Requests)
The call chain has 4 layers:
**Layer 1: Command `func()` body** (e.g., `src/commands/issue/list.ts`)
- Calls domain API functions from `src/lib/api-client.ts` (barrel re-export)
- Example: `listIssuesPaginated(org, query, options)`
**Layer 2: Domain API modules** (e.g., `src/lib/api/issues.ts`, `src/lib/api/organizations.ts`)
- Two sub-paths depending on endpoint type:
**Path A — `@sentry/api` SDK functions** (most endpoints):
```
sdkListOrganizations({ ...getSdkConfig(regionUrl) })
→ unwrapResult(result, context) // extracts data or throws ApiError
```
The SDK functions receive `{ baseUrl, fetch, throwOnError: false }` from `getSdkConfig()`. ...
Now I have a good understanding of the test infrastructure. Let me fetch the actual CI logs to see which specific tests are producing "unexpected fetch call to" warnings. The web fetch failed, so let me try a different approach - maybe I can use the gh CLI to get the logs. Good, I have a solid understanding of the test infrastructure. Let me get the actual CI logs to see which specific tests are producing warnings.
grep: (standard input): binary file matches
Unit Tests Unit Tests 2026-04-10T22:33:54.7377351Z [TEST] Unexpected fetch call to: https://sentry.io/api/0/organizations/my-org/ Unit Tests Unit Tests 2026-04-10T22:33:55.7392444Z [TEST] Unexpected fetch call to: https://sentry.io/api/0/organizations/my-org/ Unit Tests Unit Tests 2026-04-10T22:33:57.7413030Z [TEST] Unexpected fetch call to: https://sentry.io/api/0/organizations/my-org/ Unit Tests Unit Tests 2026-04-10T22:34:16.0664692Z [TEST] Unexpected fetch call to: https://sentry.io/api/0/users/me/regions/ Unit Tests Unit Tests 2026-04-10T22:34:17.0667412Z [TEST] Unexpected fetch call to: https://sentry.io/api/0/users/me/regions/ Unit Tests Unit Tests 2026-04-10T22:34:19.0678083Z [TEST] Unexpected fetch call to: https://sentry.io/api/0/users/me/regions/ Unit Tests Unit Tests 2026-04-10T22:34:19.0685025Z [TEST] Unexpected fetch call to: https://sentry.io/api/0/organizations/ Unit Tests Unit Tests 2026-04-10T22:34:20.0689764Z [TEST] Unexpected fetch call to: ...
Let me get more context around these warnings to see which test files are generating them.
182
Unit Tests Unit Tests 2026-04-10T22:34:37.3744256Z ##[group]test/lib/index.test.ts: Unit Tests Unit Tests 2026-04-10T22:35:09.7041062Z ##[group]test/lib/help-positional.test.ts: Unit Tests Isolated Tests 2026-04-10T22:36:42.6861407Z ##[group]test/isolated/login-reauth.test.ts:
Unit Tests Unit Tests 2026-04-10T22:33:54.0480655Z ##[group]test/types/dashboard.test.ts: Unit Tests Unit Tests 2026-04-10T22:33:54.1108762Z ##[group]test/types/seer.test.ts: Unit Tests Unit Tests 2026-04-10T22:33:54.1117399Z ##[group]test/types/dashboard.property.test.ts: Unit Tests Unit Tests 2026-04-10T22:33:54.1619619Z ##[group]test/types/oauth.test.ts: Unit Tests Unit Tests 2026-04-10T22:33:54.1647643Z ##[group]test/lib/completions.test.ts: Unit Tests Unit Tests 2026-04-10T22:33:54.4696431Z ##[group]test/lib/config.test.ts: Unit Tests Unit Tests 2026-04-10T22:33:54.7038473Z ##[group]test/lib/detect-agent.test.ts: Unit Tests Unit Tests 2026-04-10T22:33:54.7243397Z ##[group]test/lib/resolve-target-listing.test.ts: Unit Tests Unit Tests 2026-04-10T22:33:54.7377351Z [TEST] Unexpected fetch call to: https://sentry.io/api/0/organizations/my-org/ Unit Tests Unit Tests 2026-04-10T22:33:55.7392444Z [TEST] Unexpected fetch call to: https://sentry.io/api/0/organizations/my-org/ Unit ...
Now I can see the pattern clearly. The warnings come primarily from three test files:
test/lib/resolve-target-listing.test.ts (around 22:33:54) - /organizations/my-org/ warningstest/lib/resolve-target.test.ts (around 22:34:16) - /users/me/regions/ and /organizations/ warningstest/lib/index.test.ts (around 22:34:37) - /organizations/1/, /organizations/123/, /organizations/0/, /projects/1/.../ warningsLet me scan the rest of the log to see if there are any additional warnings or isolated test failures I might have missed.
Unit Tests Unit Tests 2026-04-10T22:36:28.1736018Z ##[group]test/commands/log/view.func.test.ts: Unit Tests Unit Tests 2026-04-10T22:36:28.1894168Z ##[group]test/commands/log/view.test.ts: Unit Tests Unit Tests 2026-04-10T22:36:28.2001989Z ##[group]test/commands/log/list.test.ts: Unit Tests Unit Tests 2026-04-10T22:36:28.5536817Z [TEST] Unexpected fetch call to: https://sentry.io/api/0/users/me/regions/ Unit Tests Unit Tests 2026-04-10T22:36:28.5549717Z [TEST] Unexpected fetch call to: https://sentry.io/api/0/users/me/regions/ Unit Tests Unit Tests 2026-04-10T22:36:28.5560003Z [TEST] Unexpected fetch call to: https://sentry.io/api/0/organizations/ Unit Tests Unit Tests 2026-04-10T22:36:28.5571355Z [TEST] Unexpected fetch call to: https://sentry.io/api/0/organizations/ Unit Tests Unit Tests 2026-04-10T22:36:28.5582406Z [TEST] Unexpected fetch call to: https://sentry.io/api/0/organizations/ Unit Tests Unit Tests 2026-04-10T22:36:28.5593132Z [TEST] Unexpected fetch call to: ...
Now I can see clearly which test files produce the warnings. Let me map them out:
test/lib/resolve-target-listing.test.ts (22:33:54) → /organizations/my-org/ (3 warnings from retry)
test/lib/resolve-target.test.ts (22:34:16) → /users/me/regions/ and /organizations/ (many warnings)
test/lib/index.test.ts (22:34:37) → /organizations/1/, /organizations/123/, /organizations/0/, /projects/1/.../, /projects/123/.../, /projects/0/.../ (many warnings)
test/commands/log/list.test.ts (22:36:28) → /users/me/regions/ and /organizations/ (many warnings)
test/isolated/login-reauth.test.ts (22:36:42) → /users/me/regions/ and /organizations/ (5 warnings)
I need to dig into these test files to see what's causing the fetch calls to leak. Now I have a clear picture of which test files produce warnings. Let me examine them.
task_id: ses_286726deeffe44b1UdgodjltY3 (for resuming to continue this task if needed)
<task_result>
No env files. Let me just accept that the DSN detection somehow finds DSN data (perhaps from previous test runs' leftovers, or from a different path) and focus on the fix recommendations since I've identified the root causes for all files.
Now let me compile the complete report:
---
## Complete Analysis
### File 1: `test/lib/resolve-target-listing.test.ts`
**Leaked URL:** `https://sentry.io/api/0/organizations/my-org/` (3 times — 1 original + 2 retries)
**Leaking test:** `resolveOrgProjectTarget > returns org and project for explicit type` (line 139-148)
**Call chain:**
```
resolveOrgProjectTarget({ type: "explicit", org: "my-org", project: "my-proj" })
→ resolveEffectiveOrg("my-org") [resolve-target.ts:1283]
→ resolveOrgFromCache("my-org") [region.ts:123] — DB cache miss (no setOrgRegion)
→ resolveOrgRegion("my-org") [region.ts:180]
→ ...
Excellent, now I have a very detailed analysis. Let me also look at some of the key files to understand the patterns better before writing the plan.
Let me now look at some specific files to verify the analysis and understand the code better. I'll look at:
test/lib/resolve-target-listing.test.ts - the specific test block
test/lib/resolve-target.test.ts - the environment variable tests
test/lib/index.test.ts - the SDK integration tests
test/isolated/login-reauth.test.ts - the warmOrgCache leak
test/commands/log/list.test.ts - to understand the ordering issue
I also need to examine the code paths in src/lib/region.ts for the resolveEffectiveOrg function and src/lib/resolve-target.ts to trace through the resolution cascade.
Excellent analysis. Let me verify the key code paths before designing the plan.
task_id: ses_286674ee7ffeLo5M6VZKbQcvvt (for resuming to continue this task if needed)
<task_result>
Here is the complete analysis of all 8 files:
---
## 1. `test/lib/resolve-target-listing.test.ts` (lines 100-170)
**Does `setOrgRegion("my-org", ...)` exist already?**
**Yes**, but only in the `resolveOrgProjectFromArg` describe block (line 277), NOT in the `resolveOrgProjectTarget` describe block.
The `resolveOrgProjectTarget` describe block (lines 122-261) sets up:
- `findProjectsBySlugSpy = spyOn(apiClient, "findProjectsBySlug")`
- `resolveOrgAndProjectSpy = spyOn(resolveTargetModule, "resolveOrgAndProject")`
It has **no** `setOrgRegion` call. The `"explicit"` case test (line 139-148) passes `parsed = { type: "explicit", org: "my-org", project: "my-proj" }`, which calls `resolveEffectiveOrg("my-org")` at line 1283 of `resolve-target.ts`. Without `setOrgRegion`, this triggers `resolveOrgRegion("my-org")` which hits the API via `retrieveAnOrganization` -- leaking a fetch call. ...
Now I have a very thorough understanding of the problem. Let me also check a few things:
test/commands/log/list.test.ts - I need to confirm it's spillover from login-reauth or some other testtest/lib/index.test.ts - I need to understand what the cleanest fix istest/lib/help-positional.test.ts - it appeared in the grep output too, let me check if it also has warningsLet me look at the timing correlation more carefully to map which warnings correlate with which test files:
22:33:54 - resolve-target-listing.test.ts starts → 22:33:54 warnings start (3x /organizations/my-org/)
22:34:16 - resolve-target.test.ts starts → 22:34:16 warnings start (regions/orgs)
22:34:37 - index.test.ts starts → 22:34:37 warnings start (organizations/1/, etc.)
22:36:28 - log/list.test.ts starts → 22:36:28 warnings (regions/orgs)
22:36:42 - login-reauth.test.ts starts → 22:36:42 warnings (regions/orgs)
Interesting - the log/list.test.ts warnings at 22:36:28 actually ...
task_id: ses_286646fe1ffe46QuXFFXdJ5Czi (for resuming to continue this task if needed)
<task_result>
Lines 665-682: When `_fetch` (the mock fetch) throws, the SDK catches it at line 667. Since `throwOnError` is `false`, it returns `{ error: finalError2, request: request2, response: undefined }` at line 678-682.
So the SDK catches the error from mock fetch. The result has `error` set and `response: undefined`. Then `unwrapResult` calls `throwApiError(error, undefined, context)` which creates a new `ApiError`.
But before that, the mock fetch already logged to `console.error` at lines 123-126 of preload.ts. The `console.error` happens synchronously when `mockFetch` is called. The throw is caught by the SDK. The `ApiError` propagates up.
So the flow is:
1. Mock fetch logs `[TEST] Unexpected fetch call to: ...` to stderr
2. Mock fetch throws
3. SDK catches the throw (line 667), returns error result
4. `unwrapResult` → `throwApiError` → throws `ApiError`
5. ...
Now I have all the information I need. Let me also verify one thing about the test/lib/help-positional.test.ts - the CI output showed it starting at 22:35:09 which is between the index.test.ts warnings. There were warnings between 22:34:46 and 22:35:09 that I attributed to index.test.ts retries. Let me just confirm that help-positional.test.ts doesn't produce any warnings by looking at the gap in timestamps.
Actually, looking at the output more carefully:
So there are 77 seconds between 22:34:52 and 22:36:28 with NO warnings. help-positional.test.ts is in that gap and doesn't produce warnings. Good.
Now I have enough information to write the plan directly. Let me summarize the files that need fixing.
For test/lib/resolve-target-listing.test.ts, the ...
Wrote file successfully.
The plan is ready. Here's a summary:
182 warnings from 5 test files, all caused by incomplete fetch mocking where code paths reach the global fetch trap in test/preload.ts:
| File | Warnings | Root Cause | Fix |
|------|----------|------------|-----|
| resolve-target-listing.test.ts | 3 | Missing setOrgRegion for explicit org case | Add setOrgRegion to beforeEach |
| resolve-target.test.ts | ~30 | Env var tests fall through to DSN/directory inference | Spy on detectDsn + findProjectsByPattern |
| index.test.ts | ~60 | SDK integration tests trigger full resolution cascade | Mock fetch or set SENTRY_ORG/SENTRY_PROJECT env vars |
| log/view.test.ts | ~40 | Barrel re-export spy doesn't intercept internal module calls | Spy on listOrganizationsUncached too |
| login-reauth.test.ts | 5 | Fire-and-forget warmOrgCache() calls listOrganizationsUncached | Spy on listOrganizationsUncached |
Each fix adds the minimal mocking needed to prevent fetch calls from reaching the preload trap, without changing test semantics.
User approved switching to build agent. Wait for further instructions.
The plan at .opencode/plans/1775860569408-mighty-cactus.md has been approved, you can now edit files. Execute the plan <system-reminder> Your operational mode has changed from plan to build. You are no longer in read-only mode. You are permitted to make file changes, run shell commands, and utilize your arsenal of tools as needed. </system-reminder>
A plan file exists at /home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/calm-forest/.opencode/plans/1775860569408-mighty-cactus.md. You should execute on the plan defined within it
Let me start executing the plan. I'll read the plan file first to refresh my memory, then work through each fix.
[
{
"content": "Fix test/lib/resolve-target-listing.test.ts — add setOrgRegion to resolveOrgProjectTarget beforeEach",
"status": "pending",
"priority": "high"
},
{
"content": "Fix test/lib/resolve-target.test.ts — spy on DSN detection and directory inference",
"status": "pending",
"priority": "high"
},
{
"content": "Fix test/lib/index.test.ts — prevent resolution cascade in SDK tests",
"status": "pending",
"priority": "high"
},
{
"content": "Fix test/commands/log/view.test.ts — fix barrel re-export spy gap",
"status": "pending",
"priority": "high"
},
{
"content": "Fix test/isolated/login-reauth.test.ts — spy on listOrganizationsUncached for warmOrgCache",
"status": "pending",
"priority": "high"
},
{
"content": "Verify all fixes — run tests and check zero warnings",
"status": "pending",
"priority": "high"
}
]
Let me start by reading all the files I need to modify in parallel.
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/calm-forest/test/lib/resolve-target-listing.test.ts</path>
<type>file</type>
<content>
100: });
101:
102: const result = await resolveOrgsForListing(undefined, CWD);
103: expect(result.skippedSelfHosted).toBe(2);
104: });
105:
106: test("returns empty orgs and propagates skippedSelfHosted when targets empty but DSNs found", async () => {
107: resolveAllTargetsSpy.mockResolvedValue({
108: targets: [],
109: skippedSelfHosted: 3,
110: });
111:
112: const result = await resolveOrgsForListing(undefined, CWD);
113: expect(result.orgs).toEqual([]);
114: expect(result.skippedSelfHosted).toBe(3);
115: });
116: });
117:
118: // ---------------------------------------------------------------------------
119: // resolveOrgProjectTarget
120: // ---------------------------------------------------------------------------
121:
122: ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/calm-forest/test/lib/resolve-target.test.ts</path>
<type>file</type>
<content>
175:
176: describe("Environment variable resolution (SENTRY_ORG / SENTRY_PROJECT)", () => {
177: useTestConfigDir("test-resolve-target-");
178:
179: beforeEach(() => {
180: delete process.env.SENTRY_ORG;
181: delete process.env.SENTRY_PROJECT;
182: });
183:
184: afterEach(() => {
185: delete process.env.SENTRY_ORG;
186: delete process.env.SENTRY_PROJECT;
187: });
188:
189: // --- resolveOrg ---
190:
191: test("resolveOrg: returns org from SENTRY_ORG", async () => {
192: process.env.SENTRY_ORG = "test-org";
193: const result = await resolveOrg({ cwd: "/tmp" });
194: expect(result?.org).toBe("test-org");
195: });
196:
197: test("resolveOrg: SENTRY_PROJECT=org/project combo extracts org", async () => {
198: process.env.SENTRY_PROJECT = "combo-org/combo-project";
199: ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/calm-forest/test/lib/index.test.ts</path>
<type>file</type>
<content>
1: import { describe, expect, test } from "bun:test";
2: import createSentrySDK, { SentryError } from "../../src/index.js";
3:
4: describe("createSentrySDK() library API", () => {
5: test("sdk.run returns version string for --version", async () => {
6: const sdk = createSentrySDK();
7: const result = await sdk.run("--version");
8: expect(typeof result).toBe("string");
9: // Version output is a semver string like "0.0.0-dev" or "0.21.0"
10: expect(result as string).toMatch(/\d+\.\d+\.\d+/);
11: });
12:
13: test("sdk.run returns parsed object for help command in JSON mode", async () => {
14: const sdk = createSentrySDK();
15: const result = await sdk.run("help");
16: // help --json returns a parsed object with routes
17: expect(typeof result).toBe("object");
18: ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/calm-forest/test/commands/log/view.test.ts</path>
<type>file</type>
<content>
1: /**
2: * Log View Command Tests
3: *
4: * Tests for positional argument parsing, project resolution,
5: * and viewCommand func() body in src/commands/log/view.ts
6: */
7:
8: import {
9: afterEach,
10: beforeEach,
11: describe,
12: expect,
13: mock,
14: spyOn,
15: test,
16: } from "bun:test";
17: import {
18: parsePositionalArgs,
19: viewCommand,
20: } from "../../../src/commands/log/view.js";
21: import type { ProjectWithOrg } from "../../../src/lib/api-client.js";
22: // biome-ignore lint/performance/noNamespaceImport: needed for spyOn mocking
23: import * as apiClient from "../../../src/lib/api-client.js";
24: // biome-ignore lint/performance/noNamespaceImport: needed for spyOn mocking
25: import * as browser from "../../../src/lib/browser.js";
26: import { DEFAULT_SENTRY_URL } from ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/calm-forest/test/isolated/login-reauth.test.ts</path>
<type>file</type>
<content>
1: /**
2: * Isolated test for login re-authentication interactive prompt path.
3: *
4: * Uses mock.module() to override node:tty so isatty(0) returns true,
5: * and mocks the logger module to control the prompt response.
6: *
7: * Run with: bun test test/isolated/login-reauth.test.ts
8: */
9:
10: import {
11: afterEach,
12: beforeEach,
13: describe,
14: expect,
15: mock,
16: spyOn,
17: test,
18: } from "bun:test";
19:
20: // Mock isatty to simulate interactive terminal.
21: // Bun's ESM wrapper for CJS built-ins exposes a `default` re-export plus
22: // `ReadStream` / `WriteStream` — all must be present or Bun throws
23: // "Missing 'default' export in module 'node:tty'". ...
[
{
"content": "Fix test/lib/resolve-target-listing.test.ts — add setOrgRegion to resolveOrgProjectTarget beforeEach",
"status": "in_progress",
"priority": "high"
},
{
"content": "Fix test/lib/resolve-target.test.ts — spy on DSN detection and directory inference",
"status": "pending",
"priority": "high"
},
{
"content": "Fix test/lib/index.test.ts — prevent resolution cascade in SDK tests",
"status": "pending",
"priority": "high"
},
{
"content": "Fix test/commands/log/view.test.ts — fix barrel re-export spy gap",
"status": "pending",
"priority": "high"
},
{
"content": "Fix test/isolated/login-reauth.test.ts — spy on listOrganizationsUncached for warmOrgCache",
"status": "pending",
"priority": "high"
},
{
"content": "Verify all fixes — run tests and check zero warnings",
"status": "pending",
"priority": "high"
}
]
Now let me also read the imports at the top of resolve-target-listing.test.ts and read more of log/view.test.ts to understand the spy setup:
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/calm-forest/test/lib/resolve-target-listing.test.ts</path>
<type>file</type>
<content>
1: /**
2: * Tests for new resolve-target listing functions
3: *
4: * Tests for resolveOrgsForListing, resolveOrgProjectTarget, and
5: * resolveOrgProjectFromArg added in the pagination PR.
6: * Uses spyOn to mock dependencies without real HTTP calls.
7: */
8:
9: import { afterEach, beforeEach, describe, expect, spyOn, test } from "bun:test";
10: // biome-ignore lint/performance/noNamespaceImport: needed for spyOn mocking
11: import * as apiClient from "../../src/lib/api-client.js";
12: import { DEFAULT_SENTRY_URL } from "../../src/lib/constants.js";
13: // biome-ignore lint/performance/noNamespaceImport: needed for spyOn mocking
14: import * as defaults from "../../src/lib/db/defaults.js";
15: import { setOrgRegion } from "../../src/lib/db/regions.js";
16: import { ContextError, ResolutionError } from ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/calm-forest/test/commands/log/view.test.ts</path>
<type>file</type>
<content>
225: test("newline-delimited log IDs as a single arg with target", () => {
226: const ids = [
227: "019c6d2ca9ec7cc5bd02f9190d77debe",
228: "019c71e55b817bccb2a842fe6252caed",
229: "019c71e92c887cdfb4367790907032f7",
230: ];
231: const combined = ids.join("\n");
232: const result = parsePositionalArgs(["brandai/brandai", combined]);
233: expect(result.targetArg).toBe("brandai/brandai");
234: expect(result.logIds).toEqual(ids);
235: });
236: });
237: });
238:
239: describe("resolveProjectBySlug", () => {
240: const HINT = "sentry log view <org>/<project> <log-id> [<log-id>...]";
241: let findProjectsBySlugSpy: ReturnType<typeof spyOn>;
242:
243: beforeEach(() => {
244: findProjectsBySlugSpy = spyOn(apiClient, "findProjectsBySlug");
245: ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/calm-forest/test/lib/resolve-target.test.ts</path>
<type>file</type>
<content>
1: /**
2: * Tests for resolve-target utilities
3: *
4: * Property-based and unit tests for pure functions in the resolve-target module.
5: * Integration tests for async resolution functions are in e2e tests due to
6: * the complexity of mocking module dependencies in Bun's test environment.
7: */
8:
9: import { afterEach, beforeEach, describe, expect, test } from "bun:test";
10: import { array, constantFrom, assert as fcAssert, property } from "fast-check";
11: import { DEFAULT_SENTRY_URL } from "../../src/lib/constants.js";
12: import { setAuthToken } from "../../src/lib/db/auth.js";
13: import { setOrgRegion } from "../../src/lib/db/regions.js";
14: import { AuthError, ResolutionError } from "../../src/lib/errors.js";
15: import {
16: fetchProjectId,
17: isValidDirNameForInference,
18: ...
Now I have all the context I need. Let me also read the rest of log/view.test.ts to see the viewCommand.func block, and the rest of login-reauth.test.ts to understand the afterEach.
Let me also check if there's something I need to import in resolve-target.test.ts for DSN detection spying. Let me check what modules are available.
For log/view.test.ts - the resolveProjectBySlug describe block (line 239) has findProjectsBySlugSpy = spyOn(apiClient, "findProjectsBySlug").
I'm realizing the spy on the barrel re-export won't intercept calls from within resolve-target.ts since it imports findProjectsBySlug directly from ./api-client.js. Even though the test calls resolveProjectBySlug("my-project", HINT) which internally uses that function, I need to verify exactly how the import is structured in the source file to understand whether the spy will actually work. ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/calm-forest/test/commands/log/view.test.ts</path>
<type>file</type>
<content>
445: });
446:
447: test("swapped args throw ValidationError since non-hex ID fails validation", async () => {
448: const { context } = createMockContext();
449: const func = await viewCommand.loader();
450: // With hex validation, "test-org/test-proj" in log ID position throws
451: // ValidationError before swap detection runs.
452: await expect(
453: func.call(
454: context,
455: { json: true, web: false },
456: "968c763c740cfda8b6728f27fb9e9b01",
457: "test-org/test-proj"
458: )
459: ).rejects.toThrow(ValidationError);
460: });
461:
462: test("logs normalized slug warning when underscores present", async () => {
463: getLogsSpy.mockResolvedValue([sampleLog]);
464: setOrgRegion("test-org", DEFAULT_SENTRY_URL);
465:
466: const { ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/calm-forest/test/isolated/login-reauth.test.ts</path>
<type>file</type>
<content>
140: runInteractiveLoginSpy.mockRestore();
141: getUserInfoSpy.mockRestore();
142: });
143:
144: test("shows prompt with user identity when authenticated on TTY", async () => {
145: isAuthenticatedSpy.mockReturnValue(true);
146: getUserInfoSpy.mockReturnValue({
147: userId: "42",
148: name: "Jane Doe",
149: email: "jane@example.com",
150: });
151: mockPrompt.mockResolvedValue(true);
152:
153: const context = createMockContext();
154: await func.call(context, { force: false, timeout: 900 });
155:
156: expect(mockPrompt).toHaveBeenCalledTimes(1);
157: const promptMessage = (mockPrompt.mock.calls[0] as unknown as string[])[0];
158: expect(promptMessage).toContain("Jane Doe");
159: expect(promptMessage).toContain("jane@example.com");
160: ...
Now I have a much clearer picture. Let me re-analyze the log/view.test.ts issue:
Looking at the resolveProjectBySlug describe block (lines 239-399):
findProjectsBySlugSpy = spyOn(apiClient, "findProjectsBySlug") is set in beforeEach (line 244)
Each test sets findProjectsBySlugSpy.mockResolvedValue(...) before calling resolveProjectBySlug
If the spy intercepts the call correctly, findProjectsBySlug returns the mocked value and no fetch happens
The viewCommand.func describe block (lines 406-527) has a similar setup with spies for findProjectsBySlug, getLogs, and openInBrowser, plus it initializes the org region with a test URL.
Tests at lines 479 and 503 mock findProjectsBySlugSpy.mockResolvedValue(...) before calling the function.
The real question is whether spyOn(apiClient, "findProjectsBySlug") actually intercepts calls originating from resolve-target.ts. ...
Edit applied successfully.
[
{
"content": "Fix test/lib/resolve-target-listing.test.ts — add setOrgRegion to resolveOrgProjectTarget beforeEach",
"status": "completed",
"priority": "high"
},
{
"content": "Fix test/lib/resolve-target.test.ts — spy on DSN detection and directory inference",
"status": "in_progress",
"priority": "high"
},
{
"content": "Fix test/lib/index.test.ts — prevent resolution cascade in SDK tests",
"status": "pending",
"priority": "high"
},
{
"content": "Fix test/commands/log/view.test.ts — fix barrel re-export spy gap",
"status": "pending",
"priority": "high"
},
{
"content": "Fix test/isolated/login-reauth.test.ts — spy on listOrganizationsUncached for warmOrgCache",
"status": "pending",
"priority": "high"
},
{
"content": "Verify all fixes — run tests and check zero warnings",
"status": "pending",
"priority": "high"
}
]
test/lib/resolve-target.test.tsThe env variable tests fall through to DSN detection and directory inference. I'll mock globalThis.fetch with a silent 404 to prevent warnings while preserving test behavior.
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/calm-forest/test/lib/resolve-target.test.ts</path>
<type>file</type>
<content>
175:
176: describe("Environment variable resolution (SENTRY_ORG / SENTRY_PROJECT)", () => {
177: useTestConfigDir("test-resolve-target-");
178:
179: beforeEach(() => {
180: delete process.env.SENTRY_ORG;
181: delete process.env.SENTRY_PROJECT;
182: });
183:
184: afterEach(() => {
185: delete process.env.SENTRY_ORG;
186: delete process.env.SENTRY_PROJECT;
187: });
188:
189: // --- resolveOrg ---
(Showing lines 175-189 of 469. Use offset=190 to continue.)
</content>
Edit applied successfully.
[
{
"content": "Fix test/lib/resolve-target-listing.test.ts — add setOrgRegion to resolveOrgProjectTarget beforeEach",
"status": "completed",
"priority": "high"
},
{
"content": "Fix test/lib/resolve-target.test.ts — spy on DSN detection and directory inference",
"status": "completed",
"priority": "high"
},
{
"content": "Fix test/lib/index.test.ts — prevent resolution cascade in SDK tests",
"status": "in_progress",
"priority": "high"
},
{
"content": "Fix test/commands/log/view.test.ts — fix barrel re-export spy gap",
"status": "pending",
"priority": "high"
},
{
"content": "Fix test/isolated/login-reauth.test.ts — spy on listOrganizationsUncached for warmOrgCache",
"status": "pending",
"priority": "high"
},
{
"content": "Verify all fixes — run tests and check zero warnings",
"status": "pending",
"priority": "high"
}
]
test/lib/index.test.tsThe SDK tests trigger full resolution cascades. I need to mock fetch to return silent responses instead of preload's warning-producing trap. Let me also check what mockFetch needs to be imported from.
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/calm-forest/test/helpers.ts</path>
<type>file</type>
<content>
1: /**
2: * Test Helpers
3: *
4: * Shared utilities for test setup and teardown.
5: */
6:
7: import { afterEach, beforeEach } from "bun:test";
8: import { mkdirSync } from "node:fs";
9: import { mkdtemp, rm } from "node:fs/promises";
10: import { join } from "node:path";
11: import { CONFIG_DIR_ENV_VAR, closeDatabase } from "../src/lib/db/index.js";
12:
13: // biome-ignore lint/performance/noBarrelFile: re-exporting a single constant, not a barrel
14: export { TEST_TMP_DIR } from "./constants.js";
15:
16: import { TEST_TMP_DIR } from "./constants.js";
17:
18: mkdirSync(TEST_TMP_DIR, { recursive: true });
19:
20: type TestConfigDirOptions = {
21: /**
22: * Creates a .git directory to make this an isolated "project root". ...
Now let me implement the fix for index.test.ts. The key tests that leak are: sdk.run("issue", "list") (lines 21-31, 45-56) and sdk.org.list() (lines 77-89). I need to silence the fetch warnings.
Edit applied successfully.
[
{
"content": "Fix test/lib/resolve-target-listing.test.ts — add setOrgRegion to resolveOrgProjectTarget beforeEach",
"status": "completed",
"priority": "high"
},
{
"content": "Fix test/lib/resolve-target.test.ts — spy on DSN detection and directory inference",
"status": "completed",
"priority": "high"
},
{
"content": "Fix test/lib/index.test.ts — prevent resolution cascade in SDK tests",
"status": "completed",
"priority": "high"
},
{
"content": "Fix test/commands/log/view.test.ts — fix barrel re-export spy gap",
"status": "in_progress",
"priority": "high"
},
{
"content": "Fix test/isolated/login-reauth.test.ts — spy on listOrganizationsUncached for warmOrgCache",
"status": "pending",
"priority": "high"
},
{
"content": "Verify all fixes — run tests and check zero warnings",
"status": "pending",
"priority": "high"
}
]
test/commands/log/view.test.tsLet me first check empirically whether this file is actually the source of the log/* warnings by running it individually.
0
0
0
Interesting! None of the log/* test files produce warnings when run individually. The warnings are likely spillover from fire-and-forget async operations in other test files that run before these. Let me check by running them in order with Bun's test runner.
Let me check the order of test files in CI. In Bun, test files are run sequentially. The warnings at 22:36:28 appear right when the log/* test files start loading. The fire-and-forget warmOrgCache() from a test file that ran earlier (like some auth test) might be completing during log/* file loading.
But wait, the isolated tests run separately in their own CI step, and login-reauth.test.ts is part of that isolated test run, so the warmOrgCache spillover wouldn't affect the main test step. I need to look at what's actually running just before the log/* files in the CI output to find the real source.
All three log/* test files produce zero warnings individually. ...
Unit Tests Unit Tests 2026-04-10T22:36:27.5707206Z ##[group]test/commands/auth/status.test.ts: Unit Tests Unit Tests 2026-04-10T22:36:27.6064981Z ##[group]test/commands/auth/refresh.test.ts: Unit Tests Unit Tests 2026-04-10T22:36:27.6117023Z ##[group]test/commands/team/list.test.ts: Unit Tests Unit Tests 2026-04-10T22:36:27.6286089Z ##[group]test/commands/cli/setup.test.ts: Unit Tests Unit Tests 2026-04-10T22:36:27.6870236Z ##[group]test/commands/cli/fix.test.ts: Unit Tests Unit Tests 2026-04-10T22:36:28.0590945Z ##[group]test/commands/cli/upgrade.test.ts: Unit Tests Unit Tests 2026-04-10T22:36:28.1736018Z ##[group]test/commands/log/view.func.test.ts: Unit Tests Unit Tests 2026-04-10T22:36:28.1894168Z ##[group]test/commands/log/view.test.ts: Unit Tests Unit Tests 2026-04-10T22:36:28.2001989Z ##[group]test/commands/log/list.test.ts: Unit Tests Unit Tests 2026-04-10T22:36:28.5536817Z [TEST] Unexpected fetch call to: https://sentry.io/api/0/users/me/regions/ Unit Tests Unit ...
The files that load right before the log/* files are:
test/commands/auth/status.test.ts (22:36:27.57)
test/commands/auth/refresh.test.ts (22:36:27.61)
test/commands/team/list.test.ts (22:36:27.61)
test/commands/cli/setup.test.ts (22:36:27.63)
test/commands/cli/fix.test.ts (22:36:27.69)
test/commands/cli/upgrade.test.ts (22:36:28.06)
The warnings appear about 500ms after the upgrade test loads, and the API patterns match listOrganizationsUncached. One of these test files is likely triggering background async operations like org cache warming that complete after the test finishes. I should look at the setup test since it might be initiating this caching behavior.
Actually, the cli/setup.test.ts file has a known issue with fetch save/restore at line 688. The upgrade test has four describe blocks that properly manage fetch, but if there's code outside those blocks calling functions that trigger fetch requests, that could be the culprit. ...
0
0
0
Hmm, none of them produce warnings individually either. This means the warnings are coming from some test file that runs EVEN earlier, and the fire-and-forget promises complete much later (during the log/* file loading). With exponential backoff retries, this could be 30+ seconds later.
Let me check the auth/ files:
0
0
None of the files that run right before produce warnings individually. This is a spillover problem — some file that runs much earlier has a fire-and-forget async operation with retries that takes long enough to only fire much later.
Looking at the retry backoff in sentry-client.ts, retries have exponential backoff. If a fetch call fails and retries 3 times with 1s, 2s, 4s backoff, the total time is ~7s. But the warnings I'm seeing at 22:36:28 come ~2 minutes after the index.test.ts warnings at 22:34:37. That's way too long for retries.
Actually, the gap is even larger than I thought — 96 seconds between the index.test.ts warnings and the log/* warnings. That rules out spillover from index.test.ts entirely, since retries wouldn't take that long. So the log/* warnings must be coming from a test file that runs in that window, but running those files individually produces nothing. ...
No warnings from running these files together either. This means the spillover comes from even earlier files. Let me check which files have warmOrgCache patterns or listOrganizationsUncached that fire asynchronously.
Let me search for fire-and-forget patterns in command files and check if any test file exercises them.
Found 5 matches
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/calm-forest/src/commands/auth/login.ts:
Line 200: warmOrgCache();
Line 212: warmOrgCache();
Line 231: function warmOrgCache(): void {
Line 232: listOrganizationsUncached().catch(() => {
/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/calm-forest/src/commands/cli/upgrade.ts:
Line 622: .catch(() => undefined as undefined);
Found 3 matches /home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/calm-forest/test/commands/auth/status.test.ts: Line 81: listOrgsSpy = spyOn(apiClient, "listOrganizationsUncached"); /home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/calm-forest/test/isolated/resolve-target.test.ts: Line 129: listOrganizationsUncached: mockListOrganizationsUncached, Line 300: // (after listOrganizationsUncached populates the cache)
Interesting. The warmOrgCache is only in login.ts, and there's no test for it in the unit tests (only in login-reauth.test.ts which is isolated). The auth/status.test.ts does spy on listOrganizationsUncached, so it's protected.
So the log/* warnings aren't from warmOrgCache. They must be from some other source. Let me try a different approach — run the entire test:unit command and see the warnings with their context to identify the actual source.
Actually, let me try running a larger batch of test files including the ones that run before log/* to find the spillover source.
[TEST] Unexpected fetch call to: https://sentry.io/api/0/users/me/regions/ [TEST] Unexpected fetch call to: https://sentry.io/api/0/users/me/regions/ [TEST] Unexpected fetch call to: https://sentry.io/api/0/organizations/ [TEST] Unexpected fetch call to: https://sentry.io/api/0/organizations/ [TEST] Unexpected fetch call to: https://sentry.io/api/0/organizations/ [TEST] Unexpected fetch call to: https://sentry.io/api/0/organizations/ [TEST] Unexpected fetch call to: https://sentry.io/api/0/users/me/regions/ [TEST] Unexpected fetch call to: https://sentry.io/api/0/users/me/regions/ [TEST] Unexpected fetch call to: https://sentry.io/api/0/organizations/ [TEST] Unexpected fetch call to: https://sentry.io/api/0/users/me/regions/ [TEST] Unexpected fetch call to: https://sentry.io/api/0/users/me/regions/ [TEST] Unexpected fetch call to: https://sentry.io/api/0/users/me/regions/ [TEST] Unexpected fetch call to: https://sentry.io/api/0/organizations/ [TEST] Unexpected fetch call to: ...
I can reproduce the warnings by running these test directories together! Now let me narrow it down. The log/* files don't produce warnings alone, and the cli+log files don't produce warnings together. But adding auth and team files produces warnings.
Let me bisect: does auth/ + log/ produce warnings?
45
0
0
0
0
login.test.ts logout.test.ts refresh.test.ts status.test.ts whoami.test.ts
45
Found it! test/commands/auth/login.test.ts is the culprit. Its fire-and-forget warmOrgCache() calls spill over into later test files.
10
test/commands/auth/login.test.ts produces 10 warnings on its own. And when run before log/* files, it produces 45 (the extra 35 are from fire-and-forget operations that complete during the log/* test execution).
Wait, that's weird. 10 warnings from login.test.ts alone, plus 45 when run with log/. But the log/ files don't produce any warnings on their own. The extra warnings (35) must be from the login.test.ts fire-and-forget operations that take longer when more files are being loaded/run.
Actually, the retries with backoff explain this: when login.test.ts runs alone, some retries complete before the test process exits (producing 10 warnings).
When it runs alongside log/* files, the process stays alive longer, allowing more of those retries to fire and complete (producing 45 total). So I need to look at what's leaking in login.test.ts—it's probably calling loginCommand's func() which triggers warmOrgCache().
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/calm-forest/test/commands/auth/login.test.ts</path> <type>file</type> <content> 1: /** 2: * Login Command Tests 3: * 4: * Unit tests for the --token and --force authentication paths in src/commands/auth/login.ts. 5: * Uses spyOn to mock api-client, db/auth, db/user, and interactive-login 6: * to cover all branches without real HTTP calls or database access. 7: * 8: * Status messages go through consola (→ stderr). Logger message content is NOT 9: * asserted here because mock.module in login-reauth.test.ts can replace the 10: * logger module globally. Tests verify behavior via spy assertions instead. 11: * 12: * Tests that require isatty(0) to return true (interactive TTY prompt tests) 13: * live in test/isolated/login-reauth.test.ts to avoid mock.module pollution. ...
Now I see the problem in login.test.ts. The tests at lines 129, 145, 280, 294, 329 call func.call(context, ...) which triggers the login flow. When login succeeds (via runInteractiveLoginSpy.mockResolvedValue({...})), the login function calls warmOrgCache() which is fire-and-forget (listOrganizationsUncached().catch(() => {})).
The runInteractiveLoginSpy.mockResolvedValue({...}) returns { method: "oauth", configPath: "/fake" } — this is a truthy result, so the login flow proceeds to the success path which calls warmOrgCache().
But listOrganizationsUncached isn't spied on in this test file, so even though getUserRegionsSpy is set up on apiClient.getUserRegions, the spy doesn't intercept the call when listOrganizationsUncached invokes it internally.
The solution is to spy on apiClient.listOrganizationsUncached instead. ...
[
{
"content": "Fix test/lib/resolve-target-listing.test.ts — add setOrgRegion to resolveOrgProjectTarget beforeEach",
"status": "completed",
"priority": "high"
},
{
"content": "Fix test/lib/resolve-target.test.ts — spy on DSN detection and directory inference",
"status": "completed",
"priority": "high"
},
{
"content": "Fix test/lib/index.test.ts — prevent resolution cascade in SDK tests",
"status": "completed",
"priority": "high"
},
{
"content": "Fix test/commands/auth/login.test.ts — spy on listOrganizationsUncached for warmOrgCache spillover",
"status": "in_progress",
"priority": "high"
},
{
"content": "Fix test/isolated/login-reauth.test.ts — spy on listOrganizationsUncached for warmOrgCache",
"status": "pending",
"priority": "high"
},
{
"content": "Verify all fixes — run tests and check zero warnings",
"status": "pending",
"priority": "high"
}
]
test/commands/auth/login.test.tsAfter successful login, warmOrgCache() fires as a fire-and-forget. I need to spy on listOrganizationsUncached to prevent fetch calls.
Edit applied successfully.
Now verify that login.test.ts no longer produces warnings:
0
And verify no spillover:
0
[
{
"content": "Fix test/lib/resolve-target-listing.test.ts — add setOrgRegion to resolveOrgProjectTarget beforeEach",
"status": "completed",
"priority": "high"
},
{
"content": "Fix test/lib/resolve-target.test.ts — spy on DSN detection and directory inference",
"status": "completed",
"priority": "high"
},
{
"content": "Fix test/lib/index.test.ts — prevent resolution cascade in SDK tests",
"status": "completed",
"priority": "high"
},
{
"content": "Fix test/commands/auth/login.test.ts — spy on listOrganizationsUncached for warmOrgCache spillover",
"status": "completed",
"priority": "high"
},
{
"content": "Fix test/isolated/login-reauth.test.ts — spy on listOrganizationsUncached for warmOrgCache",
"status": "in_progress",
"priority": "high"
},
{
"content": "Verify all fixes — run tests and check zero warnings",
"status": "pending",
"priority": "high"
}
]
test/isolated/login-reauth.test.tsSame warmOrgCache issue — spy on listOrganizationsUncached:
Edit applied successfully.
Now add the restore in afterEach:
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/calm-forest/test/isolated/login-reauth.test.ts</path>
<type>file</type>
<content>
145: clearAuthSpy.mockRestore();
146: runInteractiveLoginSpy.mockRestore();
147: getUserInfoSpy.mockRestore();
148: });
149:
150: test("shows prompt with user identity when authenticated on TTY", async () => {
151: isAuthenticatedSpy.mockReturnValue(true);
152: getUserInfoSpy.mockReturnValue({
153: userId: "42",
154: name: "Jane Doe",
(Showing lines 145-154 of 271. Use offset=155 to continue.)
</content>
Edit applied successfully.
[
{
"content": "Fix test/lib/resolve-target-listing.test.ts — add setOrgRegion to resolveOrgProjectTarget beforeEach",
"status": "completed",
"priority": "high"
},
{
"content": "Fix test/lib/resolve-target.test.ts — spy on DSN detection and directory inference",
"status": "completed",
"priority": "high"
},
{
"content": "Fix test/lib/index.test.ts — prevent resolution cascade in SDK tests",
"status": "completed",
"priority": "high"
},
{
"content": "Fix test/commands/auth/login.test.ts — spy on listOrganizationsUncached for warmOrgCache spillover",
"status": "completed",
"priority": "high"
},
{
"content": "Fix test/isolated/login-reauth.test.ts — spy on listOrganizationsUncached for warmOrgCache",
"status": "completed",
"priority": "high"
},
{
"content": "Verify all fixes — run tests and check zero warnings",
"status": "in_progress",
"priority": "high"
}
]
Let me run each fixed test file individually first, then the full test suite.
0
0
0
0
All individual files are clean. Now let me run the full test suites:
57
Still 57 warnings. Let me find what's still leaking. Let me get the details. 57 remaining. Let me find the sources:
[TEST] Unexpected fetch call to: https://sentry.io/api/0/users/me/regions/ [TEST] Unexpected fetch call to: https://sentry.io/api/0/users/me/regions/ [TEST] Unexpected fetch call to: https://sentry.io/api/0/users/me/regions/ [TEST] Unexpected fetch call to: https://sentry.io/api/0/organizations/ [TEST] Unexpected fetch call to: https://sentry.io/api/0/organizations/ [TEST] Unexpected fetch call to: https://sentry.io/api/0/organizations/ [TEST] Unexpected fetch call to: https://api.github.com/repos/getsentry/cli/releases/latest [TEST] Unexpected fetch call to: https://api.github.com/repos/getsentry/cli/releases/latest [TEST] Unexpected fetch call to: https://api.github.com/repos/getsentry/cli/releases/latest [TEST] Unexpected fetch call to: https://api.github.com/repos/getsentry/cli/releases/latest [TEST] Unexpected fetch call to: https://sentry.io/api/0/users/me/regions/ [TEST] Unexpected fetch call to: https://sentry.io/api/0/users/me/regions/ [TEST] Unexpected fetch call to: ...
I see new patterns:
/users/me/regions/ and /organizations/ — still coming from somewhere (6 groups of 3 retries = ~36 warnings)api.github.com/repos/getsentry/cli/releases/latest — 4 warnings from version check/projects/1/4510798755856384/ — 2 warnings from some DSN resolution/trace-items/ — many warnings from span view testsI can't see which test files are producing these since the group]test/ markers aren't showing in the output.
The unit test runner might be using a different logging format, so I need to capture more detailed output to trace where these requests are coming from.
test/lib/resolve-effective-org.test.ts: [TEST] Unexpected fetch call to: https://sentry.io/api/0/users/me/regions/ [TEST] Unexpected fetch call to: https://sentry.io/api/0/users/me/regions/ [TEST] Unexpected fetch call to: https://sentry.io/api/0/users/me/regions/ [TEST] Unexpected fetch call to: https://sentry.io/api/0/organizations/ [TEST] Unexpected fetch call to: https://sentry.io/api/0/organizations/ [TEST] Unexpected fetch call to: https://sentry.io/api/0/organizations/ -- test/lib/version-check.test.ts: [TEST] Unexpected fetch call to: https://api.github.com/repos/getsentry/cli/releases/latest [TEST] Unexpected fetch call to: https://api.github.com/repos/getsentry/cli/releases/latest [TEST] Unexpected fetch call to: https://api.github.com/repos/getsentry/cli/releases/latest [TEST] Unexpected fetch call to: https://api.github.com/repos/getsentry/cli/releases/latest -- test/lib/help-positional.test.ts: [TEST] Unexpected fetch call to: ...
Now I can see the remaining files that need fixing:
test/lib/resolve-effective-org.test.ts — 6 warnings (regions + organizations)
test/lib/version-check.test.ts — 4 warnings (GitHub API)
test/lib/help-positional.test.ts — 24 warnings (regions + organizations × 4 tests)
test/lib/release-notes.property.test.ts — 2 warnings (projects DSN)
test/commands/issue/utils.test.ts — 6 warnings (regions + organizations)
I'm also noticing there are span-related warnings scattered throughout that didn't surface in the main output, so I need to dig deeper to find those.
test/commands/span/view.test.ts: [TEST] Unexpected fetch call to: https://sentry.io/api/0/projects/test-org/test-project/trace-items/a1b2c3d4e5f67890/?trace_id=aaaa1111bbbb2222cccc3333dddd4444&item_type=spans [TEST] Tests should mock fetch or use SENTRY_TEST_* credentials for real API calls [debug] [http] GET /api/0/projects/test-org/test-project/trace-items/a1b2c3d4e5f67890/ → retry 1/2 after 1000ms [TEST] Unexpected fetch call to: https://sentry.io/api/0/projects/test-org/test-project/trace-items/a1b2c3d4e5f67890/?trace_id=aaaa1111bbbb2222cccc3333dddd4444&item_type=spans [TEST] Tests should mock fetch or use SENTRY_TEST_* credentials for real API calls [debug] [http] GET /api/0/projects/test-org/test-project/trace-items/a1b2c3d4e5f67890/ → retry 2/2 after 2000ms [TEST] Unexpected fetch call to: https://sentry.io/api/0/projects/test-org/test-project/trace-items/a1b2c3d4e5f67890/?trace_id=aaaa1111bbbb2222cccc3333dddd4444&item_type=spans -- [warn] [span.view] Could not fetch details ...
Good, now I have the complete picture. There are 5 more files to fix:
[
{
"content": "Fix test/lib/resolve-target-listing.test.ts",
"status": "completed",
"priority": "high"
},
{
"content": "Fix test/lib/resolve-target.test.ts",
"status": "completed",
"priority": "high"
},
{
"content": "Fix test/lib/index.test.ts",
"status": "completed",
"priority": "high"
},
{
"content": "Fix test/commands/auth/login.test.ts",
"status": "completed",
"priority": "high"
},
{
"content": "Fix test/isolated/login-reauth.test.ts",
"status": "completed",
"priority": "high"
},
{
"content": "Fix test/lib/resolve-effective-org.test.ts — 6 warnings (regions+orgs)",
"status": "pending",
"priority": "high"
},
{
"content": "Fix test/lib/version-check.test.ts — 4 warnings (GitHub API)",
"status": "pending",
"priority": "high"
},
{
"content": "Fix test/lib/help-positional.test.ts — 24 warnings (regions+orgs)",
"status": "pending",
"priority": "high"
},
{
...
Let me read these remaining files in parallel to understand the leaks:
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/calm-forest/test/lib/resolve-effective-org.test.ts</path>
<type>file</type>
<content>
1: /**
2: * Tests for resolveEffectiveOrg and DSN org ID resolution.
3: *
4: * Covers the offline cache lookup path that resolves DSN-style org
5: * identifiers (e.g., `o1081365`) to real org slugs using the local
6: * org_regions cache.
7: */
8:
9: import { afterEach, beforeEach, describe, expect, test } from "bun:test";
10: import { setAuthToken } from "../../src/lib/db/auth.js";
11: import {
12: getOrgByNumericId,
13: getOrgRegion,
14: setOrgRegion,
15: setOrgRegions,
16: } from "../../src/lib/db/regions.js";
17: import { resolveEffectiveOrg } from "../../src/lib/region.js";
18: import { mockFetch, useTestConfigDir } from "../helpers.js";
19:
20: useTestConfigDir("resolve-effective-org-");
21:
22: // getOrgByNumericId (DB layer)
23:
24: describe("getOrgByNumericId", () => {
25: test("returns ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/calm-forest/test/lib/version-check.test.ts</path>
<type>file</type>
<content>
1: /**
2: * Version Check Logic Tests
3: */
4:
5: import { afterEach, beforeEach, describe, expect, test } from "bun:test";
6: import { setReleaseChannel } from "../../src/lib/db/release-channel.js";
7: import {
8: getVersionCheckInfo,
9: setVersionCheckInfo,
10: } from "../../src/lib/db/version-check.js";
11: import {
12: abortPendingVersionCheck,
13: getUpdateNotification,
14: maybeCheckForUpdateInBackground,
15: shouldSuppressNotification,
16: } from "../../src/lib/version-check.js";
17: import { useTestConfigDir } from "../helpers.js";
18:
19: describe("shouldSuppressNotification", () => {
20: test("suppresses for upgrade command", () => {
21: expect(shouldSuppressNotification(["upgrade"])).toBe(true);
22: expect(shouldSuppressNotification(["upgrade", "--check"])).toBe(true);
23: });
24: ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/calm-forest/test/lib/help-positional.test.ts</path>
<type>file</type>
<content>
1: /**
2: * Tests for help-as-positional-arg error recovery in buildCommand.
3: *
4: * When a command throws a CliError and a positional arg was `"help"`,
5: * the buildCommand wrapper recovers by showing the command's help
6: * instead of the confusing error.
7: *
8: * This only fires as error recovery — if a command successfully resolves
9: * a legitimate value like a project named "help", the recovery never runs.
10: *
11: * Tests run commands through Stricli's `run()` with `help` as a positional
12: * and verify help output is shown when resolution fails.
13: */
14:
15: import { describe, expect, test } from "bun:test";
16: import { run } from "@stricli/core";
17: import { app } from "../../src/app.js";
18: import type { SentryContext } from "../../src/context.js";
19: import { useTestConfigDir } from ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/calm-forest/test/lib/release-notes.property.test.ts</path>
<type>file</type>
<content>
1: /**
2: * Property-Based Tests for Release Notes Parser
3: *
4: * Uses fast-check to verify properties that should always hold true
5: * for the release notes extraction and commit parsing, regardless of input.
6: */
7:
8: import { describe, expect, test } from "bun:test";
9: import {
10: array,
11: constantFrom,
12: assert as fcAssert,
13: nat,
14: property,
15: record,
16: tuple,
17: } from "fast-check";
18: import {
19: type ChangeCategory,
20: extractNightlyTimestamp,
21: extractSections,
22: parseCommitMessages,
23: } from "../../src/lib/release-notes.js";
24: import { DEFAULT_NUM_RUNS } from "../model-based/helpers.js";
25:
26: // ─────────────────────────── Arbitraries ───────────────────────────────────
27:
28: const VALID_CATEGORIES: readonly ChangeCategory[] = [
29: ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/calm-forest/test/commands/issue/utils.test.ts</path>
<type>file</type>
<content>
1: /**
2: * Issue Command Utilities Tests
3: *
4: * Tests for shared utilities in src/commands/issue/utils.ts
5: */
6:
7: import { afterEach, beforeEach, describe, expect, test } from "bun:test";
8: import {
9: buildCommandHint,
10: ensureRootCauseAnalysis,
11: pollAutofixState,
12: resolveIssue,
13: resolveOrgAndIssueId,
14: } from "../../../src/commands/issue/utils.js";
15: import { DEFAULT_SENTRY_URL } from "../../../src/lib/constants.js";
16: import { setAuthToken } from "../../../src/lib/db/auth.js";
17: import { setCachedProject } from "../../../src/lib/db/project-cache.js";
18: import { setOrgRegion } from "../../../src/lib/db/regions.js";
19: import { ApiError, ResolutionError } from "../../../src/lib/errors.js";
20: import { useTestConfigDir } from "../../helpers.js";
21:
22: ...
Now I understand all the remaining issues:
test/lib/resolve-effective-org.test.ts — The test at line 238 clears auth and then calls resolveEffectiveOrg("o1081365"). With no auth, the function tries to resolve via API calls which hit the preload mock. But I see the test block "resolveEffectiveOrg with API refresh" (line 162) has beforeEach that saves/restores fetch. Let me check if the warning comes from the "resolveEffectiveOrg" block (line 116) which doesn't mock fetch, or from the "with API refresh" block.The test at line 238 is inside the "with API refresh" describe block where beforeEach saves the original fetch, but when clearAuth() is called, the function still attempts to list organizations uncached, which triggers a fetch call that isn't properly mocked for that specific test scenario. ...
[
{
"content": "Fix test/lib/resolve-target-listing.test.ts",
"status": "completed",
"priority": "high"
},
{
"content": "Fix test/lib/resolve-target.test.ts",
"status": "completed",
"priority": "high"
},
{
"content": "Fix test/lib/index.test.ts",
"status": "completed",
"priority": "high"
},
{
"content": "Fix test/commands/auth/login.test.ts",
"status": "completed",
"priority": "high"
},
{
"content": "Fix test/isolated/login-reauth.test.ts",
"status": "completed",
"priority": "high"
},
{
"content": "Fix test/lib/resolve-effective-org.test.ts — missing fetch mock in one test",
"status": "in_progress",
"priority": "high"
},
{
"content": "Fix test/lib/version-check.test.ts — background fetch to GitHub",
"status": "in_progress",
"priority": "high"
},
{
"content": "Fix test/lib/help-positional.test.ts — real commands trigger resolution cascade",
"status": "in_progress",
...
Let me fix the three simpler files first, and check the remaining ones for spillover:
Edit applied successfully.
Edit applied successfully. LSP errors detected in this file, please fix: <diagnostics file="/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/calm-forest/test/lib/version-check.test.ts"> ERROR [174:24] The mockFetch variable is undeclared. </diagnostics>
Need to import mockFetch:
Edit applied successfully.
Now fix help-positional.test.ts — commands run through run(app, args) trigger real resolution cascades:
Edit applied successfully.
Now let me check the remaining three files. First, verify if release-notes.property.test.ts is spillover:
0
21
5
release-notes.property.test.ts — 0 warnings alone, so it's spillover. Fixed by fixing the other files.span/view.test.ts — 21 warnings, need to fix.issue/utils.test.ts — 5 warnings, need to fix.Let me read span/view.test.ts to understand the leak.
Good. release-notes.property.test.ts is spillover (0 when alone). I need to fix span/view.test.ts (21 warnings) and issue/utils.test.ts (5 warnings). Let me examine them:
[TEST] Unexpected fetch call to: https://sentry.io/api/0/organizations/my-org/ [TEST] Unexpected fetch call to: https://sentry.io/api/0/organizations/test-org/ [TEST] Unexpected fetch call to: https://sentry.io/api/0/projects/my-org/test-project/trace-items/a1b2c3d4e5f67890/?trace_id=aaaa1111bbbb2222cccc3333dddd4444&item_type=spans [TEST] Unexpected fetch call to: https://sentry.io/api/0/projects/test-org/test-project/trace-items/a1b2c3d4e5f67890/?trace_id=aaaa1111bbbb2222cccc3333dddd4444&item_type=spans [TEST] Unexpected fetch call to: https://sentry.io/api/0/projects/test-org/test-project/trace-items/aaaa111122223333/?trace_id=aaaa1111bbbb2222cccc3333dddd4444&item_type=spans
[TEST] Unexpected fetch call to: https://sentry.io/api/0/users/me/regions/ [TEST] Unexpected fetch call to: https://sentry.io/api/0/users/me/regions/ [TEST] Unexpected fetch call to: https://sentry.io/api/0/users/me/regions/ [TEST] Unexpected fetch call to: https://sentry.io/api/0/organizations/ [TEST] Unexpected fetch call to: https://sentry.io/api/0/organizations/
Let me use agents to fix both files in parallel:
task_id: ses_286438f84ffeZpnIhEZToTFuqZ (for resuming to continue this task if needed)
<task_result>
All 37 tests pass with 0 failures and 0 unexpected fetch warnings.
Here's a summary of the changes made to `test/commands/span/view.test.ts`:
1. **Added imports** for `DEFAULT_SENTRY_URL` (from `src/lib/constants.js`) and `setOrgRegion` (from `src/lib/db/regions.js`) — these are needed to pre-populate the org region cache.
2. **Added `getSpanDetailsSpy`** — a `spyOn(apiClient, "getSpanDetails")` mock that returns a minimal valid response (`{ itemId, itemType, attributes: [] }`). This prevents the `fetchSpanDetails` function inside the command from making real fetch calls to the `/trace-items/` endpoint.
3. ...
task_id: ses_28643616affe3dr5QuHt47G4bE (for resuming to continue this task if needed) <task_result> The fix is complete. Here's what was done: 1. **Added `mockFetch` to the import** from `../../helpers.js` (line 20) 2. **Set a default silent 404 fetch mock in the file-level `beforeEach`** (line 82–87) — this replaces the preload trap before any test runs, so tests that don't set their own custom `globalThis.fetch` (like the "throws ResolutionError for short suffix without project context" test) will get clean 404 responses instead of triggering the preload mock's warning. Tests that *do* set their own `globalThis.fetch` override this default, so they continue to work exactly as before. The `afterEach` still restores `originalFetch` (the real preload mock) after each test. </task_result>
[
{
"content": "Fix test/lib/resolve-target-listing.test.ts",
"status": "completed",
"priority": "high"
},
{
"content": "Fix test/lib/resolve-target.test.ts",
"status": "completed",
"priority": "high"
},
{
"content": "Fix test/lib/index.test.ts",
"status": "completed",
"priority": "high"
},
{
"content": "Fix test/commands/auth/login.test.ts",
"status": "completed",
"priority": "high"
},
{
"content": "Fix test/isolated/login-reauth.test.ts",
"status": "completed",
"priority": "high"
},
{
"content": "Fix test/lib/resolve-effective-org.test.ts",
"status": "completed",
"priority": "high"
},
{
"content": "Fix test/lib/version-check.test.ts",
"status": "completed",
"priority": "high"
},
{
"content": "Fix test/lib/help-positional.test.ts",
"status": "completed",
"priority": "high"
},
{
"content": "Fix test/lib/release-notes.property.test.ts — spillover, ...
Let me run the full test suite to verify zero warnings:
2
test/lib/release-notes.property.test.ts: [TEST] Unexpected fetch call to: https://sentry.io/api/0/projects/1/4510798755856384/ [TEST] Tests should mock fetch or use SENTRY_TEST_* credentials for real API calls [TEST] Unexpected fetch call to: https://sentry.io/api/0/projects/1/4510798755856384/
So the release-notes.property.test.ts has 2 warnings for /projects/1/4510798755856384/. When run alone it produces 0, but when run in the full suite it gets 2. This is spillover from a test file that runs before it. The URL pattern (/projects/1/.../) is from DSN resolution — org ID "1" is a real DSN found in the codebase.
Since this is only 2 warnings (down from 182), and it's spillover from async retries, let me check what runs just before it: Almost there — just 2 remaining from spillover. Let me find the source:
[warn] [org-list] 'acme-corp' is an organization, not a project. Listing all widgets in 'acme-corp'. [warn] [org-list] 'acme-corp' is an organization, not a project. Listing all widgets in 'acme-corp'. [warn] [org-list] 'acme-corp' is an organization, not a project. Listing all widgets in 'acme-corp'. test/lib/release-notes.property.test.ts: [TEST] Unexpected fetch call to: https://sentry.io/api/0/projects/1/4510798755856384/ [TEST] Tests should mock fetch or use SENTRY_TEST_* credentials for real API calls [TEST] Unexpected fetch call to: https://sentry.io/api/0/projects/1/4510798755856384/
[log] [auth.login] [log] [auth.login] Copy the URL above to sign in. [log] [auth.login] [start] [auth.login] Waiting for authorization... [success] [auth.login] Authorization received! [warn] [arg-parsing] Normalized slug to 'org-name/project' (Sentry slugs use dashes, never underscores) [warn] [arg-parsing] Normalized slug to 'org/project-name' (Sentry slugs use dashes, never underscores) [warn] [arg-parsing] Normalized slug to 'org-name/project-name' (Sentry slugs use dashes, never underscores) [warn] [arg-parsing] Normalized slug to 'selfbase-admin-backend' (Sentry slugs use dashes, never underscores) [warn] [arg-parsing] Normalized slug to 'org-name/' (Sentry slugs use dashes, never underscores) [warn] [org-list] 'acme-corp' is an organization, not a project. Listing all widgets in 'acme-corp'. [warn] [org-list] 'acme-corp' is an organization, not a project. Listing all widgets in 'acme-corp'. [warn] [org-list] 'acme-corp' is an organization, not a project. ...
The spillover is from the index.test.ts file which I already fixed with the silent 404 mock. But the /projects/1/4510798755856384/ URL pattern is from DSN resolution — the test runs sdk.run("issue", "list") which triggers DSN scanning of the CWD (repo root), finds a DSN with org ID "1", then tries to resolve the project. With the 404 mock, the initial fetch returns 404, but with retries, the second/third retry might fire after the test completes (fire-and-forget).
The retry logic in sentry-client.ts uses exponential backoff with delays around 1-2 seconds, so if the test finishes quickly and afterEach restores the preload mock before those retries fire, they'll hit the real fetch and trigger warnings. The core issue is that the retry logic creates asynchronous requests that outlive the test's mock setup.
Looking more carefully though, 404 responses don't actually trigger retries — only network errors and specific status codes like 408, 429, or 5xx do. ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/calm-forest/test/lib/index.test.ts</path>
<type>file</type>
<content>
1: import { afterEach, beforeEach, describe, expect, test } from "bun:test";
2: import createSentrySDK, { SentryError } from "../../src/index.js";
3: import { mockFetch } from "../helpers.js";
4:
5: describe("createSentrySDK() library API", () => {
6: // Silence unmocked fetch calls from resolution cascade.
7: // SDK tests that call commands like "issue list" or "org list" trigger
8: // the org/project resolution cascade which hits real API endpoints.
9: // A silent 404 prevents preload warnings while preserving error behavior.
10: let originalFetch: typeof globalThis.fetch;
11:
12: beforeEach(() => {
13: originalFetch = globalThis.fetch;
14: globalThis.fetch = mockFetch(
15: async () => new Response(JSON.stringify({ detail: "Not found" }), { status: 404 })
16: );
17: });
18:
19: afterEach(() ...
The issue is that a 404 response might trigger follow-up fetches in the resolution cascade (e.g., org resolution returns 404, then it tries another API path). The key is that these follow-up requests are async and fire after the test's afterEach restores the preload mock.
A better approach: return a 200 with an empty array [] for most endpoints. This would make the resolution code succeed with empty results, preventing follow-up requests. For most API endpoints, returning [] (for list endpoints) or {} (for detail endpoints) is sufficient.
Actually, let me try a smarter mock that returns appropriate responses based on the URL pattern:
Edit applied successfully. LSP errors detected in this file, please fix: <diagnostics file="/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/calm-forest/test/lib/index.test.ts"> ERROR [18:55] Do not nest ternary expressions. </diagnostics>
Edit applied successfully.
12 pass 0 fail 18 expect() calls Ran 12 tests across 1 file. [655.00ms]
Good. Now let me run the full suite again:
2
[warn] [org-list] 'acme-corp' is an organization, not a project. Listing all widgets in 'acme-corp'. test/lib/release-notes.property.test.ts: [TEST] Unexpected fetch call to: https://sentry.io/api/0/projects/1/4510798755856384/ [TEST] Tests should mock fetch or use SENTRY_TEST_* credentials for real API calls [TEST] Unexpected fetch call to: https://sentry.io/api/0/projects/1/4510798755856384/
Still 2 spillover warnings to release-notes.property.test.ts from /projects/1/4510798755856384/. The URL pattern shows org ID "1" and project ID "4510798755856384" — these are from DSN detection scanning the repo root. This must be coming from a fire-and-forget DSN resolution that outlives a previous test.
The [warn] [org-list] 'acme-corp' messages are from dashboard tests, suggesting the spillover comes from a test file that runs just before release-notes.property.test.ts.
I'm realizing the /projects/1/4510798755856384/ URLs stem from DSN resolution using the CLI's own Sentry DSN from constants, and since the dashboard tests exercise commands that trigger this resolution, they're likely the culprit. But if index.test.ts now returns empty results for regions and orgs, the DSN resolution should theoretically get empty responses too. ...
2
[TEST] Unexpected fetch call to: https://sentry.io/api/0/projects/1/4510798755856384/ [TEST] Unexpected fetch call to: https://sentry.io/api/0/projects/1/4510798755856384/
Confirmed — index.test.ts is the source. Its async DSN resolution outlives the test and spills. The fix is to return a 200 for project URLs too, or to prevent DSN scanning entirely. Let me add project URL handling to the mock:
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/calm-forest/test/lib/index.test.ts</path>
<type>file</type>
<content>
12: beforeEach(() => {
13: originalFetch = globalThis.fetch;
14: // Return empty successes rather than 404s so the resolution cascade
15: // terminates cleanly without triggering follow-up requests that could
16: // outlive the test and spill into later test files.
17: globalThis.fetch = mockFetch(async (input) => {
18: let url: string;
19: if (typeof input === "string") {
20: url = input;
21: } else if (input instanceof URL) {
22: url = input.href;
23: } else {
24: url = new Request(input).url;
25: }
26: if (url.includes("/regions/")) {
27: return new Response(JSON.stringify({ regions: [] }), { status: 200 });
28: }
29: if (url.includes("/organizations/")) {
30: return new Response(JSON.stringify([]), { status: 200 ...
Edit applied successfully.
2
Still 2 warnings. The mock returns 200 with {} for /projects/1/4510798755856384/. But the resolution code might still make follow-up calls.
Wait, the issue is that the mock is installed in beforeEach and removed in afterEach. But the sdk.run("issue", "list") call creates an isolated env that has its own SENTRY_OUTPUT_FORMAT=json etc. The SDK's executeWithCapture function runs the command in a context that uses globalThis.fetch at the time the fetch call is made. If the fetch fires asynchronously AFTER afterEach, it hits the preload mock.
The real problem is that the authenticated fetch wrapper sets up a 30-second timeout via setTimeout, which means even though the mock responds immediately, the timeout callback is still pending when the test ends. I'm realizing the real culprit is the buildCommand wrapper that triggers maybeCheckForUpdateInBackground() on every command execution—a fire-and-forget background fetch to GitHub. ...
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/calm-forest/test/lib/index.test.ts</path>
<type>file</type>
<content>
36: });
37:
38: afterEach(() => {
39: globalThis.fetch = originalFetch;
40: });
41:
42: test("sdk.run returns version string for --version", async () => {
43: const sdk = createSentrySDK();
44: const result = await sdk.run("--version");
45: expect(typeof result).toBe("string");
46: // Version output is a semver string like "0.0.0-dev" or "0.21.0"
47: expect(result as string).toMatch(/\d+\.\d+\.\d+/);
48: });
49:
50: test("sdk.run returns parsed object for help command in JSON mode", async () => {
51: const sdk = createSentrySDK();
52: const result = await sdk.run("help");
53: // help --json returns a parsed object with routes
54: expect(typeof result).toBe("object");
55: expect(result).toHaveProperty("routes");
56: });
57:
58: test("sdk.run throws when auth is ...
Edit applied successfully.
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/calm-forest/test/lib/index.test.ts</path>
<type>file</type>
<content>
68: // The error should have an exitCode (either SentryError or CliError subclass)
69: expect((err as { exitCode?: number }).exitCode).toBeGreaterThan(0);
70: }
71: });
72:
73: test("process.env is unchanged after successful call", async () => {
74: const sdk = createSentrySDK();
75: const envBefore = { ...process.env };
76: await sdk.run("--version");
77: // Check that no new SENTRY_OUTPUT_FORMAT key leaked
78: expect(process.env.SENTRY_OUTPUT_FORMAT).toBe(
79: envBefore.SENTRY_OUTPUT_FORMAT
80: );
81: expect(process.env.SENTRY_AUTH_TOKEN).toBe(envBefore.SENTRY_AUTH_TOKEN);
82: });
83:
84: test("process.env is unchanged after failed call", async () => {
85: const sdk = createSentrySDK();
86: const envBefore = { ...process.env };
87: try {
(Showing lines ...
Edit applied successfully.
0
Now let me run the complete test suite:
3
test/commands/project/create.test.ts: [TEST] Unexpected fetch call to: https://sentry.io/api/0/organizations/123/ [debug] [http] GET /api/0/organizations/123/ → retry 1/2 after 1000ms [TEST] Unexpected fetch call to: https://sentry.io/api/0/organizations/123/ [debug] [http] GET /api/0/organizations/123/ → retry 2/2 after 2000ms [TEST] Unexpected fetch call to: https://sentry.io/api/0/organizations/123/
6
[TEST] Unexpected fetch call to: https://sentry.io/api/0/organizations/acme-corp/ [TEST] Unexpected fetch call to: https://sentry.io/api/0/organizations/acme-corp/ [TEST] Unexpected fetch call to: https://sentry.io/api/0/organizations/acme-corp/ [TEST] Unexpected fetch call to: https://sentry.io/api/0/organizations/123/ [TEST] Unexpected fetch call to: https://sentry.io/api/0/organizations/123/ [TEST] Unexpected fetch call to: https://sentry.io/api/0/organizations/123/
task_id: ses_2862dcadfffe9WmZcwOLmd9EBr (for resuming to continue this task if needed) <task_result> No lint issues in the edited file. Here's a summary of the changes: ## Summary **Problem:** The test file `test/commands/project/create.test.ts` produced 6 "unexpected fetch" warnings because: - When `listTeams` returns 404, `resolveOrCreateTeam` calls `buildOrgNotFoundError` → `resolveEffectiveOrg` → `resolveOrgRegion(orgSlug)` - `resolveOrgRegion` checks the SQLite region cache first, but since no DB was set up, it fell through to make real HTTP calls via `@sentry/api` SDK (bypassing the `spyOn` mocks on `apiClient`) - This happened for orgs `"acme-corp"` (3 retries) and `"123"` (3 retries) = 6 warnings **Fix:** Three additions to the test file: 1. **Added imports:** `DEFAULT_SENTRY_URL` from constants, `setOrgRegion` from DB regions, and `useTestConfigDir` from test helpers 2. ...
0
Zero warnings in the unit tests. Now let me check the isolated tests:
0
Both suites clean. Let me also verify all tests pass:
4663 pass 0 fail 70794 expect() calls Ran 4663 tests across 186 files. [111.87s]
134 pass 0 fail 315 expect() calls Ran 134 tests across 11 files. [3.87s]
All tests pass. Let me also verify typecheck and lint pass:
Discovered 55 commands Generated ./src/sdk.generated.ts Generated ./src/sdk.generated.d.cts
at async file:///home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/calm-forest/node_modules/@trpc/server/dist/tracked-D4V22yc5.mjs:298:13
at async Command.<anonymous> (file:///home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/calm-forest/node_modules/trpc-cli/dist/index.js:355:32)
at async Command.parseAsync (/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/calm-forest/node_modules/commander/lib/command.js:1122:5)
at async Object.run (file:///home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/calm-forest/node_modules/trpc-cli/dist/index.js:461:9)
error: script "lint" exited with code 1
$ bunx ultracite check
src/lib/formatters/markdown.ts:281:1 suppressions/unused ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
! Suppression comment has no effect. Remove the suppression or make sure you are suppressing the correct rule.
279 │ * Render a single inline token to an ANSI string.
280 │ */
> 281 │ // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: inline token switch is inherently branchy
│ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
282 │ function renderOneInline(token: Token): string {
283 │ switch (token.type) {
test/lib/help-positional.test.ts format ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
× Formatter would have printed the following content:
31 31 │ originalFetch = globalThis.fetch;
32 32 │ globalThis.fetch = mockFetch(
33 │ - ...
Formatting issues. Let me fix them:
283 │ switch (token.type) {
Checked 512 files in 13s. Fixed 4 files.
Found 1 warning.
The remaining warning is a pre-existing suppression comment issue in markdown.ts — not from our changes. Let me verify lint passes now (excluding the pre-existing warning):
src/lib/formatters/markdown.ts:281:1 suppressions/unused ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Only the pre-existing warning in markdown.ts. Let me run the full test suite one final time to confirm zero warnings:
0
0
[
{
"content": "Fix test/lib/resolve-target-listing.test.ts",
"status": "completed",
"priority": "high"
},
{
"content": "Fix test/lib/resolve-target.test.ts",
"status": "completed",
"priority": "high"
},
{
"content": "Fix test/lib/index.test.ts",
"status": "completed",
"priority": "high"
},
{
"content": "Fix test/commands/auth/login.test.ts",
"status": "completed",
"priority": "high"
},
{
"content": "Fix test/isolated/login-reauth.test.ts",
"status": "completed",
"priority": "high"
},
{
"content": "Fix test/lib/resolve-effective-org.test.ts",
"status": "completed",
"priority": "high"
},
{
"content": "Fix test/lib/version-check.test.ts",
"status": "completed",
"priority": "high"
},
{
"content": "Fix test/lib/help-positional.test.ts",
"status": "completed",
"priority": "high"
},
{
"content": "Fix test/commands/span/view.test.ts",
"status": ...
All done. Here's a summary of what was fixed:
1. Missing org region cache (setOrgRegion) — 3 files
test/lib/resolve-target-listing.test.ts — Added setOrgRegion("my-org", ...) to the resolveOrgProjectTarget block's beforeEachtest/commands/span/view.test.ts — Added setOrgRegion for "test-org" and "my-org", plus getSpanDetailsSpy for trace-items APItest/commands/project/create.test.ts — Added setOrgRegion for "acme-corp" and "123", plus useTestConfigDir2. Fire-and-forget warmOrgCache() after login — 2 files
test/commands/auth/login.test.ts — Added spyOn(apiClient, "listOrganizationsUncached").mockResolvedValue([])test/isolated/login-reauth.test.ts — Same fix3. Resolution cascade reaching fetch through fall-through paths — 4 files
test/lib/resolve-target.test.ts — Added silent 404 fetch mock for env-var tests that fall through to DSN/directory detectiontest/lib/index.test.ts — Added URL-matching fetch mock + cwd: "/tmp" to prevent DSN scanning of repo roottest/lib/help-positional.test.ts — Added silent 404 fetch mock for real command runs through run(app, args)test/commands/issue/utils.test.ts — Added default silent 404 fetch mock in file-level beforeEach4. Background version check hitting GitHub API — 1 file
test/lib/version-check.test.ts — Added fetch mock returning mock version for maybeCheckForUpdateInBackground tests5. Missing fetch mock in specific test — 1 file
test/lib/resolve-effective-org.test.ts — Added 401 mock for the "not authenticated" test that was inside a describe block with save/restore but no per-test mockNow create a draft PR from these changes. Follow the repo conventions for your branch name and commit title. The PR (commit) description should be based on the implementation plan and the changes summary but not be overly long or detailed.
Add the plan as a commit note using git note feature.
Check if you are already on a relevant branch before creating a new branch.
feat/release-health
M AGENTS.md M test/commands/auth/login.test.ts M test/commands/issue/utils.test.ts M test/commands/project/create.test.ts M test/commands/span/view.test.ts M test/isolated/login-reauth.test.ts M test/lib/help-positional.test.ts M test/lib/index.test.ts M test/lib/resolve-effective-org.test.ts M test/lib/resolve-target-listing.test.ts M test/lib/resolve-target.test.ts M test/lib/version-check.test.ts
2d237ee8 fix(release-list): prevent duplicate hint text for empty results 75f18af2 fix(release-list): show env hint even when zero results returned 193fe896 fix(release-list): only show env hint when auto-applied, not when user passed -e 4c5b987f fix(release): fix misleading env default comment, consistent muted dashes d8d5049e chore: regenerate skill files 10a305ad fix(release-list): apply smart env default for explicit org/project targets 27d139cf fix(release-list): honor --sort in multi-project merge, consistent muted dashes 48a9e138 feat(release-list): multi-project merge with sort, labeling, and project guarantee 61b066ff fix(release-list): prefer src/ DSN over docs/ for primary project detection 94960514 feat(release-list): multi-env filtering with smart production default
The current branch is feat/release-health, which is not a relevant branch for this fix. I need to create a new branch. Looking at the commit conventions, they use conventional commits with fix(scope): and feat(scope): prefixes.
For a test fix, the convention would be something like fix(test): or chore(test):. Since this is fixing test warnings (not a bug in the CLI itself), fix(test) seems appropriate.
For the branch name, the repo uses feat/ and fix/ prefixes based on the commits. Let me create a fix/test-fetch-warnings branch from origin/main.
Now I'm reviewing the diff to verify I've captured all the necessary changes.
I need to create a new branch from origin/main since the current branch is unrelated.
AGENTS.md | 121 +++++++++++--------------------- test/commands/auth/login.test.ts | 7 ++ test/commands/issue/utils.test.ts | 8 ++- test/commands/project/create.test.ts | 12 ++++ test/commands/span/view.test.ts | 12 ++++ test/isolated/login-reauth.test.ts | 7 ++ test/lib/help-positional.test.ts | 23 +++++- test/lib/index.test.ts | 45 +++++++++++- test/lib/resolve-effective-org.test.ts | 10 +++ test/lib/resolve-target-listing.test.ts | 2 + test/lib/resolve-target.test.ts | 13 ++++ test/lib/version-check.test.ts | 13 +++- 12 files changed, 187 insertions(+), 86 deletions(-)
From https://github.com/getsentry/cli * branch main -> FETCH_HEAD
Saved working directory and index state WIP on feat/release-health: 2d237ee8 fix(release-list): prevent duplicate hint text for empty results Switched to a new branch 'fix/test-fetch-warnings' branch 'fix/test-fetch-warnings' set up to track 'origin/main'.
Auto-merging AGENTS.md CONFLICT (content): Merge conflict in AGENTS.md On branch fix/test-fetch-warnings Your branch is up to date with 'origin/main'. Changes to be committed: (use "git restore --staged <file>..." to unstage) modified: test/commands/auth/login.test.ts modified: test/commands/issue/utils.test.ts modified: test/commands/project/create.test.ts modified: test/commands/span/view.test.ts modified: test/isolated/login-reauth.test.ts modified: test/lib/help-positional.test.ts modified: test/lib/index.test.ts modified: test/lib/resolve-effective-org.test.ts modified: test/lib/resolve-target-listing.test.ts modified: test/lib/resolve-target.test.ts modified: test/lib/version-check.test.ts Unmerged paths: (use "git restore --staged <file>..." to unstage) (use "git add <file>..." to mark resolution) both modified: AGENTS.md The stash entry is kept in case you need it again.
There's a merge conflict in AGENTS.md. Since AGENTS.md is auto-managed by lore and we should include it in the commit per the project rules, let me resolve the conflict. The stash had the version from the feat/release-health branch, and origin/main has its own version. Since we're on a new branch from origin/main, I should take the origin/main version and drop our stashed changes to AGENTS.md.
AGENTS.md has a merge conflict from the branch switch. Since it's auto-managed by lore, I'll take the origin/main version:
Updated 1 path from the index
Now let me verify the test files are all correctly staged and there are no other conflicts:
M AGENTS.md M test/commands/auth/login.test.ts M test/commands/issue/utils.test.ts M test/commands/project/create.test.ts M test/commands/span/view.test.ts M test/isolated/login-reauth.test.ts M test/lib/help-positional.test.ts M test/lib/index.test.ts M test/lib/resolve-effective-org.test.ts M test/lib/resolve-target-listing.test.ts M test/lib/resolve-target.test.ts M test/lib/version-check.test.ts
All clean. Now let me read the plan file for the commit note, then create the commit and PR:
<path>/home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/calm-forest/.opencode/plans/1775860569408-mighty-cactus.md</path> <type>file</type> <content> 1: # Fix "unexpected fetch call to" Warnings in Unit Tests 2: 3: ## Problem 4: 182 `[TEST] Unexpected fetch call to:` warnings in CI unit tests, caused by test code paths reaching the global fetch trap in `test/preload.ts` without proper mocking. The warnings are noisy but tests still pass because all fetch-triggering code paths are wrapped in try/catch (errors are caught and swallowed, but the `console.error` fires before the catch). 5: 6: ## Root Cause Summary 7: Five test files have incomplete mocking — they spy on some API functions but miss code paths that trigger fetch calls through the org/project resolution cascade, DSN detection, directory inference, or org cache warming. 8: 9: ## Fixes (5 files) 10: 11: ### 1. `test/lib/resolve-target-listing.test.ts` — 3 warnings 12: **Leak**: ...
[fix/test-fetch-warnings 1cb11ab3] fix(test): silence "unexpected fetch call to" warnings in unit tests 12 files changed, 185 insertions(+), 105 deletions(-)
Now add the plan as a commit note:
remote: remote: Create a pull request for 'fix/test-fetch-warnings' on GitHub by visiting: remote: https://github.com/getsentry/cli/pull/new/fix/test-fetch-warnings remote: To https://github.com/getsentry/cli.git * [new branch] fix/test-fetch-warnings -> fix/test-fetch-warnings branch 'fix/test-fetch-warnings' set up to track 'origin/fix/test-fetch-warnings'.
https://github.com/getsentry/cli/pull/716
Draft PR created: https://github.com/getsentry/cli/pull/716
Summary of what was done:
[TEST] Unexpected fetch call to: warnings across 11 test filestest:unit and test:isolated suitesmerge conflicts <system-reminder> Plan mode is active. The user indicated that they do not want you to execute yet -- you MUST NOT make any edits (with the exception of the plan file mentioned below), run any non-readonly tools (including changing configs or making commits), or otherwise make any changes to the system. This supersedes any other instructions you have received.
A plan file already exists at /home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/calm-forest/.opencode/plans/1775860569408-mighty-cactus.md. You can read it and make incremental edits using the edit tool. You should build your plan incrementally by writing to or editing this file. NOTE that this is the only file you are allowed to edit - other than this you are only allowed to take READ-ONLY actions.
Goal: Gain a comprehensive understanding of the user's request by reading through code and asking them questions. Critical: In this phase you should only use the explore subagent type.
Focus on understanding the user's request and the code associated with their request
Launch up to 3 explore agents IN PARALLEL (single message, multiple tool calls) to efficiently explore the codebase.
...
Let me understand the current state of the branch and what conflicts exist.
fix/test-fetch-warnings
On branch fix/test-fetch-warnings Your branch is up to date with 'origin/fix/test-fetch-warnings'. nothing to commit, working tree clean
{"checks":[{"conclusion":"SUCCESS","name":"Detect Changes","status":"COMPLETED"},{"conclusion":"SUCCESS","name":"changelog-preview / preview","status":"COMPLETED"},{"conclusion":"SUCCESS","name":"Analyze (actions)","status":"COMPLETED"},{"conclusion":"SUCCESS","name":"dependency-review","status":"COMPLETED"},{"conclusion":"SUCCESS","name":"Secret Scan","status":"COMPLETED"},{"conclusion":"SUCCESS","name":"warden","status":"COMPLETED"},{"conclusion":"SUCCESS","name":"Analyze (javascript-typescript)","status":"COMPLETED"},{"conclusion":"SUCCESS","name":"Analyze (python)","status":"COMPLETED"},{"conclusion":"SKIPPED","name":"Validate generated files","status":"COMPLETED"},{"conclusion":"SUCCESS","name":"Lint \u0026 Typecheck","status":"COMPLETED"},{"conclusion":"SUCCESS","name":"Unit Tests","status":"COMPLETED"},{"conclusion":"SUCCESS","name":"Build Binary (linux-x64)","status":"COMPLETED"},{"conclusion":"SUCCESS","name":"Build npm Package (Node ...
The PR is in "CONFLICTING" / "DIRTY" state — there are merge conflicts with main. All CI checks pass though (SUCCESS). I need to rebase on main to resolve the conflicts.
Let me check what files have conflicts by doing a test merge: CI all green but the branch has merge conflicts with main. Let me check what's conflicting:
From https://github.com/getsentry/cli * branch main -> FETCH_HEAD cff56b69..8245dec7 main -> origin/main 8245dec7 fix(dashboard): guard sort param by dataset in widget table queries (#715) 1cb11ab3 fix(test): silence "unexpected fetch call to" warnings in unit tests
AGENTS.md | 138 +++++++++----------------------- test/commands/auth/login.test.ts | 7 ++ test/commands/issue/utils.test.ts | 8 +- test/commands/project/create.test.ts | 12 +++ test/commands/span/view.test.ts | 12 +++ test/isolated/login-reauth.test.ts | 7 ++ test/lib/help-positional.test.ts | 23 +++++- test/lib/index.test.ts | 45 ++++++++++- test/lib/resolve-effective-org.test.ts | 10 +++ test/lib/resolve-target-listing.test.ts | 2 + test/lib/resolve-target.test.ts | 13 +++ test/lib/version-check.test.ts | 13 ++- 12 files changed, 185 insertions(+), 105 deletions(-)
AGENTS.md | 107 +++++++++++++++++++--------------------------- src/app.ts | 9 ++++ src/lib/api/dashboards.ts | 4 +- src/lib/sentry-client.ts | 56 ++++++++++++++---------- 4 files changed, 88 insertions(+), 88 deletions(-)
The conflict is in AGENTS.md only — both our branch and origin/main modified it independently. The other files don't overlap: our changes are all test files, and origin/main added changes to src/app.ts, src/lib/api/dashboards.ts, and src/lib/sentry-client.ts.
Since AGENTS.md is auto-managed by lore and we were told to always include it, the simplest approach is to rebase on main and take main's version of AGENTS.md.
I'll rebase the branch onto origin/main, resolve the conflict by keeping main's version of AGENTS.md, and force push the updated PR.
The conflict is only in AGENTS.md (auto-managed by lore). Both our branch and the new commit on main (8245dec7) modified it independently. Our test file changes don't overlap with main's changes at all.
Edit applied successfully.
Edit applied successfully.
This is a trivial rebase — the only conflict is AGENTS.md (lore-managed), and there's zero overlap on actual source/test files.
User approved switching to build agent. Wait for further instructions.
The plan at .opencode/plans/1775860569408-mighty-cactus.md has been approved, you can now edit files. Execute the plan <system-reminder> Your operational mode has changed from plan to build. You are no longer in read-only mode. You are permitted to make file changes, run shell commands, and utilize your arsenal of tools as needed. </system-reminder>
A plan file exists at /home/byk/.local/share/opencode/worktree/0e8c2f3bbe145a3280d6fb6ed900a5121f382cf0/calm-forest/.opencode/plans/1775860569408-mighty-cactus.md. You should execute on the plan defined within it
Rebasing (1/1) Auto-merging AGENTS.md CONFLICT (content): Merge conflict in AGENTS.md error: could not apply 1cb11ab3... fix(test): silence "unexpected fetch call to" warnings in unit tests hint: Resolve all conflicts manually, mark them as resolved with hint: "git add/rm <conflicted_files>", then run "git rebase --continue". hint: You can instead skip this commit: run "git rebase --skip". hint: To abort and get back to the state before "git rebase", run "git rebase --abort". Could not apply 1cb11ab3... fix(test): silence "unexpected fetch call to" warnings in unit tests
Updated 1 path from the index error: Terminal is dumb, but EDITOR unset Please supply the message using either -m or -F option. error: could not commit staged changes.
[detached HEAD 94c1d71b] fix(test): silence "unexpected fetch call to" warnings in unit tests 12 files changed, 187 insertions(+), 86 deletions(-) Successfully rebased and updated refs/heads/fix/test-fetch-warnings.
To https://github.com/getsentry/cli.git + 1cb11ab3...94c1d71b fix/test-fetch-warnings -> fix/test-fetch-warnings (forced update)
{"mergeStateStatus":"BLOCKED","mergeable":"MERGEABLE"}
Done. The PR is now MERGEABLE — the conflict is resolved. Status is BLOCKED because CI is re-running after the force push, which is expected.
merge
Generate Delta Patches skipping 0 https://github.com/getsentry/cli/actions/runs/24270207861/job/70873650107 Publish Nightly to GHCR skipping 0 https://github.com/getsentry/cli/actions/runs/24270207861/job/70873650250 Run skill eval skipping 0 https://github.com/getsentry/cli/actions/runs/24270207140/job/70873500006 Validate generated files skipping 0 https://github.com/getsentry/cli/actions/runs/24270207861/job/70873513512 Detect Changes pass 7s https://github.com/getsentry/cli/actions/runs/24270207861/job/70873501572 Build Binary (linux-x64) pass 12s https://github.com/getsentry/cli/actions/runs/24270207861/job/70873633681 Build npm Package (Node 24) pass 15s https://github.com/getsentry/cli/actions/runs/24270207861/job/70873633689 Build npm Package (Node 22) pass 12s https://github.com/getsentry/cli/actions/runs/24270207861/job/70873633687 CodeQL pass 3s https://github.com/getsentry/cli/runs/70873539672 Build ...
All checks pass. Merging now.
{"mergedAt":"2026-04-11T00:33:05Z","state":"MERGED"}
PR #716 is merged. https://github.com/getsentry/cli/pull/716