Skip to content

fix(editor-view): preload a verified private copy instead of the store path - #2187

Merged
schickling-assistant merged 5 commits into
mainfrom
fix/editor-view-preload-copy
Oct 30, 2026
Merged

schickling-assistant merged 5 commits into
mainfrom
fix/editor-view-preload-copy

Conversation

@schickling-assistant

@schickling-assistant schickling-assistant commented Oct 30, 2026 •

Copy link
Copy Markdown
Collaborator

Problem

The source lease launcher exports a store-backed JavaScript preload to every Node/Bun child. Bun 1.4.4 enumerates a resolved module's parent and uncached ancestor directories, including the entire store directory. Consequently every short-lived fake native/worker process in the cache-posture fixtures paid approximately 450 ms of resolver overhead. The isolation fixture launches 126 Bun processes; healthy forward progress then exceeded its unchanged 60-second aggregate deadline. This is not a daemon lock deadlock.

The mechanism is already reported in oven-sh/bun#32389. Proposed fix #32392 remains open and is scoped to the main entry point, not a demonstrated preload/ancestor fix. Exact 1.4.4 resolver evidence:

Goal

Keep the bootstrap-safe preload's exact trusted bytes while removing store enumeration from every child startup. No timeout changes or retries.

Decisions

  • Keep the wrapper implementation in shell/Nix. Install preload-<sha256>.cjs under a private editor-view-lease directory: Linux $XDG_RUNTIME_DIR, macOS per-user $TMPDIR, otherwise the user's cache directory.
  • Create the private leaf with mode 0700. Resolve each candidate with realpath, then validate every real ancestor up to /: root/current-user ownership, and no group/other write permissions unless sticky. The private base/leaf remain current-user-owned and non-writable by group/others. Unsafe candidates fall through to the next platform candidate or cache fallback; if none qualifies, launch fails closed.
  • Export only the resolved path, matching ^[A-Za-z0-9._/+-]+$, so runtime option tokenization cannot split or reinterpret it. Inherited child forwarding applies the same character check. Refusals name the affected path and a repair/removal remedy.
  • Install via a same-directory temporary file, write, fsync, chmod 0444, and no-clobber rename. Competing first launches converge; temporary files are cleaned on exit.
  • Before every export, verify a non-symlink regular file, current-user ownership, exact 0444 mode, and SHA-256 against the store source. Existing mismatches fail closed, without silently repairing tampering.
  • A symlink to the store file is insufficient: Bun realpaths it and still enumerates the store. Merely nesting the preload in a derivation is also insufficient because ancestor enumeration remains.

Consumer audit

consumer.nix exports one verified path consistently through EDITOR_VIEW_LEASE_PRELOAD, NODE_OPTIONS --require, and BUN_OPTIONS --preload. inherit.cjs checks its own __filename against the same option-safe character whitelist before forwarding, so descendants naturally retain the verified copy, including replacement environments and patched spawn methods. Genie's ts-api.ts imports the exported absolute path and has no store-prefix identity check; its comment now describes the verified bootstrap mapper. The native lease contains no preload-path comparison or store-prefix trust check. Standalone-staging metadata continues to identify the immutable source artifact; direct descriptor-handoff fixtures intentionally exercise that tracked source rather than a production path override.

Verification

Final head: 01738e3a17f8906ee0067fe9687e216cd6e93918.

Final review-hardening proofs

At the exact final clean head, under gate-slot --class eval --max-hold 1800 and nice -n 19:

  • Real-launcher bun test ./scripts/editor-view-source.integration.test.ts: 35 pass, 0 fail, 123 assertions, 7.45 s.
  • ONE devenv tasks run buck2:cache-posture:test --mode single --refresh-task-cache --no-tui: 160 pass, 0 fail, 1,223 assertions, 38.50 s; zero classified timeout/assertion/other failures and no killed-dangling message.
  • Added isolated regressions for non-sticky group/other-writable ancestors with safe fallback, sticky world-writable ancestor acceptance, whitespace rejection/fallback and all-candidates-refused behavior, canonical symlink resolution, path/remedy diagnostics, and unsafe inherited forwarding.
  • Review hardening is one implementation commit plus two small test-only corrections: canonical path comparison for macOS /var resolution, and surfacing Bun spawnSync's returned refusal error rather than ignoring it. No timeout changes, amendments, or force pushes.

Initial implementation proofs

The measurements and aggregate results below were collected at initial head 7f1fdaeed8e34a7651cecc77b2760c4d7437540c, before the additional ancestry checks. They are retained as mechanism evidence, not as a new measurement of final-launcher overhead.

All execution was scoped and admitted through gate-slot --class eval with nice -n 19; no workspace-wide check was run.

Proof Result
buck2:cache-posture:test --mode single --refresh-task-cache --no-tui, run 1 160 pass, 0 fail, 34.82 s
Same task, run 2 160 pass, 0 fail, 32.36 s
Timeout classification, both runs 0 timeout / 0 assertion / 0 other failures, no killed-dangling message
Changed scripts/editor-view-source.integration.test.ts through the real source launcher 29 pass, 0 fail, 97 assertions, 1.377 s
Touched TypeScript files only: oxfmt and oxlint Both passed
buck2:editor:publish:test prerequisite Passed
Owning genie:buck2:test --mode single --refresh-task-cache --no-tui 253 pass, 3 prerequisite failures, zero timeouts; see caveat below

New regressions cover the real launcher's three consistent non-store exports, content hash/tampering, exact file mode, concurrent first installs, wrong-owner and group/world-writable directories, and symlink rejection. Their owning task is genie:buck2:test, run by CI quality / pr/quality, step Genie projection and CI workflow regression tests; the aggregate also participates in the regular test:run lane. CI executes the same launcher/installer path.

Startup measurements

Bun 1.4.4; 10 interleaved real-launcher starts per variant, same checkout and runtime:

Start Before After
Real launcher, median 725.53 ms 121.36 ms
Bun child -e 1 spawned by the actual preloaded Bun parent, retaining exported lease environment, median of 10 approximately 450 ms store-preload baseline 12.33 ms (10.45–12.74 ms)

The remaining launcher cost is its existing native workspace/lease discovery, paid once per launcher, not once per child. A traced new-launcher start had 2,656 getdents64 calls across 1,326 directories in native discovery; the Bun phase had only 38 calls and zero enumeration of the store root. Largest native directories held 338, 258 and 243 entries. strace -f -c counted 19,623 newfstatat (94.721 ms), 2,698 getdents64 (30.565 ms), 1,801 openat (8.870 ms), and 13 statx (0.071 ms). These traced syscall times are not untraced wall-clock measurements.

Complexity

One bootstrap-independent shell installer, using the wrapper's existing coreutils dependency. No new runtime/language dependency or lease protocol change.

Concerns

The full owning aggregate is not locally green in this narrowly provisioned checkout: its three unchanged reaper fixtures lack the scheduled megarepo dependency publication (@overeng/effect-path). Before the approved scoped prerequisite, they lacked effect; afterward they still lack the workspace dependency. The original store-backed launcher reproduces the same three missing-module failures on the unchanged reaper file, independently of this fix. Publication was not widened beyond the approved source-test prerequisite. The changed file and both cache-posture acceptance runs are green. macOS behavior is covered by the shared code path and CI, not a local macOS run.

Friction & bottlenecks

Single-mode task execution omits the owning aggregate's scheduled megarepo installer; dependency failures are explicitly retained above rather than described as passing tests. The native launcher's recursive discovery is a separate fixed-per-launch cost, not changed here. Focused verification waited through a scheduled resource-admission fence; no admission bypass was used.

Follow-ups

Upstream resolver optimization is tracked by oven-sh/bun#32389 and #32392; no upstream issue was opened for this change.

References

Refs #1990 (source lease wrapper), #2180 (private fixture roots), #2182 (Bun 1.4.4 task runtime).

Posted on behalf of @schickling
field value
agent_identity agent/effect-utils/build-cache
session 01a1e7d9
agent_persona generalist
agent_supervisor unavailable
agent_tool OMP
agent_tool_version 18.10.2
agent_runtime OMP 18.10.2
agent_model anthropic/claude-opus-5-5
worktree editor-view-preload-copy/editor-view-preload-copy

…e path

agent-identity: agent/effect-utils/build-cache
agent-persona: generalist
agent-supervisor: unavailable
agent-tool: OMP
agent-tool-version: 18.10.2
agent-runtime: OMP 18.10.2
agent-model: anthropic/claude-opus-5-5
@schickling-assistant schickling-assistant added origin:agent Filed or primarily produced by an AI agent · Set: AI agent or manual area:ci CI workflows, runners, and pipeline configuration · Set: manual labels Oct 30, 2026
@github-actions

github-actions Bot commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

Pipeline traces

24 jobs; 7 successful, 0 failed, 0 cancelled, 17 skipped

Image unavailable; jobs-only Mermaid timeline below.

Job Status Wall time Delta vs main p50 Trace
default-ref-policy success 0m 51s -6.0s (-10.5%; n=7) not instrumented
test-megarepo-store-gc success 6m 22s no main baseline Explore
pr-buck2-tools success 4m 59s no main baseline Explore
quality success 10m 42s no main baseline Explore
source-shape success 0m 57s no main baseline not instrumented
All other jobs (19)
Job Status Wall time Delta vs main p50 Trace
pr-reviews-resolved success 0m 03s -1.0s (-25.0%; n=7) not instrumented
tested-tree success 0m 03s -11.0s (-78.6%; n=7) not instrumented
trusted-buck2-remote-cache-proof skipped unavailable duration unavailable unavailable
test-live-deploy-ci-tools skipped unavailable duration unavailable unavailable
test-integration-notion skipped unavailable duration unavailable unavailable
consumer-smoke skipped unavailable duration unavailable unavailable
promote-published skipped unavailable duration unavailable unavailable
weaver skipped unavailable duration unavailable unavailable
test-playwright-tui-react skipped unavailable duration unavailable unavailable
test[runner=namespace-profile-linux-x86-64] skipped unavailable duration unavailable unavailable
cargo skipped unavailable duration unavailable unavailable
test-playwright-utils skipped unavailable duration unavailable unavailable
test-integration-restate skipped unavailable duration unavailable unavailable
pr-a-inert-buck skipped unavailable duration unavailable unavailable
build-products skipped unavailable duration unavailable unavailable
test[runner=namespace-profile-macos-arm64] skipped unavailable duration unavailable unavailable
publish-products skipped unavailable duration unavailable unavailable
deploy-storybooks skipped unavailable duration unavailable unavailable
notify-alignment skipped unavailable duration unavailable unavailable

Main baseline samples (by job): default-ref-policy n=7, pr-reviews-resolved n=7, tested-tree n=7, test-megarepo-store-gc n=0, pr-buck2-tools n=0, trusted-buck2-remote-cache-proof n=7, test-live-deploy-ci-tools n=7, test-integration-notion n=7, consumer-smoke n=7, promote-published n=7, quality n=0, weaver n=0, test-playwright-tui-react n=0, test[runner=namespace-profile-linux-x86-64] n=0, cargo n=0, test-playwright-utils n=0, test-integration-restate n=0, pr-a-inert-buck n=0, build-products n=0, test[runner=namespace-profile-macos-arm64] n=0, publish-products n=7, deploy-storybooks n=7, source-shape n=0, notify-alignment n=7.
Selected main run IDs: 40963652692, 40583742369, 40577413153, 40574768792, 40567843858, 40553922820, 40545041350, 40539008876, 40527890767, 40523082503, 40517599401, 40451502897, 40449789215, 40448068821, 40444468076, 40442544723, 40435001667, 40422347106, 40419419978, 40416967114.
Task-level durations are not included. Trace links may be empty while export, indexing, or retention is pending.

Pipeline timeline
gantt
    title Pipeline jobs (start 2026-10-30 02:23:35 UTC; axis in local time)
    dateFormat YYYY-MM-DD HH:mm:ssZZ
    axisFormat %H:%M
    todayMarker off
    section Jobs
    pr-reviews-resolved (success) :job1, 2026-10-30 02:23:35+0000, 3s
    tested-tree (success) :job2, 2026-10-30 02:23:35+0000, 3s
    test-megarepo-store-gc (success) :job3, 2026-10-30 02:23:41+0000, 382s
    default-ref-policy (success) :job0, 2026-10-30 02:23:42+0000, 51s
    pr-buck2-tools (success) :job4, 2026-10-30 02:23:42+0000, 299s
    quality (success) :job10, 2026-10-30 02:23:46+0000, 642s
    source-shape (success) :job22, 2026-10-30 02:24:35+0000, 57s
Loading

17 job(s) without a start time are omitted from the timeline, not measured as zero.

@github-actions

github-actions Bot commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

Storybook Previews

Subject Status Report Details Updated
devbar success devbar preview deployed Preview is ready 2026-10-30 02:34 UTC
effect-react success effect-react preview deployed Preview is ready 2026-10-30 02:34 UTC
effect-rpc-explorer-react success effect-rpc-explorer-react preview deployed Preview is ready 2026-10-30 02:34 UTC
effect-schema-form-aria success effect-schema-form-aria preview deployed Preview is ready 2026-10-30 02:34 UTC
genie success genie preview deployed Preview is ready 2026-10-30 02:34 UTC
gh-ci-utils success gh-ci-utils preview deployed Preview is ready 2026-10-30 02:34 UTC
megarepo success megarepo preview deployed Preview is ready 2026-10-30 02:34 UTC
meters success meters preview deployed Preview is ready 2026-10-30 02:34 UTC
notion-cli success notion-cli preview deployed Preview is ready 2026-10-30 02:34 UTC
notion-md success notion-md preview deployed Preview is ready 2026-10-30 02:35 UTC
notion-react success notion-react preview deployed Preview is ready 2026-10-30 02:35 UTC
react-inspector success react-inspector preview deployed Preview is ready 2026-10-30 02:35 UTC
tui-react success tui-react preview deployed Preview is ready 2026-10-30 02:35 UTC
Report history

PR 2187 · 2026-10-30 02:35 UTC

Subject Status Report Details Updated
devbar success devbar preview deployed Preview is ready 2026-10-30 02:34 UTC
effect-react success effect-react preview deployed Preview is ready 2026-10-30 02:34 UTC
effect-rpc-explorer-react success effect-rpc-explorer-react preview deployed Preview is ready 2026-10-30 02:34 UTC
effect-schema-form-aria success effect-schema-form-aria preview deployed Preview is ready 2026-10-30 02:34 UTC
genie success genie preview deployed Preview is ready 2026-10-30 02:34 UTC
gh-ci-utils success gh-ci-utils preview deployed Preview is ready 2026-10-30 02:34 UTC
megarepo success megarepo preview deployed Preview is ready 2026-10-30 02:34 UTC
meters success meters preview deployed Preview is ready 2026-10-30 02:34 UTC
notion-cli success notion-cli preview deployed Preview is ready 2026-10-30 02:34 UTC
notion-md success notion-md preview deployed Preview is ready 2026-10-30 02:35 UTC
notion-react success notion-react preview deployed Preview is ready 2026-10-30 02:35 UTC
react-inspector success react-inspector preview deployed Preview is ready 2026-10-30 02:35 UTC
tui-react success tui-react preview deployed Preview is ready 2026-10-30 02:35 UTC

PR 2187 · 2026-10-30 02:20 UTC

Subject Status Report Details Updated
devbar success devbar preview deployed Preview is ready 2026-10-30 02:19 UTC
effect-react success effect-react preview deployed Preview is ready 2026-10-30 02:19 UTC
effect-rpc-explorer-react success effect-rpc-explorer-react preview deployed Preview is ready 2026-10-30 02:19 UTC
effect-schema-form-aria success effect-schema-form-aria preview deployed Preview is ready 2026-10-30 02:19 UTC
genie success genie preview deployed Preview is ready 2026-10-30 02:19 UTC
gh-ci-utils success gh-ci-utils preview deployed Preview is ready 2026-10-30 02:19 UTC
megarepo success megarepo preview deployed Preview is ready 2026-10-30 02:19 UTC
meters success meters preview deployed Preview is ready 2026-10-30 02:19 UTC
notion-cli success notion-cli preview deployed Preview is ready 2026-10-30 02:19 UTC
notion-md success notion-md preview deployed Preview is ready 2026-10-30 02:19 UTC
notion-react success notion-react preview deployed Preview is ready 2026-10-30 02:19 UTC
react-inspector success react-inspector preview deployed Preview is ready 2026-10-30 02:19 UTC
tui-react success tui-react preview deployed Preview is ready 2026-10-30 02:20 UTC

PR 2187 · 2026-10-30 01:38 UTC

Subject Status Report Details Updated
devbar success devbar preview deployed Preview is ready 2026-10-30 01:37 UTC
effect-react success effect-react preview deployed Preview is ready 2026-10-30 01:37 UTC
effect-rpc-explorer-react success effect-rpc-explorer-react preview deployed Preview is ready 2026-10-30 01:37 UTC
effect-schema-form-aria success effect-schema-form-aria preview deployed Preview is ready 2026-10-30 01:37 UTC
genie success genie preview deployed Preview is ready 2026-10-30 01:38 UTC
gh-ci-utils success gh-ci-utils preview deployed Preview is ready 2026-10-30 01:38 UTC
megarepo success megarepo preview deployed Preview is ready 2026-10-30 01:38 UTC
meters success meters preview deployed Preview is ready 2026-10-30 01:38 UTC
notion-cli success notion-cli preview deployed Preview is ready 2026-10-30 01:38 UTC
notion-md success notion-md preview deployed Preview is ready 2026-10-30 01:38 UTC
notion-react success notion-react preview deployed Preview is ready 2026-10-30 01:38 UTC
react-inspector success react-inspector preview deployed Preview is ready 2026-10-30 01:38 UTC
tui-react success tui-react preview deployed Preview is ready 2026-10-30 01:38 UTC

agent-identity: agent/effect-utils/build-cache
agent-persona: generalist
agent-supervisor: unavailable
agent-tool: OMP
agent-tool-version: 18.10.2
agent-runtime: OMP 18.10.2
agent-model: anthropic/claude-opus-5-5
agent-identity: agent/effect-utils/build-cache
agent-persona: generalist
agent-supervisor: unavailable
agent-tool: OMP
agent-tool-version: 18.10.2
agent-runtime: OMP 18.10.2
agent-model: anthropic/claude-opus-5-5
agent-identity: agent/effect-utils/build-cache
agent-persona: generalist
agent-supervisor: unavailable
agent-tool: OMP
agent-tool-version: 18.10.2
agent-runtime: OMP 18.10.2
agent-model: anthropic/claude-opus-5-5
agent-identity: agent/effect-utils/build-cache
agent-persona: generalist
agent-supervisor: unavailable
agent-tool: OMP
agent-tool-version: 18.10.2
agent-runtime: OMP 18.10.2
agent-model: anthropic/claude-opus-5-5
@schickling-assistant

Copy link
Copy Markdown
Collaborator Author

Review GO at 4b0a251

Round Head Reviewer Result Notes
1 7f1fdae buck-toolchain (owner) GO Trust model, atomic install, consumers, GNU tool portability. P3 nit: refusal messages should name the path and the remedy.
1 7f1fdae independent NO-GO P1: ancestors of the runtime dir could be replaced by another user after verification. P2: a path with whitespace breaks NODE_OPTIONS/BUN_OPTIONS tokenization.
2 01738e3 independent GO Realpath plus StrictModes-style ancestor walk with candidate fallback; safe character set in selection and forwarding; P3 messages.
2 01738e3 buck-toolchain (owner) GO Delta confirmed.
CI 01738e3 pr/quality failed check_format only (test file wrapping).
3 4b0a251 independent GO Format-only delta.
Posted on behalf of @schickling
field value
agent_identity agent/effect-utils/build-cache
session 01a1e7d9
agent_persona generalist
agent_supervisor unavailable
agent_tool OMP
agent_tool_version 18.10.2
agent_runtime OMP 18.10.2
agent_model anthropic/claude-opus-5-5
worktree effect-utils/main

@schickling-assistant

Copy link
Copy Markdown
Collaborator Author

Receipts at 4b0a251

New tests (scripts/editor-view-source.integration.test.ts, task genie:buck2:test, CI job pr/quality step "Genie projection and CI workflow regression tests"), all passing in this job:

Test Result
the real source launcher exports the same verified copy to every consumer pass
publishes the expected hash outside the store and refuses subsequent tampering pass
concurrent installers converge on the same verified file pass
refuses a writable runtime directory (720) pass
refuses a writable runtime directory (702) pass
refuses a runtime directory owned by another user pass
refuses a symlink instead of a content-addressed regular file pass
refuses an existing writable preload even when its bytes match pass
skips a candidate beneath a non-sticky writable ancestor (770) pass
skips a candidate beneath a non-sticky writable ancestor (707) pass
accepts a sticky world-writable ancestor pass
skips a candidate with spaces and fails closed if no safe candidate remains pass
exports a resolved path rather than a symlinked runtime ancestor pass
refuses unsafe inherited forwarding even when loaded by an explicit argument pass

Local evidence (Linux): changed file 35/0; buck2:cache-posture:test 160/0 at the final behavior head, with no "killed dangling process" message (it was failing locally before with 15 s and 60 s timeouts). Inherited child Bun start under the real launcher: median 12.3 ms, previously about 450 ms.

Posted on behalf of @schickling
field value
agent_identity agent/effect-utils/build-cache
session 01a1e7d9
agent_persona generalist
agent_supervisor unavailable
agent_tool OMP
agent_tool_version 18.10.2
agent_runtime OMP 18.10.2
agent_model anthropic/claude-opus-5-5
worktree effect-utils/main

@schickling-assistant
schickling-assistant marked this pull request as ready for review October 30, 2026 02:39
@github-actions
github-actions Bot requested a review from schickling October 30, 2026 02:39
@schickling-assistant

Copy link
Copy Markdown
Collaborator Author

Handoff from Build-cache (agent/effect-utils/build-cache): ready at 4b0a251, with owner GO (buck-toolchain), independent exact-head GO and green CI. Waiting for effect-utils-manager to queue it. Handoff message: message/4d4ec42b99e3f288 (waiting for delivery).

Posted on behalf of @schickling
field value
agent_identity agent/effect-utils/build-cache
session 01a1e7d9
agent_persona generalist
agent_supervisor unavailable
agent_tool OMP
agent_tool_version 18.10.2
agent_runtime OMP 18.10.2
agent_model anthropic/claude-opus-5-5
worktree effect-utils/main

@schickling-assistant

Copy link
Copy Markdown
Collaborator Author

Merge record (effect-utils-manager): head 4b0a251, PR CI green (36 checks), owner GO at 01738e3 plus a 1-commit delta to 4b0a251 (test-file formatting only), independent review GO at 4b0a251 after the NO-GO round, no Hypermerge label, no timeout changes. Enqueuing.

Posted on behalf of @schickling
field value
agent_identity agent/effect-utils/effect-utils-manager
session 01a1b244
agent_persona generalist
agent_supervisor unavailable
agent_tool OMP
agent_tool_version 18.10.2
agent_runtime OMP 18.10.2
agent_model anthropic/claude-opus-5-5
worktree effect-utils/main

@schickling-assistant
schickling-assistant added this pull request to the merge queue Oct 30, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Oct 30, 2026
@schickling-assistant

Copy link
Copy Markdown
Collaborator Author

Merge record (effect-utils-manager): ejected at 02:54Z by test-storybook-plays (run 40993747193): the RpcExplorer story iframe did not become ready within 60 s. The other three aggregates passed. The editor-view lease output is identical to the last green main run (40992090126), and the same aggregate took 14 s there. This looks like an unrelated flake, so I re-enqueue the unchanged head 4b0a251 once. If it fails the same way again, the PR goes back to the author for analysis.

Posted on behalf of @schickling
field value
agent_identity agent/effect-utils/effect-utils-manager
session 01a1b244
agent_persona generalist
agent_supervisor unavailable
agent_tool OMP
agent_tool_version 18.10.2
agent_runtime OMP 18.10.2
agent_model anthropic/claude-opus-5-5
worktree effect-utils/main

@schickling-assistant
schickling-assistant added this pull request to the merge queue Oct 30, 2026
Merged via the queue into main with commit 7f3a86c Oct 30, 2026
36 checks passed
@schickling-assistant
schickling-assistant deleted the fix/editor-view-preload-copy branch October 30, 2026 03:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:ci CI workflows, runners, and pipeline configuration · Set: manual origin:agent Filed or primarily produced by an AI agent · Set: AI agent or manual

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant