Skip to content

🤖 perf: keep toolDefinitions out of the main chunk and pin the Node 22.23.4 sandbox image - #7369

Merged
ibetitsmike merged 2 commits into
mainfrom
mike/bugbash-sandbox-image-node-22.23.4
Oct 23, 2026
Merged

ibetitsmike merged 2 commits into
mainfrom
mike/bugbash-sandbox-image-node-22.23.4

Conversation

@ibetitsmike

@ibetitsmike ibetitsmike commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Summary

This PR fixes the two problems that keep main red, in one PR, because each fix fails CI without the other. The first commit is Thomas's fix from #7364 (cherry-picked, his authorship kept). It moves the ask_user_question argument schemas out of toolDefinitions.ts, so the renderer entry chunk no longer pulls in every tool schema and rendererFirstLoad.test.ts passes again. The second commit pins the bug-bash sandbox image that main published from #7362 (base node:22.23.4-slim, the CVE-2026-111497 fix), so the model-driven story jobs run again on main and in the merge queue. Fixes #7363.

Background

So #7364 alone fails the story jobs, and the pin alone fails the unit test. The queue groups entries with ALLGREEN, so neither can merge first. This PR carries both.

Implementation

Field Value
digest sha256:e3804b5418a8e6783698d807c75cc256efae45b81b03400644ae7f13364c9a03
inputsKey 2bf9e12d3ac7dcb10397698df2792bf1b244b3fcbe68225378302ef695ba302a, what make -s bugbash-sandbox-key prints on this commit
playwrightCore 1.63.0 (unchanged)
publishedFrom 2e2a2b769f417aedcecc09f33abb379d6c8be7b1 (main, the #7362 merge)

Validation

  • rendererFirstLoad.test.ts fails on the pin commit alone (21f9c3f) and passes with the cherry-pick.
  • Publish run on main: 40016150145, from 2e2a2b769f. The digest is the subject of its build provenance attestation.
  • gh attestation verify oci://ghcr.io/coder/xum-bugbash-sandbox@sha256:e3804b54… --repo coder/xum passes. The signer is .github/workflows/bugbash-sandbox-image.yml@refs/heads/main (workflow_dispatch, run 40016150145), and the source commit is 2e2a2b769f.
  • I pulled the image by digest. It is linux/amd64, its org.xum.bugbash.inputs label is 2bf9e12d…a302a, its org.xum.bugbash.playwright-core label is 1.63.0, and node -v in it prints v22.23.4.

Co-authored-by: Thomas Kosiewski tk@coder.com

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-23T21:59:40.155577Z 2741561 Manual request
🔒 Security Review ✅ Completed 2026-10-23T22:01:39.608427Z 2741561 Manual request
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@github-actions

github-actions Bot commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

🟢 e2e stories (Haiku): 14 passed

27 agent steps · 7 replayed from cache · 32 model calls · 230.1k tokens (71% cached)
Spend: $0.10 of the $1.00 cap (proxy ledger)

All 14 tests in 9 files
Test Agent Time
🟢 chatRestart.e2e.ts · 1 passed 2 steps · 5 calls 27.9s
🟢 a chat survives a restart of the server 2 steps · 5 calls 27.9s
🟢 compaction.e2e.ts · 1 passed 3 steps · 7 calls 50.7s
🟢 /compact replaces the old chat with a summary 3 steps · 7 calls 50.7s
🟢 pluginTrustRestart.e2e.ts · 1 passed 4 steps · 2 calls 9.6s
🟢 a trusted plugin hook stays trusted after the server restarts 4 steps · 2 calls 9.6s
🟢 settingsRoundTrip.e2e.ts · 1 passed 3 steps · 5 calls 30.3s
🟢 a chat survives trips through Settings 3 steps · 5 calls 30.3s
🟢 sidebarPerWorkspace.e2e.ts · 1 passed 4 steps · 1 call 4.4s
🟢 a new workspace starts with its right sidebar collapsed while another keeps it open 4 steps · 1 call 4.4s
🟢 smoke.e2e.ts · 1 passed 2 steps · 1 call 2.7s
🟢 the agent opens the playground workspace 2 steps · 1 call 2.7s
🟢 streamErrors.e2e.ts · 1 passed 1 step · 1 call 7.5s
🟢 stream errors show in the chat, and the chat recovers 1 step · 1 call 7.5s
🟢 todoNudge.e2e.ts · 1 passed 2 steps · 4 calls 24.4s
🟢 the agent finishes open TODO items after the turn-end nudge 2 steps · 4 calls 24.4s
🟢 touchAlignment.e2e.ts · 6 passed 6 steps · 6 calls 32.9s
🟢 the Settings close button is level with the title on a touch screen 390px wide 1 step · 1 call 3.6s
🟢 the Settings close button is level with the title on a touch screen 768px wide 1 step · 1 call 4.2s
🟢 Backup settings checkboxes are small and level with their labels on a touch phone 1 step · 1 call 7.9s
🟢 the heartbeat checkbox is small and level with its label on a touch phone 1 step · 1 call 3.7s
🟢 a reply's model and time stay on one line on a touch phone 1 step · 1 call 6.7s
🟢 the workspace actions menu stays on the title row on a touch phone 1 step · 1 call 6.8s

e2e 0.20.0 · 3m 14s · web · run artifacts

🟢 e2e Electron stories (Haiku): 3 passed

3 agent steps · 3 model calls · 8.1k tokens (21% cached)
Spend: $0.02 of the $1.00 cap (proxy ledger)

All 3 tests in 3 files
Test Agent Time
🟢 electron/deepLink.e2e.ts · 1 passed 1 step · 1 call 9.4s
🟢 a deep link of a second launch starts a chat in the running app 1 step · 1 call 9.4s
🟢 electron/menuBar.e2e.ts · 1 passed 1 step · 1 call 6.2s
🟢 the workspace menu bar is the desktop title bar 1 step · 1 call 6.2s
🟢 electron/smoke.e2e.ts · 1 passed 1 step · 1 call 6.2s
🟢 Xum Electron opens the playground workspace 1 step · 1 call 6.2s

e2e 0.20.0 · 24.3s · electron · run artifacts

🟢 e2e agent repros (Haiku): no tests selected

Spend: $0.00 of the $1.00 cap (proxy ledger)

e2e 0.20.0 · 6.6s · 2 targets (web, phone) · run artifacts

openAskUserQuestions.ts (eager via StreamingMessageAggregator) imported
TOOL_DEFINITIONS only to parse ask_user_question args, which put every
tool schema into main-*.js. Move the ask_user_question arg schemas to
askUserQuestionSchemas.ts (zod only); toolDefinitions re-exports them.

(cherry picked from commit fd6b719)
@ibetitsmike ibetitsmike changed the title 🤖 tests: pin the Node 22.23.4 bug-bash sandbox image 🤖 perf: keep toolDefinitions out of the main chunk and pin the Node 22.23.4 sandbox image Oct 23, 2026
@ibetitsmike

Copy link
Copy Markdown
Contributor Author

@codex review

This head adds Thomas's commit from #7364 (cherry-picked unchanged) to the image pin, so the PR fixes both of main's failures: the rendererFirstLoad unit test and the stale sandbox key.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Swish!

Reviewed commit: 2741561b20

ℹ️ 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".

@chatgpt-codex-connector

Copy link
Copy Markdown

🛡️ Codex Security Review · Automatically triggered

Security review completed. No security issues were found in this pull request.

Reviewed commit: 2741561b20

View security finding report

Only the user who started this review can view the report in Codex.

ℹ️ About Codex security reviews in GitHub

This is an experimental Codex feature. Security reviews are triggered when:

  • You comment "@codex security review"
  • A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review

Once complete, Codex will leave suggestions, or a comment if no findings are found.

@ibetitsmike
ibetitsmike added this pull request to the merge queue Oct 23, 2026
Merged via the queue into main with commit 2633118 Oct 23, 2026
38 checks passed
@ibetitsmike
ibetitsmike deleted the mike/bugbash-sandbox-image-node-22.23.4 branch October 23, 2026 22:19
azaj01 pushed a commit to azaj01/mux that referenced this pull request Oct 25, 2026
…through HostFiles, HostPaths and HostClock (coder#7371)

## Summary

5b PR 7 of phase 5 (Loop host I/O) of the agent-loop refactor. The
instruction readers and the home-clutter reminder reach the host through
the phase 5 and phase 3 services:

- `instructionFiles.ts` and `homeClutterWatch.ts` read files through
`HostFiles` (coder#7319).
- `systemMessage.ts` and `tools.ts` take the user home and the Xum home
from `HostPaths` (coder#7319).
- `HomeClutterReminderSource` arms its scan timeout on the session's
`HostClock` (phase 3).

The five files import no `fs`, `fs/promises` or `os` any more, and
`systemMessage.ts` no longer imports `getXumHome`. Behavior does not
change: the Node layers read the same `fs/promises` and `os` namespaces
and call `getXumHome` at each call, so the `os.homedir` spies of
`systemMessage.test.ts` and `instructionsService.test.ts` still apply.
None of the five files is in the `local/no-host-imports` file set, so
the frozen pairs do not change.

## Order

Plan order: stack 5b is PR 1 to PR 9, and this PR comes after 5b PR 6
(coder#7322, merged).

Landing order: this PR lands ahead of 5b PRs 2 to 5, by rule 2 of plan
note 1. Those PRs wait for phase 4 and phase 2 PRs that have not merged.
This PR waits only for 5a PR 5 (coder#7319, merged) and phase 3 PR 1 (coder#7270,
merged), and it uses no code of 5b PRs 2 to 5. So it opens on its own,
with base main. No open phase 2 to 5 PR changes these five files.

## Implementation

- `utils/main/instructionFiles.ts`: the local file reader calls
`nodeHostFiles.promises.readFile`.
- `runtime/homeClutterWatch.ts`: the default `readDir` calls
`nodeHostFiles.promises.readdir`.
- `services/systemMessage.ts`: the Claude-compat global dir comes from
`nodeHostPaths.userHome()`. The global instruction set, the settings
`config.json` path and its directory come from
`nodeHostPaths.xumHome()`.
- `agentNotifications/sources/HomeClutterReminderSource.ts`: the
constructor takes an optional `clock` (absent: `nodeClock`, as for tool
configs that tests build by hand). The scan timeout calls
`clock.setTimer`, and the scan start times come from `clock.nowMs()`.
- `common/utils/tools/tools.ts`: the reminder gets
`nodeHostPaths.userHome()` and `config.clock`.

The plan estimated about 320 lines for this PR. It adds 71 lines and
removes 21, because no caller passes its own `HostFiles` or `HostPaths`
yet (the same reason as in 5b PR 6).

## Validation

- `HomeClutterReminderSource.test.ts`: a new case runs a poll on a stuck
scan with the TestClock. The poll is still open at 249 ms of TestClock
time and ends at 250 ms, with no real wait. With the timer pointed back
at `nodeClock`, the case fails.
- The plan's tests (`instructionFiles`, `systemMessage`,
`instructionsService`, `homeClutterWatch`, `HomeClutterReminderSource`)
plus `tools.test.ts`: 135 pass, 0 fail.
- `make static-check`, `make lint-eslint`, `make dry-check`, `make
crap-check`.
- `make test` (host suite lock) on head c9af576: `bun test src` had
27679 pass, 7 skip and 1 fail. The fail is `renderer first load > the
entry's static imports do not reach the tool definitions module`, which
fails the same way on main 2e2a2b7 (I ran it there alone). `make
test` stops at the first failing run, so I ran its other steps by hand:
the shared scripts/storybook/vscode run (729 pass, 0 fail) and each of
the 18 isolated files (0 fail).
- The ui line on that head: 732 pass, 0 fail.
- Loop-test tripwire, 3 runs against origin/main 2e2a2b7: 0 trips.
- Round 2 (77a0664) merges main 2633118 (coder#7369, the fix for the
renderer first load test). On it: `make static-check`, and the plan's
tests plus `tools.test.ts` and `rendererFirstLoad.test.ts`: 138 pass, 0
fail.

---

_Generated with `xum` • Model: `anthropic:claude-opus-5-5` • Thinking:
`high` • Cost: `$112.49`_

<!-- mux-attribution: model=anthropic:claude-opus-5-5 thinking=high
costs=112.49 -->
@linear-code

linear-code Bot commented Oct 26, 2026

Copy link
Copy Markdown

MUX-410

yermakoffivan pushed a commit to yermakoffivan/mux that referenced this pull request Oct 27, 2026
…oder#7671)

## Summary

The "Bug-bash sandbox image" workflow now publishes the image by itself.
A push to main that changes an image input runs the publish job. The job
creates the image only if the key has none yet: each inputs key gets one
stable tag, `ghcr.io/coder/xum-bugbash-sandbox:inputs-<key>`. A key that
has its tag pushes nothing. This is PR 1 of 2. Runners still trust only
the digest in `image.json` until PR 2.

## Background

An image change takes four steps today, and two of them need a person.
coder#7362 changed the Dockerfile. Its story lanes refused the stale image,
so it needed an admin merge, and the merge queue then stayed red for 3.5
hours. After that, a maintainer ran the manual publish on main, and
coder#7369 pinned the new digest. Four images went through that process
between Oct 8 and Oct 23.

The plan, which the user approved: main publishes once per key with no
person (this PR). Then every sandbox job pulls `inputs-<key>`, checks
its build attestation (`gh attestation verify --source-ref
refs/heads/main`), and builds locally when there is no verified image
(PR 2). `image.json` and the `BUGBASH_SANDBOX_BUILD_STALE` opt-in go
away in PR 2.

## Implementation

1. **New trigger:** `push` to main, filtered to the image inputs
(`build.sh --key` hashes the Dockerfile, `build.sh` and the
playwright-core version in `bun.lock`) and to this workflow file. A
change to this file therefore publishes the current key once. `Makefile`
is not in the push filter. A Makefile change does not change the key,
and an existing key needs no publish.
2. **Create if missing:** the publish step looks up the stable tag with
`docker buildx imagetools inspect`. If the tag exists, the step writes
"exists" to the summary and stops. Only a `: not found` error counts as
missing. Any other lookup error fails the job. If the tag is missing,
the step runs the publish as before.
3. **Tag last:** Attest signs the new digest. Only then does a new step,
"Tag inputs-<key>", point the stable tag at it with `imagetools create
--prefer-index=false`. That flag copies the manifest as it is. The
default wraps a single manifest in a new index with a new, unsigned
digest. The step reads the tag's digest back and fails unless it equals
the signed digest. The stable tag marks the key as done, so a failed
Attest leaves no tag, and a re-run publishes again.
4. **No races:** the existing concurrency group runs one publish at a
time and never cancels it. A second push of the same key waits, then
finds the tag and stops.
5. **Docs:** AGENTS.md and the bug-bash skill now say that the merge
push publishes the image. A manual run on main retries a failed publish.

This PR does not change any image input, so the inputs key stays
`2bf9e12d…`, the key in `image.json`. No old-style publish is needed for
this PR.

## Validation

- I ran the step's lookup branch against GHCR with an empty Docker
config, with these results:
  - The current key's stable tag: `PUBLISH: … missing`.
  - An existing published tag: `SKIP: … exists`.
- An unreachable registry: `FAIL` with exit 1, and the DNS error
printed.
- I ran the "Tag inputs-<key>" step's script against a local registry,
with a single-platform Docker v2 manifest like the published image. It
kept the source digest. Without `--prefer-index=false`, the tag got a
different digest.
- `actionlint` 1.7.13: clean. `make lint-zizmor` and `make
static-check`: pass.
- After the merge, I will check two runs. The merge push must publish
`inputs-2bf9e12d3ac7dcb10397698df2792bf1b244b3fcbe68225378302ef695ba302a`.
Then a manual run on main must report "exists" and push nothing. I will
link both runs here.

## Risks

Low. Publishing stays main-only, from the run's own commit, with a fresh
build and an attestation. A new path is the one trigger: every
`bun.lock` change on main starts a run that ends after the lookup, at
about one minute of runner time each. A failed lookup fails the run and
pushes nothing.

<details>
<summary>Decisions in the approved plan</summary>

1. A job can build the image itself in CI and on a developer machine.
2. Only main pushes images, after a merge. The merge queue does not
push.
3. A job uses a registry image only if its attestation shows that main's
publish workflow built it. Otherwise it builds locally.
4. Two PRs: this publish change first, then the runner, `build.sh` and
docs.

</details>

---

_Generated with `xum` • Model: `anthropic:claude-opus-5-5` • Thinking:
`xhigh` • Cost: `$263.47`_

<!-- mux-attribution: model=anthropic:claude-opus-5-5 thinking=xhigh
costs=263.47 -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

perf: #6887 ask_user_question dock adds ~24 KB to the entry chunk and slows seeded load (TBT +40 ms mobile, LCP +52 ms desktop)

2 participants