ci: pin the OpenClaw Bun fork b368 prerelease (#163251)

Pin the verified b368 Bun fork for Linux CI and admit three files whose CommonJS exports, post-script argv, and native pipe-output gaps are fixed. Keep mixed, broad, and V8-specific selections on Node; preserve complete oxlint diagnostic capture with a bounded fixture buffer.

Proof: no regressions in the eleven-selection fc90/b368 Linux comparison; final fast lane passed 16,608 cases on each pin; all 103 newly admitted cases passed through CI groups. Both Node-hidden smokes passed 10/10 with zero Node attempts. Final focused Node/Bun checks, local changed-file checks, and P2 reviews passed. WebKit remains unchanged at fb1167ebf2.
This commit is contained in:
Peter Steinberger 2026-10-01 23:53:23 -05:00 • committed by GitHub
parent 36ab072244
commit db20d75239
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 139 additions and 25 deletions

View file

@ -12,10 +12,10 @@ runs:
exit 1
fi
# Built from openclaw/bun commit fc90aa4d9c5dac37f7a63a04f8bd2e25df930c60.
# Built from openclaw/bun commit b3684189fe1f3592dfc5f9774060b405a243d9a6.
# WebKit commit fb1167ebf2cb9edc1f6771a2c11771b024693ae0.
bun_dir="$(mktemp -d "$RUNNER_TEMP/openclaw-test-bun.XXXXXX")"
release_url="https://github.com/openclaw/bun/releases/download/openclaw-v1.4.3-20261001-fc90aa4d9c-webkit-fb1167ebf2"
release_url="https://github.com/openclaw/bun/releases/download/openclaw-v1.4.3-20261002-b3684189fe-webkit-fb1167ebf2"
archive="$bun_dir/bun-linux-x64.zip"
for asset in bun-linux-x64.zip SHA256SUMS manifest.json; do
curl --fail --location --no-progress-meter --show-error \
@ -32,14 +32,14 @@ runs:
done
)
printf '%s %s\n' \
'34bb56d144ea9406fdb0eef41c18eef49d010d29147f15f9b0bd5f7b7a7512a4' \
'ba15d6d39be476dd2ec5151a047b51636c67d49281313021d697ccc2494c3987' \
"$archive" | sha256sum --check -
unzip -p "$archive" bun-linux-x64/bun > "$bun_dir/bun"
printf '%s %s\n' \
"$(jq -er '.assets[] | select(.name == "bun-linux-x64.zip") | .executable.sha256' "$bun_dir/manifest.json")" \
"$bun_dir/bun" | sha256sum --check -
printf '%s %s\n' \
'1b87aed612055f982689925c8b33e9f8b340ea822d9cb82ff3ee14be4c3a216b' \
'333ee756a2d3fa86089651031bf47be165ed48cf99e024e6597fa1330282d059' \
"$bun_dir/bun" | sha256sum --check -
chmod 755 "$bun_dir/bun"
"$bun_dir/bun" --version

View file

@ -190,11 +190,14 @@ test-project planner to find their owners. The runtime owner admits only qualifi
configs, exact files, and partitions; ambiguous selections retain Node. No tests
are removed from the selected inventory.
Worktree removal recovery (`src/agents/worktrees/service.removal-recovery.test.ts`)
also supports Bun when it is the entire exact selection in `agents-support`.
Mixed and broad PR selections retain their original Node invocation. Dual-runtime
validation keeps that complete Node selection and adds only the qualified recovery
file when the original include patterns select it.
Worktree removal recovery (`src/agents/worktrees/service.removal-recovery.test.ts`),
plugin CommonJS interoperability (`src/plugins/plugin-module-generation.interop.test.ts`),
oxlint configuration (`test/scripts/oxlint-config.test.ts`), and update timeout
diagnostics (`test/scripts/upgrade-survivor-timeout-diagnostics.test.ts`) also
support Bun when qualified files make up the entire exact selection in their
existing scoped owner. Mixed and broad PR selections retain their original Node
invocation. Dual-runtime validation keeps that complete Node selection and adds
only the qualified files selected by the original include patterns.
The gateway-client leaf config also supports Bun. Its existing ordered
gateway-core/gateway-client stripes run the core portion on Node and the client
@ -267,12 +270,16 @@ functions remain valid after the original cache buffer is garbage-collected.
It also keeps allocator ownership during zero-time event-loop polls, while
retaining the idle handoff for polls that can block.
The pinned build pairs Bun `fc90aa4d9c5dac37f7a63a04f8bd2e25df930c60` with WebKit
The pinned build pairs Bun `b3684189fe1f3592dfc5f9774060b405a243d9a6` with WebKit
`fb1167ebf2cb9edc1f6771a2c11771b024693ae0` in prerelease
`openclaw-v1.4.3-20261001-fc90aa4d9c-webkit-fb1167ebf2`.
WebKit is unchanged from the previous `17c9ecf9eb` pin. The build adds fixes for
compile-cache idle wakeups, `v8.queryObjects`, idempotent native readable
`ref`/`unref`, the default `module-sync` condition, and `process.once` wrapper identity.
`openclaw-v1.4.3-20261002-b3684189fe-webkit-fb1167ebf2`.
WebKit is unchanged from the previous `fc90aa4d9c` pin. The build fixes post-script
`--` argument separators, hidden CommonJS data exports, and truncated large writes
through native standard I/O pipes. It also switches Darwin file watches to kqueue;
that change does not affect Linux CI.
It retains fixes for compile-cache idle wakeups, `v8.queryObjects`, idempotent
native readable `ref`/`unref`, the default `module-sync` condition, and
`process.once` wrapper identity.
It retains the upstream Bun sync through `4b02e1031d` and fixes for thread-safe
function ownership, shared-environment deletion, and a module-key crash.
The shared provider-catalog retention test is qualified on this build and runs

View file

@ -77,8 +77,33 @@ const bunCompatibleConfigs = new Set([
"test/vitest/vitest.extension-memory.config.ts",
gatewayClientConfig,
]);
// Measured whole-file admission; the rest of agents-support retains Node.
const bunCompatibleAgentSupportFiles = ["src/agents/worktrees/service.removal-recovery.test.ts"];
// Whole-file qualification keeps mixed and broad scoped-owner envelopes on Node.
const bunCompatibleScopedOwners = new Map([
[
agentVitestProjectOwners.support.config,
{
dir: agentVitestProjectOwners.support.dir,
files: ["src/agents/worktrees/service.removal-recovery.test.ts"],
},
],
[
"test/vitest/vitest.plugins.config.ts",
{
dir: "src/plugins",
files: ["src/plugins/plugin-module-generation.interop.test.ts"],
},
],
[
"test/vitest/vitest.tooling.config.ts",
{
dir: "",
files: [
"test/scripts/oxlint-config.test.ts",
"test/scripts/upgrade-survivor-timeout-diagnostics.test.ts",
],
},
],
]);
const embeddedRunOwner = agentVitestProjectOwners.embeddedRun;
// src/state/openclaw-state-lease.retention.test.ts stays with its default Node owner:
// cold fs-safe native initialization roots the caller's ALS through custom_gc.
@ -350,13 +375,15 @@ export function resolveCiTestRuntimeSelections(
if (plans.every((plan) => bunCompatibleConfigs.has(plan.config))) {
return completeBun();
}
const config = plans[0]!.config;
const scopedOwner = bunCompatibleScopedOwners.get(config);
if (
plans.every((plan) => plan.config === agentVitestProjectOwners.support.config) &&
selection.targets.every((file) => bunCompatibleAgentSupportFiles.includes(file))
scopedOwner &&
plans.every((plan) => plan.config === config) &&
selection.targets.every((file) => scopedOwner.files.includes(file))
) {
return completeBun();
}
const config = plans[0]!.config;
const partition = runtimePartitions.get(config);
if (
!partition ||
@ -408,13 +435,13 @@ export function resolveCiTestRuntimeSelections(
if (bunCompatibleConfigs.has(config)) {
return completeBun();
}
if (config === agentVitestProjectOwners.support.config) {
const owner = agentVitestProjectOwners.support;
const scopedOwner = bunCompatibleScopedOwners.get(config);
if (scopedOwner) {
const includePatterns = selection.includePatterns?.length ? selection.includePatterns : null;
const qualifiedPatterns = relativizeScopedPatterns(bunCompatibleAgentSupportFiles, owner.dir);
const qualifiedPatterns = relativizeScopedPatterns(scopedOwner.files, scopedOwner.dir);
if (
includePatterns &&
relativizeScopedPatterns(includePatterns, owner.dir).every((pattern) =>
relativizeScopedPatterns(includePatterns, scopedOwner.dir).every((pattern) =>
qualifiedPatterns.includes(pattern),
)
) {
@ -422,8 +449,15 @@ export function resolveCiTestRuntimeSelections(
}
const bunFiles =
policy === "dual"
? bunCompatibleAgentSupportFiles.filter((file) =>
matchesVitestCliSelection(file, owner.include, [], owner.dir, {}, includePatterns),
? scopedOwner.files.filter((file) =>
matchesVitestCliSelection(
file,
scopedOwner.files,
[],
scopedOwner.dir,
{},
includePatterns,
),
)
: [];
return bunFiles.length ? [...node, { runtime: "bun", includePatterns: bunFiles }] : node;

View file

@ -1092,6 +1092,77 @@ describe("scripts/ci-run-node-test-shard.mts", () => {
expect(ciTestShardRequiresBun(selection, "dual")).toBe(row.bun);
});
it.each([
{
config: "test/vitest/vitest.plugins.config.ts",
dir: "src/plugins",
targets: ["src/plugins/plugin-module-generation.interop.test.ts"],
sibling: "src/plugins/plugin-module-generation.test.ts",
glob: "plugin-module-generation*.test.ts",
},
{
config: "test/vitest/vitest.tooling.config.ts",
dir: "",
targets: [
"test/scripts/oxlint-config.test.ts",
"test/scripts/upgrade-survivor-timeout-diagnostics.test.ts",
],
sibling: "test/scripts/oxlint-report-memory.test.ts",
glob: "test/scripts/*.test.ts",
},
])("admits only the qualified complete selections in $config", (row) => {
for (const policy of ["node", "bun-compatible", "dual"] as const) {
const expected =
policy === "node"
? [{ runtime: "node" }]
: policy === "dual"
? [{ runtime: "node" }, { runtime: "bun" }]
: [{ runtime: "bun" }];
for (const targets of [row.targets, ...row.targets.map((target) => [target])]) {
for (const selection of [
{ targets },
{ configs: [row.config], includePatterns: targets },
{
configs: [row.config],
includePatterns: targets.map((target) =>
row.dir ? target.slice(row.dir.length + 1) : target,
),
},
]) {
expect(resolveCiTestRuntimeSelections(selection, policy)).toEqual(expected);
expect(ciTestShardRequiresBun(selection, policy)).toBe(policy !== "node");
expect(
resolveCiTestRuntimeSelections({ ...selection, vitestArgs: ["--shard=1/2"] }, policy),
).toEqual([{ runtime: "node" }]);
}
}
for (const includePatterns of [undefined, [], [row.glob]]) {
const selection = { configs: [row.config], includePatterns };
expect(resolveCiTestRuntimeSelections(selection, policy)).toEqual([
{ runtime: "node" },
...(policy === "dual" ? [{ runtime: "bun", includePatterns: row.targets }] : []),
]);
expect(ciTestShardRequiresBun(selection, policy)).toBe(policy === "dual");
}
for (const target of row.targets) {
const selection = { configs: [row.config], includePatterns: [target, row.sibling] };
expect(resolveCiTestRuntimeSelections(selection, policy)).toEqual([
{ runtime: "node" },
...(policy === "dual" ? [{ runtime: "bun", includePatterns: [target] }] : []),
]);
expect(ciTestShardRequiresBun(selection, policy)).toBe(policy === "dual");
}
for (const selection of [
{ targets: [row.sibling] },
{ targets: [...row.targets, row.sibling] },
{ configs: [row.config], includePatterns: [row.sibling] },
{ configs: [row.config], includePatterns: ["src/infra/worker-task-pool.memory.test.ts"] },
]) {
expect(resolveCiTestRuntimeSelections(selection, policy)).toEqual([{ runtime: "node" }]);
}
}
});
it.each([
{ env: { OPENCLAW_NODE_TEST_VITEST_ARGS_JSON: '["--shard=1/2"]' } },
{ env: { OPENCLAW_NODE_TEST_VITEST_ARGS_JSON: '["--root=another-root"]' } },

View file

@ -741,6 +741,8 @@ describe("oxlint config", () => {
{
cwd: root,
encoding: "utf8",
// Capture the complete JSON and owner trace when temporary paths are long.
maxBuffer: 8 * 1024 * 1024,
timeout: 30_000,
env: {
...process.env,