Skip to content

Commit 9baa39e

Browse files
committed
chore: sync AGENTS.md lore entries
1 parent 89feac4 commit 9baa39e

File tree

1 file changed

+7
-5
lines changed

1 file changed

+7
-5
lines changed

AGENTS.md

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -642,25 +642,27 @@ mock.module("./some-module", () => ({
642642
643643
### Gotcha
644644
645+
<!-- lore:019caf48-e010-7d86-a35e-b6bdfaae9b23 -->
646+
* **sudo scripts: $HOME resolves to /root, use SUDO\_USER for original user paths**: When a script runs under sudo, $HOME resolves to /root, not the invoking user's home. SSH keys, config files, etc. referenced via $HOME will fail. Fix: use \`REAL\_HOME=$(eval echo ~${SUDO\_USER:-$USER})\` at the top of the script and reference that instead of $HOME for user-owned paths like ~/.ssh/id\_ed25519.
645647
<!-- lore:019c9a88-bf99-7322-b192-aafe4636c600 -->
646648
* **getsentry/codecov-action enables JUnit XML test reporting by default**: The \`getsentry/codecov-action@main\` has \`enable-tests: true\` by default, which searches for JUnit XML files matching \`\*\*/\*.junit.xml\`. If the test framework doesn't produce JUnit XML, the action emits 3 warnings on every CI run: "No files found matching pattern", "No JUnit XML files found", and "Please ensure your test framework is generating JUnit XML output". Fix: either set \`enable-tests: false\` in the action inputs, or configure the test runner to output JUnit XML. For Bun, add \`\[test.reporter] junit = "test-results.junit.xml"\` to \`bunfig.toml\` and add \`\*.junit.xml\` to \`.gitignore\`.
647649
<!-- lore:019caedf-91c7-79a5-8357-7f13a532f36b -->
648650
* **OpenCode worktrees accumulate massive .test-tmp dirs — clean periodically**: OpenCode worktrees at \`~/.local/share/opencode/worktree/\` accumulate massive \`.test-tmp/\` dirs (14+ GB in getsentry/cli). Worktrees are ephemeral — safe to delete entirely between sessions. Targeted: \`rm -rf ~/.local/share/opencode/worktree/\*/.test-tmp\`. Also: \`git checkout main\` fails because main is used by the worktree. Workaround: always use \`origin/main\`\`git checkout -b \<branch> origin/main\` or rebase onto \`origin/main\`, never the local \`main\` branch.
649-
<!-- lore:019c9994-d161-783e-8b3e-79457cd62f42 -->
650-
* **Biome lint: Response.redirect() required, nested ternaries forbidden**: Biome lint rules that frequently trip up code in this codebase: (1) \`useResponseRedirect\`: Use \`Response.redirect(url, status)\` not \`new Response(null, {status: 307, headers: {location}})\`. Exception: testing missing Location header requires \`new Response(null, {status: 307})\`. (2) \`noNestedTernary\`: Replace with \`if/else\` blocks. (3) \`noComputedPropertyAccess\`: Use \`obj.property\` not \`obj\["property"]\` for string literal keys. (4) Max cognitive complexity of 15 per function — extract helper functions to stay under. Pattern: keep dispatch function thin (condition + delegate), logic in helpers.
651651
<!-- lore:019c8c31-f52f-7230-9252-cceb907f3e87 -->
652652
* **Bugbot flags defensive null-checks as dead code — keep them with JSDoc justification**: Cursor Bugbot and Sentry Seer repeatedly flag two false positives: (1) defensive null-checks as "dead code" — keep them with JSDoc explaining why the guard exists for future safety, especially when removing would require \`!\` assertions banned by \`noNonNullAssertion\`. (2) stderr spinner output during \`--json\` mode — always a false positive since progress goes to stderr, JSON to stdout. Reply explaining the rationale and resolve.
653+
<!-- lore:019c9994-d161-783e-8b3e-79457cd62f42 -->
654+
* **Biome lint: Response.redirect() required, nested ternaries forbidden**: Biome lint rules that frequently trip up this codebase: (1) \`useResponseRedirect\`: use \`Response.redirect(url, status)\` not \`new Response\`. (2) \`noNestedTernary\`: use \`if/else\`. (3) \`noComputedPropertyAccess\`: use \`obj.property\` not \`obj\["property"]\`. (4) Max cognitive complexity 15 per function — extract helpers to stay under.
653655
<!-- lore:019c99c3-766b-7ae7-be1f-4d5e08da27d3 -->
654656
* **Cherry-picking GHCR tests requires updating mocks from version.json to GHCR manifest flow**: Nightly test mocks must use the 3-step GHCR flow: (1) token exchange at \`ghcr.io/token\`, (2) manifest fetch at \`/manifests/nightly\` returning JSON with \`annotations.version\` and \`layers\[].annotations\["org.opencontainers.image.title"]\`, (3) blob download returning \`Response.redirect()\` to Azure. The \`mockNightlyVersion()\` and \`mockGhcrNightlyVersion()\` helpers must handle all three URLs. Platform-specific filenames in manifest layers must use \`if/else\` blocks (Biome forbids nested ternaries).
655657
656658
### Pattern
657659
658-
<!-- lore:019caf37-20cb-7a17-bd5f-eadb27ea350a -->
659-
* **Re-run prior art search when task scope pivots**: When a conversation starts with one goal (e.g., "fix web UI performance") and pivots to a different approach (e.g., "embed assets in binary"), always run a fresh GitHub prior art search with keywords specific to the new scope before starting implementation. Simple searches like \`gh pr list --search "embed"\` or \`--search "binary"\` would have immediately surfaced PR #12829 — a near-identical feature PR already open for 3 weeks. The failure mode: anchoring on the original framing's keywords ("performance", "virtualization") and never re-searching when the deliverable changed. Fix: treat each material scope change as a new research task. Search PRs, issues, and discussions with approach-specific terms (not just problem-domain terms).
660660
<!-- lore:019c8c17-f5de-71f2-93b5-c78231e29519 -->
661661
* **Make Bun.which testable by accepting optional PATH parameter**: When wrapping \`Bun.which()\` in a helper function, accept an optional \`pathEnv?: string\` parameter and pass it as \`{ PATH: pathEnv }\` to \`Bun.which\`. This makes the function deterministically testable without mocking — tests can pass a controlled PATH (e.g., \`/nonexistent\` for false, \`dirname(Bun.which('bash'))\` for true). Pattern: \`const opts = pathEnv !== undefined ? { PATH: pathEnv } : undefined; return Bun.which(name, opts) !== null;\`
662662
<!-- lore:019c8a8a-64ee-703c-8c1e-ed32ae8a90a7 -->
663-
* **PR review workflow: reply, resolve, amend, force-push**: When addressing PR review comments on this project: (1) Read unresolved threads via GraphQL API, (2) Make code changes addressing all feedback, (3) Run lint+typecheck+tests to verify, (4) Create a SEPARATE commit for each review round (not amend) — this enables incremental review, (5) Push normally (not force-push), (6) Reply to each review comment via REST API explaining what changed, (7) Resolve threads via GraphQL \`resolveReviewThread\` mutation using thread node IDs. Only amend+force-push when: (a) user explicitly asks, or (b) pre-commit hook auto-modified files that need including in the same commit.
663+
* **PR review workflow: reply, resolve, amend, force-push**: PR review workflow: (1) Read unresolved threads via GraphQL, (2) make code changes, (3) run lint+typecheck+tests, (4) create a SEPARATE commit per review round (not amend) for incremental review, (5) push normally, (6) reply to comments via REST API, (7) resolve threads via GraphQL \`resolveReviewThread\`. Only amend+force-push when user explicitly asks or pre-commit hook modified files.
664+
<!-- lore:019caf37-20cb-7a17-bd5f-eadb27ea350a -->
665+
* **Re-run prior art search when task scope pivots**: When a conversation pivots from one approach to another, always run a fresh prior-art search with keywords specific to the new scope. The failure mode: anchoring on the original framing's keywords and never re-searching. Simple searches like \`gh pr list --search "embed"\` would have surfaced a near-identical open PR. Treat each material scope change as a new research task.
664666
<!-- lore:019c90f5-9140-75d0-a59d-05b70b085561 -->
665667
* **Multi-target concurrent progress needs per-target delta tracking**: When multiple targets fetch concurrently and each reports cumulative progress, maintain a \`prevFetched\` array and \`totalFetched\` running sum. Each callback computes \`delta = fetched - prevFetched\[i]\`, adds to total. This prevents display jumps and double-counting. Use \`totalFetched += delta\` (O(1)), not \`reduce()\` on every callback.
666668
<!-- lore:019c90f5-913b-7995-8bac-84289cf5d6d9 -->

0 commit comments

Comments
 (0)