Skip to content

test(ui-sdk): walk the inherited tree once for the /var socket proof - #2748

Merged
schlessera merged 1 commit into
mainfrom
fix/2674-var-socket-walk-044
Oct 23, 2026
Merged

schlessera merged 1 commit into
mainfrom
fix/2674-var-socket-walk-044

Conversation

@schlessera

@schlessera schlessera commented Oct 23, 2026 •

Copy link
Copy Markdown
Owner

Closes #2674

What changed

The /var socket test ("all worker profiles hide every /var socket while explicit runtime files still execute") no longer walks the whole visible filesystem once per worker profile. The fixture walks its own view once, and only where at least one profile inherits that view unchanged. The walk keeps up to 32 directory reads in flight. Each worker diffs its /proc/self/mountinfo against the fixture's, mount point by mount point, comparing device, root, type and source bottom to top. It reads only the subtrees below mount points whose stack differs. Everywhere else it lstats the sockets the baseline found. A worker exits non-zero (WALK_BASELINE_SKIPPED_INHERITED_PATHS) if the baseline skipped any path the worker inherits. A new control socket, /opt/odysseus-var-fixture/inherited/walk-control.sock, sits in a directory no worker mount touches. Every profile must report it (SOCKET_WALK_SEES_INHERITED_CONTROL), which proves the baseline branch. The receipt now records walk sizes and times for each profile and for the baseline. The deadline, the profiles, the / root and the /proc//sys exclusions are unchanged.

Cause

#2724's layout did not grow the walk. Workers mask /home, so the sibling .brain-unit-workers-* copies are invisible. Only the worker's own node_modules and packages are bound back, about 70k entries locally, as before. After #2724 the hosted logs show one dependency copy per worker (node_modules). Before it they show two (node_modules and packages/ui-kit/node_modules).

The test's neighbours did not change either. In both the failing run (5e6446ae, run 40034416635) and the passing rerun (d7f206d8 attempt 2, 118.5 s), the other worker was running the Chrome mounted parallel sessions suite for the whole window. Both runs used the same runner image (20261012.334.1).

The walk itself was the problem. Each profile walked the entire runner image, one directory at a time, and three profiles did so at once. Locally that is about 645k entries per profile and about 12.8 s of CPU per test. The walk spends about half its wall time blocked, not computing. Normal hosted runs took 100–118 s, about 65% of the 180 s deadline, so ordinary runner CPU and disk variance crossed it.

Why this shape

The issue ranked the fixes: (1) scan less, (2) bounded and fast, (3) fix the layout. Since the layout was not the cause, this PR does (1) and (2):

  • Three profiles re-reading the same inherited image is exactly what the test does not need. Mount stacks are the kernel's own record of what differs between two views, so the test does not trust the launcher's argv to know what changed.
  • Bounded parallel reads cover the case where the runner is waiting on a cold disk. On their own they cost about 1.6× the CPU of synchronous reads, which is why they are applied to one walk instead of three.

Proof

Base 5e6446ae9 (origin/main), head 2df07a3bc. Draft gates only. Timings are on a shared 32-core WSL2 host.

Failing first, with the test's whole cgroup capped at 7% of a CPU (systemd-run --user --scope -p CPUQuota=7% bun run test packages/ui-sdk/tests/worker-var-sockets.test.ts):

tree result cgroup CPU
origin/main fixture (fail) … [180025.78ms] ^ this test timed out after 180000ms. 12.8 s
this PR pass in 107.68 s 7.7 s

Other timings:

  • Uncontended: 7.1 s → 1.5 s wall.
  • One core shared with nine busy loops: 57.8 s → 14.9 s.
  • Receipt: baseline 574,766 entries with 10 subtrees skipped; governed and strict each read 70,070 entries, maintenance 67.

Mutations. Each was applied, run with bun run test packages/ui-sdk/tests/worker-var-sockets.test.ts, and restored:

  • M1: "/var" removed from HOST_MASKS, so /var is inherited and goes through the baseline lstat branch. Fails governed: SOCKET_WALK_ONLY_APPROVED_RELAY_AND_PROXY with + /var/lib/odysseus-runtime/host.sock, /var/snap/odysseus/host.sock, /var/spool/odysseus/host.sock, /var/tmp/odysseus/host.sock (baseline found 5 sockets; each worker checked 5).
  • M2: the /var tmpfs replaced with a self-bind, so /var is a changed mount and goes through the walked branch. Same failure, the same four /var sockets.
  • M3: workers ignore the baseline sockets. Fails governed: SOCKET_WALK_SEES_INHERITED_CONTROL (received only the two /run/brain-egress sockets).
  • M4: the fixture skips every directory. All three workers exit with WALK_BASELINE_SKIPPED_INHERITED_PATHS /boot /etc … /usr /snap /opt.
  • M5: socket collection removed. Fails governed: SOCKET_WALK_SEES_INHERITED_CONTROL (received []).
  • M6: every entry forced through the untyped lstat fallback. Still passes, as intended (test(ui-sdk): walk worker filesystems by dirent type and in parallel #2675's receipt).
  • M7: mount root left out of the stack comparison. Passes: no profile in this fixture binds two different roots of one device at the same point, so the test cannot tell the difference. Recorded as surviving.
bun run test packages/ui-sdk          # 1128 pass, 0 fail (84.25 s)
bun run check:pr --base origin/main   # rc=0, "Local preflight passed." (head 2df07a3bc)

The first bun run test packages/ui-sdk attempt had one unrelated failure, ROLLBACK_WRITER_READY_TIMEOUT in maintenance-index-input.test.ts, which is already tracked as #2747. That file then passed 3/3 on its own, and the full rerun above was clean. The host's load average was 12–24 at the time, from other workers.

No worker, launcher or sandbox source changed, only the test and its fixture, so the native hosted-app proof was not run.

Checklist

  • Focused local preflight/behavioral receipts passed; hosted proof is the coordinator's ready-candidate run.
  • Acceptance criteria from the issue are all met, or the gap is named below.
  • The PR and completed/advanced issues have verified release milestones under docs/process/github.md.
  • A changeset is included, or this changes nothing a consumer can see. (Test-only.)
  • No personal data anywhere in the diff — the leakage gate covers the whole tree.
  • The integration contract index or relevant component is updated in this same commit, or nothing in the machine surface moved.
  • Docs under docs/ reflect the change, or nothing documented moved.
  • Provider history stays append-only (docs/decisions/provider-history.md): the provider-history guard passes, or nothing on a turn's path changed.

Anything left open

🤖 Generated with Claude Code

The /var socket test walked the whole visible filesystem in each of three
worker profiles, at one directory read at a time. On a hosted runner that is
three walks of the runner image, and it sat at about two thirds of its 180 s
deadline; runner variance pushed it over (#2674).

The fixture now walks its own view once, wherever at least one profile
inherits it, with up to 32 directory reads in flight. Each worker compares
its /proc/self/mountinfo with the fixture's, reads only the subtrees below
mount points whose stack differs, and lstats the baseline's sockets
everywhere else. A worker refuses a baseline that skipped a path it
inherits. A new control socket, in a directory no worker mount touches,
proves the baseline branch in every profile.

Closes #2674

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@schlessera schlessera added this to the 0.44.0 milestone Oct 23, 2026
@schlessera schlessera added type: fix Something is broken and must behave the way it is documented. area: ui-sdk Wire protocol, runtime schemas, the server and client SDK surfaces. area: ci CI workflows, the gates they run, release scripts, packaging. labels Oct 23, 2026
@schlessera
schlessera marked this pull request as ready for review October 23, 2026 23:30
@schlessera
schlessera merged commit 73819e7 into main Oct 23, 2026
14 of 15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: ci CI workflows, the gates they run, release scripts, packaging. area: ui-sdk Wire protocol, runtime schemas, the server and client SDK surfaces. type: fix Something is broken and must behave the way it is documented.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ui-sdk: the /var socket test walks the whole filesystem three times in series and times out on loaded CI shards

1 participant