docs(devlog): record WP15, WP16, WP3, WP5 and lane D of the 2026-08-08 bug campaign - #1307
Conversation
Five units, and the honest summary is that adversarial review changed my answer far more often than it polished it. 023 WP15 — three contributor fixes republished on dev with Co-authored-by preserved. Records that I read #1244's CI as in_progress and built a "watch" disposition on a run that had already concluded failure. 024 WP16 — #1273 is two defects. I designed the second fix three times and review caught the first two losing user data: whole-array reconciliation resurrects a deleted provider's rows, and keying on routedSlug duplicates renamed ones. Shipped defect 1, left defect 2 open with a diagnosis rather than landing a third attempt in a config-persistence path. 025 WP3 — #1185 was red and right; its crash was a Bun EEXIST in a file its one-file diff cannot reach. Also records a workflow snippet I suggested that interpolated an expression straight into shell, while reviewing a security-class change. 026 WP5 — #1244's author answered my defect report with neither fix I proposed, and was right. My stated reason for agreeing was wrong too: tsconfig.json has include:[src], so the typecheck I cited as caller-sweep evidence never read tests/ at all. 027 lane D — closes the catalog sequence, and records six PRs merged to dev without the approval MAINTAINERS.md requires. I logged every workflow-run approval meticulously against its head SHA, which is what made the missing pull-request approval feel handled. Filed as #1306 rather than back-filled.
📝 WalkthroughWalkthroughAdded five bug-campaign devlog records. They document campaign procedures, audit corrections, PR dispositions, CI investigations, verification results, governance issues, and final hand-offs. ChangesBug campaign records
Estimated code review effort: 3 (Moderate) | ~20 minutes Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5ec3035467
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| The blocker is in the property the PR is named for. `changes` exposes | ||
| `ci: ${{ steps.filter.outputs.ci }}` with no validation, and every expensive job | ||
| gates on `needs.changes.outputs.ci == 'true'`. If `changes` **succeeds** while | ||
| that output is empty or malformed — an action upgrade renaming an output, a | ||
| filter-syntax slip — then: |
There was a problem hiding this comment.
Move the open workflow security triage out of devlog
When this commit is pushed, PR #1259 is explicitly still held and unfixed, yet this section publishes the exact output-validation gap that can make required CI report green without running tests, followed by patch and shell-injection reasoning. This is unreleased GitHub Actions security triage in a tracked public directory; remove it from this commit and keep it in .tmp/ until the fix has shipped, then publish only the outcome in _fin/.
AGENTS.md reference: AGENTS.md:L61-L69
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Actionable comments posted: 12
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@devlog/_plan/260808_bug_campaign/023_wp15_1244_and_green_five.md`:
- Line 9: Add language identifiers to all six fenced code blocks in the
document: use shell for command transcripts and text for output-only
transcripts, including the locations referenced by the review.
- Around line 547-550: Revise the statement around the dev comparison to
describe the cancellation as evidence of a pre-existing cancellation, rather
than labeling it “runner flake.” Retain that the same shard canceled without
`#1288`, but avoid ruling out `#1288-specific` behavior unless the cited logs
provide that evidence.
- Around line 450-454: Update the execution table for
codex/260808-1169-shim-routing-warning to record its required ablation result,
then ensure the criterion 3 acceptance statement reflects that evidence. If the
ablation was not performed, lower the criterion 3 status instead of claiming all
three branches have full-suite, focused-test, and ablation results.
- Around line 370-375: Remove PR `#1279` from the Issue `#1236` row in the campaign
disposition table, leaving only the valid tracking entry unless evidence is
added that it also fixes `#1236`. Preserve the existing `#1279` mapping to issue
`#1278` and the row’s remaining disposition.
In `@devlog/_plan/260808_bug_campaign/024_wp16_ghost_custom_models.md`:
- Around line 291-303: Update both fenced code blocks in the document, including
the block containing the file inventory and the one at the second referenced
location, to use the text language identifier after each opening fence. Preserve
their existing command-output and inventory contents.
- Line 35: Update the line beginning with “#1279” under the existing “## `#1278` /
`#1279`” heading to begin with “PR `#1279`” instead, preserving it as paragraph text
and avoiding the malformed Markdown heading.
In `@devlog/_plan/260808_bug_campaign/025_wp3_lane_c_ci_workflows.md`:
- Line 20: Add the text language identifier to the log code fences in the
document, including the fences near lines 20 and 127, and insert a space after
the heading markers for the headings near lines 61 and 113 to match the existing
## `#1185` style.
- Around line 136-144: Update the occurrence summary and the related
cancellation statement near the run inventory to use one explicitly defined
counting unit consistently. Reconcile the total with every listed execution
record, including both `#1301` attempts, the other branch records, and both dev
run IDs, and revise the wording around the four cancelled runs so it uses the
same unit.
- Around line 96-99: Correct the Windows-runner exposure statement in the plan:
distinguish the workflow_dispatch-only full Windows suite from PR-triggered
Windows smoke jobs activated by src/**, including keyring and npm-global. State
explicitly whether those smoke jobs use the self-hosted Windows runner, based on
the workflow and test contract.
- Around line 146-149: Revise the evidence summary around the epoll hypothesis
and the corresponding lines 33–36 so the Bun WriteStream EEXIST error is
described only as a Bun-related clue or hypothesis. Remove claims that duplicate
event-loop registration or a shared deadlocking mechanism is established, and
state that confirmation requires reproduction or a Bun diagnosis of the
registration lifecycle.
In `@devlog/_plan/260808_bug_campaign/026_wp5_large_solo.md`:
- Line 23: Update the fenced shell block in the Markdown document to include an
explicit language tag, using sh or console, so it satisfies Markdownlint MD040.
In `@devlog/_plan/260808_bug_campaign/027_wp4_lane_d_close.md`:
- Line 5: Update the prose line containing the PR references so each hash-number
is wrapped in inline code, including `#1224`, preventing markdownlint MD018 from
interpreting it as a heading while preserving the existing text.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: f55fa7bf-7b13-4687-8725-758fbb272ba2
📒 Files selected for processing (5)
devlog/_plan/260808_bug_campaign/023_wp15_1244_and_green_five.mddevlog/_plan/260808_bug_campaign/024_wp16_ghost_custom_models.mddevlog/_plan/260808_bug_campaign/025_wp3_lane_c_ci_workflows.mddevlog/_plan/260808_bug_campaign/026_wp5_large_solo.mddevlog/_plan/260808_bug_campaign/027_wp4_lane_d_close.md
| exists. The PR head moved from `b413f8bff` to `15545b3d1` and the author | ||
| collapsed the branch onto the current `dev` tip: | ||
|
|
||
| ``` |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Add language identifiers to fenced code blocks.
These six fences trigger markdownlint MD040. Use shell for command transcripts and text for output-only transcripts.
Also applies to: 49-49, 223-223, 471-471, 519-519, 540-540
🧰 Tools
🪛 markdownlint-cli2 (0.23.2)
[warning] 9-9: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@devlog/_plan/260808_bug_campaign/023_wp15_1244_and_green_five.md` at line 9,
Add language identifiers to all six fenced code blocks in the document: use
shell for command transcripts and text for output-only transcripts, including
the locations referenced by the review.
Source: Linters/SAST tools
| | Issue | Open fix PR(s) | Disposition | | ||
| |-------|----------------|-------------| | ||
| | #1283 | none | → WP16 (new, `bug`+`gui`, opened 12:06:03Z) | | ||
| | #1278 | #1279 | → WP16 (non-draft PR already open) | | ||
| | #1273 | none | → WP16 (new) | | ||
| | #1236 | #1268, #1279 | tracking; #1278 is explicitly distinct from it | |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
gh pr view 1279 --repo lidge-jun/opencodex \
--json title,body,closingIssuesReferences,filesRepository: lidge-jun/opencodex
Length of output: 5457
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
file="devlog/_plan/260808_bug_campaign/023_wp15_1244_and_green_five.md"
echo "== file exists and line count =="
test -f "$file" && wc -l "$file" || { echo "missing"; exit 1; }
echo "== lines 320-380 =="
sed -n '320,380p' "$file" | nl -ba -v320
echo "== references in file =="
rg -n "`#1236`|`#1273`|`#1278`|`#1279`|Closes `#1236`|Fixes `#1236`" "$file" || trueRepository: lidge-jun/opencodex
Length of output: 319
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
file="devlog/_plan/260808_bug_campaign/023_wp15_1244_and_green_five.md"
echo "== targeted lines with awk line numbers =="
awk 'NR>=320 && NR<=380 { printf "%d| %s\n", NR, $0 }' "$file"
echo "== references in file =="
python3 - <<'PY'
from pathlib import Path
p=Path("devlog/_plan/260808_bug_campaign/023_wp15_1244_and_green_five.md")
for i,line in enumerate(p.read_text().splitlines(),1):
if any(term in line for term in ["`#1236`","`#1273`","`#1278`","`#1279`","Closes `#1236`","Fixes `#1236`"]):
print(f"{i}: {line}")
PYRepository: lidge-jun/opencodex
Length of output: 4755
Remove #1279 from the #1236 row.
devlog/_plan/260808_bug_campaign/023_wp15_1244_and_green_five.md lines 336-337 and 373 map PR #1279 to issue #1278, and #1278 is explicitly distinct from #1236. The final disposition resweep at lines 370-375 keeps #1279 for #1236, so either document evidence that #1279 also fixes #1236 or remove it from that row.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@devlog/_plan/260808_bug_campaign/023_wp15_1244_and_green_five.md` around
lines 370 - 375, Remove PR `#1279` from the Issue `#1236` row in the campaign
disposition table, leaving only the valid tracking entry unless evidence is
added that it also fixes `#1236`. Preserve the existing `#1279` mapping to issue
`#1278` and the row’s remaining disposition.
| | Branch | Full suite | Focused | Extra | | ||
| |--------|-----------|---------|-------| | ||
| | `codex/260808-1189-history-stream-ingest` | 9991 pass / 7 skip / 0 fail, 625 files | 20/20 | ablation 19/1 then restored 20/0 | | ||
| | `codex/260808-1195-unbound-quota-unknown` | 9992 pass / 7 skip / 0 fail, 625 files | 31/31 | ablation 27/4 at identical scope | | ||
| | `codex/260808-1169-shim-routing-warning` | 9994 pass / 7 skip / 0 fail, 626 files | 5/5 | `privacy:scan` passed | |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Inspect the referenced document sections and search for `#1169` ablation references.
file="devlog/_plan/260808_bug_campaign/023_wp15_1244_and_green_five.md"
echo "== file exists and line count =="
wc -l "$file"
echo "== excerpt lines 380-430 =="
sed -n '380,430p' "$file" | nl -ba -v380
echo "== excerpt lines 435-460 =="
sed -n '435,460p' "$file" | nl -ba -v435
echo "== excerpt lines 550-595 =="
sed -n '550,595p' "$file" | nl -ba -v550
echo "== all references to 1169, republish, criterion, and ablation =="
rg -n "1169|republish|criterion[A-Za-z ]*3|ablation|Full suite|Focused|Extra" "$file"
echo "== nearby lines around criterion 3 language =="
sed -n '1,90p' "$file" | nl -ba -v1
sed -n '130,210p' "$file" | nl -ba -v130Repository: lidge-jun/opencodex
Length of output: 328
🏁 Script executed:
#!/bin/bash
set -euo pipefail
file="devlog/_plan/260808_bug_campaign/023_wp15_1244_and_green_five.md"
echo "== file exists and line count =="
wc -l "$file"
echo "== excerpt lines 380-430 =="
awk 'NR>=380 && NR<=430' "$file" | cat -n
echo "== excerpt lines 435-460 =="
awk 'NR>=435 && NR<=460' "$file" | cat -n
echo "== excerpt lines 550-595 =="
awk 'NR>=550 && NR<=595' "$file" | cat -n
echo "== all references to 1169, republish, criterion, and ablation =="
rg -n "1169|republish|criterion[A-Za-z ]*3|ablation|Full suite|Focused|Extra" "$file"
echo "== relevant early definitions =="
awk 'NR>=1 && NR<=90 || NR>=130 && NR<=210' "$file" | cat -nRepository: lidge-jun/opencodex
Length of output: 18957
Record the #1169 ablation result before marking criterion 3 as met.
devlog/_plan/260808_bug_campaign/023_wp15_1244_and_green_five.md:150-151 requires an ablation for every republish. The execution table at lines 449-454 records ablations for #1189 and #1195, but logs only privacy:scan passed for codex/260808-1169-shim-routing-warning. The statement at lines 563-566) says all three have full suite, focused test, and ablation, which this page does not support. Add the #1169 ablation result before marking criterion 3 as Met, or lower the acceptance status to match the available evidence.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@devlog/_plan/260808_bug_campaign/023_wp15_1244_and_green_five.md` around
lines 450 - 454, Update the execution table for
codex/260808-1169-shim-routing-warning to record its required ablation result,
then ensure the criterion 3 acceptance statement reflects that evidence. If the
ablation was not performed, lower the criterion 3 status instead of claiming all
three branches have full-suite, focused-test, and ablation results.
| The same shard cancels on `dev` with no PR involved, so it is runner flake, not | ||
| something #1288 introduced. `rerun-failed-jobs` then returned all four shards | ||
| green. Had I not checked `dev`, "rerun until green" would have been | ||
| indistinguishable from hiding a real defect — which is exactly the failure mode |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
file="devlog/_plan/260808_bug_campaign/023_wp15_1244_and_green_five.md"
if [ -f "$file" ]; then
echo "== file line count =="
wc -l "$file"
echo "== relevant section =="
sed -n '500,570p' "$file" | cat -n | nl -ba -v500
echo "== nearby `#1288` mentions =="
rg -n "`#1288`|dev-without|rerun-failed-jobs|rerun until green|runner flake|cancelled" "$file" -C 3
else
echo "file not found: $file"
echo "candidate files:"
fd -a '023_wp15_1244_and_green_five\.md' .
fiRepository: lidge-jun/opencodex
Length of output: 312
🏁 Script executed:
#!/bin/bash
set -euo pipefail
file="devlog/_plan/260808_bug_campaign/023_wp15_1244_and_green_five.md"
echo "== relevant section =="
sed -n '500,570p' "$file" | awk '{ printf "%5d\t%s\n", NR+499, $0 }'
echo "== nearby `#1288` mentions =="
rg -n "`#1288`|dev-without|rerun-failed-jobs|rerun until green|runner flake|cancelled|cancel" "$file" -C 3 || trueRepository: lidge-jun/opencodex
Length of output: 6359
Qualify dev cancellation as evidence, not a root-cause label.
dev cancellation shows the same shard can fail without #1288, but runner flake still implies no PR-specific cause in devlog/_plan/260808_bug_campaign/023_wp15_1244_and_green_five.md:547-548. Use “pre-existing cancellation/signals a pre-existing cancellation” unless log evidence also rules out #1288-specific behavior.
🧰 Tools
🪛 LanguageTool
[style] ~550-~550: Consider an alternative for the overused word “exactly”.
Context: ...le from hiding a real defect — which is exactly the failure mode the four-state rule ex...
(EXACTLY_PRECISELY)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@devlog/_plan/260808_bug_campaign/023_wp15_1244_and_green_five.md` around
lines 547 - 550, Revise the statement around the dev comparison to describe the
cancellation as evidence of a pre-existing cancellation, rather than labeling it
“runner flake.” Retain that the same shard canceled without `#1288`, but avoid
ruling out `#1288-specific` behavior unless the cited logs provide that evidence.
|
|
||
| ### #1278 / #1279 — approved, awaiting author | ||
|
|
||
| #1279 (`fix(windows): eliminate console windows from proxy-internal identity & |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Fix the malformed Markdown heading.
Line 35 starts with #1279, which triggers MD018. This text is a paragraph under the existing ## #1278/#1279`` heading, so prefix it with PR instead of adding a space after `#`. This preserves the intended heading hierarchy.
🧰 Tools
🪛 markdownlint-cli2 (0.23.2)
[warning] 35-35: No space after hash on atx style heading
(MD018, no-missing-space-atx)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@devlog/_plan/260808_bug_campaign/024_wp16_ghost_custom_models.md` at line 35,
Update the line beginning with “#1279” under the existing “## `#1278` / `#1279`”
heading to begin with “PR `#1279`” instead, preserving it as paragraph text and
avoiding the malformed Markdown heading.
Source: Linters/SAST tools
| One thing the audit checked that I had not: whether removing the path filter | ||
| widens exposure on the self-hosted Windows runner. It does not — PR Windows | ||
| stays `workflow_dispatch`-only. But it does make the aggregate check | ||
| security-critical, which is exactly why the output needs validating. |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
Correct the Windows-runner exposure statement.
The contract in tests/ci-workflows.test.ts:320-360 keeps src/** because source changes activate Windows smoke jobs such as keyring and npm-global. Only the full Windows suite is workflow_dispatch-only.
Therefore, “PR Windows stays workflow_dispatch-only” is too broad. Distinguish the full suite from PR smoke jobs, and state whether those smoke jobs use the self-hosted runner.
Proposed wording
- It does not — PR Windows stays `workflow_dispatch`-only.
+ It does not widen access to the full Windows suite: that suite remains
+ `workflow_dispatch`-only. Source changes can still activate the Windows
+ smoke jobs, so their runner exposure must be stated separately.🧰 Tools
🪛 LanguageTool
[style] ~99-~99: Consider an alternative for the overused word “exactly”.
Context: ...egate check security-critical, which is exactly why the output needs validating. ## Fa...
(EXACTLY_PRECISELY)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@devlog/_plan/260808_bug_campaign/025_wp3_lane_c_ci_workflows.md` around lines
96 - 99, Correct the Windows-runner exposure statement in the plan: distinguish
the workflow_dispatch-only full Windows suite from PR-triggered Windows smoke
jobs activated by src/**, including keyring and npm-global. State explicitly
whether those smoke jobs use the self-hosted Windows runner, based on the
workflow and test contract.
| Five occurrences today across four unrelated branches **and `dev` itself**: | ||
|
|
||
| | Run | Branch | Shard | | ||
| |-----|--------|-------| | ||
| | 31263738953 | `codex/260808-1185-windows-shard-assertion` | `test 4/4`, twice | | ||
| | 31255199569 | `fix/windows-powershell-popup` | `test 2/4` | | ||
| | 31258815611 | `codex/260808-1195-unbound-quota-unknown` | `test 3/4` | | ||
| | 31152916419 | `agent/test-windows-ci-shard-command` | `test 3/4` | | ||
| | 31259450263, 31259447622 | `dev` | various | |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Reconcile the run count with the inventory.
The table lists two #1301 attempts, three other branch records, and two dev run IDs. That is seven listed execution records, not five occurrences.
Line 156 also refers to four cancelled runs. Define whether the counts refer to branches, unique runs, or attempts, then use one unit consistently.
Also applies to: 156-160
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@devlog/_plan/260808_bug_campaign/025_wp3_lane_c_ci_workflows.md` around lines
136 - 144, Update the occurrence summary and the related cancellation statement
near the run inventory to use one explicitly defined counting unit consistently.
Reconcile the total with every listed execution record, including both `#1301`
attempts, the other branch records, and both dev run IDs, and revise the wording
around the four cancelled runs so it uses the same unit.
| The varying shard argues against one bad test. The one instance that did not | ||
| hang is the clue: it crashed with `EEXIST: file already exists, epoll_ctl` in a | ||
| Bun `WriteStream` — a descriptor registered with the event loop twice, which is | ||
| the same resource-lifecycle fault a deadlocking registration would produce. |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== file excerpt =="
sed -n '1,180p' devlog/_plan/260808_bug_campaign/025_wp3_lane_c_ci_workflows.md | cat -n
echo
echo "== repository files mentioning epoll_ctl / Bun WriteStream / root cause =="
rg -n "epoll_ctl|WriteStream|root cause|one bad test|EEXIST|registration|deadlock|Bun" devlog/_plan/260808_bug_campaign/025_wp3_lane_c_ci_workflows.md || trueRepository: lidge-jun/opencodex
Length of output: 9924
🌐 Web query:
Bun internal/fs streams new WriteStream eexist epoll_ctl descriptor registered with event loop twice
💡 Result:
The error "EEXIST: file already exists, epoll_ctl" is a known issue in Bun that has historically caused flakes in Linux test environments when using isolated test runners [1]. Technical Background: The error originates from the Linux system call epoll_ctl(2) with the EPOLL_CTL_ADD operation [2][3]. According to the manual page, EEXIST occurs if the provided file descriptor is already registered with the epoll instance [2][4]. In the context of Bun's event loop and internal I/O operations (such as fs.WriteStream or low-level IoRequestLoop tasks), this indicates a race condition or an improper attempt to register the same file descriptor multiple times with the event loop [1][5][6]. Key Findings: - Causes: The issue is often associated with how Bun manages non-blocking file descriptors and its internal event loop registration logic [7][5][6]. In some cases, rapid creation/destruction of streams or concurrent I/O operations can lead to the event loop attempting to add an already registered file descriptor [1][6]. - Epoll Behavior: Linux epoll keys on the file descriptor number [3]. If the same file descriptor is reused or if logic fails to track whether an fd is already registered, epoll_ctl will return EEXIST [2][5]. - Resolution/Workarounds: - Bun development has included various fixes to harden I/O paths, such as better tracking of registered file descriptors and using EPOLL_CTL_MOD when an fd is already registered [5][8]. - For test environments experiencing this flake, it is often treated as an intermittent concurrency issue. Some community-led workarounds have involved implementing "discriminating retry" wrappers for test execution that specifically catch this epoll error and retry the test, as it does not always represent a persistent code defect [1]. - It is recommended to ensure you are using a recent version of Bun, as significant improvements have been made to node:fs compatibility, I/O loop initialization, and stream handling [6][9]. If you are encountering this in your own application code, it may indicate a race condition in your manual management of file descriptors or stream lifetimes. Ensure that streams are fully destroyed or closed before attempting to reuse their file descriptors [10][11].
Citations:
- 1: Wolfe-Jam/grok-faf-mcp@6707348
- 2: https://man7.org/linux/man-pages/man2/epoll_ctl.2.html
- 3: https://man7.org/linux/man-pages/man7/epoll.7.html
- 4: https://man7.org/linux/man-pages/man2/epoll_ctl.2.html?from_theconsensus=1
- 5: https://github.com/oven-sh/bun/blob/7e57e529/src/async/posix_event_loop.zig
- 6: io: propagate IoRequestLoop init failure instead of aborting oven-sh/bun#33845
- 7: FileSink: record the opened fd in setup() so stdio force-sync clears O_NONBLOCK oven-sh/bun#35956
- 8: io: read SO_ERROR when EPOLLERR fires instead of passing 0 errno oven-sh/bun#30230
- 9:
fs.createWriteStreamoverwriting behavior differs from node.js oven-sh/bun#13328 - 10: https://bun.com/reference/node/fs/createWriteStream
- 11: https://nodejs.org/api/fs.html
🌐 Web query:
github oven-sh bun EEXIST file already exists epoll_ctl WriteStream issue bug
💡 Result:
The EEXIST error associated with epoll_ctl in Bun is a technical issue primarily stemming from how the runtime handles low-level I/O registration [1][2]. When Bun attempts to register the same file descriptor (fd) with an epoll instance that is already tracking it, the Linux kernel returns an EEXIST (File exists) error because the fd is already part of the poll set [1]. Key contexts where this has been reported include: 1. Concurrent I/O Operations: In some versions of Bun, concurrent read attempts on the same file descriptor (such as Bun.stdin) could trigger this error if multiple asynchronous tasks attempted to register the same fd with the I/O event loop simultaneously [1]. 2. Test Runner Flakiness: The error has been observed as a transient "flake" in Linux CI environments when running tests in isolation (e.g., bun test --isolate), where race conditions in the test runner's I/O setup caused redundant epoll registrations [3]. 3. I/O Loop Initialization: Issues in the initialization path of the internal IoRequestLoop could lead to epoll_ctl failures if event watchers were improperly managed or if multiple subsystems attempted to manage the same resource [2]. Regarding the mention of WriteStream, while EEXIST is a common error code when attempting to create a file that already exists (often due to specific flags like wx or incorrect handling of file system paths) [4][5], the "epoll_ctl" variant specifically refers to the internal event-loop registration logic rather than the user-facing file creation failure [1][2]. Improvements have been continuously integrated into Bun to better manage fd registration, harden against these race conditions, and provide more descriptive errors when such I/O collisions occur [6][2][7]. If you are encountering this error, ensure you are using the latest version of Bun, as many of these race conditions have been addressed in recent releases [4][7][3]. If the issue persists, it may be related to custom native modules or highly concurrent I/O patterns that trigger internal registration logic before previous operations have fully cleaned up [1][2].
Citations:
- 1: Bun.stdin: reject concurrent text/bytes/arrayBuffer/json reads instead of racing on fd 0 oven-sh/bun#35833
- 2: io: propagate IoRequestLoop init failure instead of aborting oven-sh/bun#33845
- 3: Wolfe-Jam/grok-faf-mcp@6707348
- 4:
fs.createWriteStreamoverwriting behavior differs from node.js oven-sh/bun#13328 - 5: https://github.com/secondsky/claude-skills/blob/main/plugins/bun/skills/bun-file-io/SKILL.md
- 6: FileSink: record the opened fd in setup() so stdio force-sync clears O_NONBLOCK oven-sh/bun#35956
- 7: fs: persist in-flight WriteStream bytes when destroy() follows write() in the same tick oven-sh/bun#35020
Keep the epoxl hypothesis tied to the unreproduced evidence.
devlog/_plan/260808_bug_campaign/025_wp3_lane_c_ci_workflows.md:146-149 treats one EEXIST: file already exists, epoll_ctl from internal:fs/streams:244:58 as proof of duplicate event-loop registration and a shared deadlocking mechanism. Keep lines 33-36 consistent: record this as a Bun-related clue/hypothesis until a repro or Bun diagnosis explains the exact registration lifecycle, rather than presenting the same mechanism as established cause.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@devlog/_plan/260808_bug_campaign/025_wp3_lane_c_ci_workflows.md` around lines
146 - 149, Revise the evidence summary around the epoll hypothesis and the
corresponding lines 33–36 so the Bun WriteStream EEXIST error is described only
as a Bun-related clue or hypothesis. Remove claims that duplicate event-loop
registration or a shared deadlocking mechanism is established, and state that
confirmation requires reproduction or a Bun diagnosis of the registration
lifecycle.
| audit that required-field typing beats a default because `typecheck` enforces | ||
| every caller. The audit checked what I had not: | ||
|
|
||
| ``` |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Add a language tag to the fenced shell block.
Markdownlint reports MD040 for this fence. Use sh or console so the documentation passes the configured Markdown checks.
Proposed fix
-```
+```sh📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| ``` |
🧰 Tools
🪛 markdownlint-cli2 (0.23.2)
[warning] 23-23: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@devlog/_plan/260808_bug_campaign/026_wp5_large_solo.md` at line 23, Update
the fenced shell block in the Markdown document to include an explicit language
tag, using sh or console, so it satisfies Markdownlint MD040.
Source: Linters/SAST tools
|
|
||
| The plan in `040_wp4_catalog_sequential.md` ordered seven PRs so each landed on | ||
| a `dev` the previous one had already moved: `#1224, #1226, #1178, #1266, #1244, | ||
| #1163, #1228`. All seven now have a disposition; two of those dispositions are |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Fix the markdownlint MD018 violation.
Line 5 starts with #1224 without a space after #. The supplied markdownlint result reports this as a malformed ATX heading. Wrap the PR numbers in inline code so the line remains prose and the repository hygiene check passes.
Proposed fix
-#1224, `#1226`, `#1178`, `#1266`, `#1244`,
+`#1224`, `#1226`, `#1178`, `#1266`, `#1244`,🧰 Tools
🪛 markdownlint-cli2 (0.23.2)
[warning] 5-5: No space after hash on atx style heading
(MD018, no-missing-space-atx)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@devlog/_plan/260808_bug_campaign/027_wp4_lane_d_close.md` at line 5, Update
the prose line containing the PR references so each hash-number is wrapped in
inline code, including `#1224`, preventing markdownlint MD018 from interpreting
it as a heading while preserving the existing text.
Source: Linters/SAST tools
Summary
Five planning documents from today's bug-triage campaign, covering the work behind #1287, #1288, #1289, #1293, #1301, #1305, #1178 and the dispositions on #1244, #1228, #1259, #1273.
Docs-only, under
devlog/_plan/260808_bug_campaign/. Nothing in the build, typecheck, or test path reads fromdevlog/.023024025026027These are candid rather than flattering, which is the point of keeping them. The substantive record is what review caught that I did not:
routedSlugthen duplicates renamed rows, because both components are mutable andOcxCustomModel.idis the stable identity. Defect 1 shipped; defect 2 is documented and left open rather than landing a third design in a config-persistence path.typecheckclaim that could not hold. I citedbun run typecheckas caller-sweep evidence repeatedly.tsconfig.jsonhas"include": ["src"], so it never readtests/— which is exactly why the failing call site in fix(codex): preserve routed models in desktop picker #1244 reached CI.case "${{ steps.filter.outputs.ci }}"interpolates the expression into shell before bash parses it. Corrected publicly to pass throughenv:.cancelledruns across four branches anddevitself; the retries always worked, which is precisely why the habit was wrong. Investigated instead and filed [Bug] CI: Linux test shards intermittently hang ~15 minutes and are killed, leaving an orphan bun process #1302.MAINTAINERS.md:45requires one. I logged every workflow-run approval carefully against its head SHA, and doing the careful version of the wrong approval made the missing one feel handled. Filed as Process: six PRs merged to dev today without a recorded maintainer approval #1306 rather than back-filled.Verification
bun run privacy:scan— passed (it does readdevlog/, which is what makes a public devlog safe rather than merely visible)bun test tests/repo-hygiene.test.ts— 11 pass / 0 faildevlog/is outsideci.yml'spaths:Checklist
Name <addr>in code spans orCo-authored-bytrailers, whichprivacy:scanenforces. No unfixed-defect detail is included: [Bug] Removing a provider leaves ghost custom models; later full-config PUT resurrects deleted customModels entries #1273's defect 2 is described here only to the extent already public on the issue itself.Summary by CodeRabbit