Repository navigation
🤖 tests: FakeRuntime honors aborts as LocalBaseRuntime does, and the runtime contract uses each runtime's path rules - #7377
Conversation
…rough HostProcesses HostProcesses (hostProcesses/) holds the host spawn (execFileAsync) and the global fetch that the import lint cannot see. skillsCatalogFetch.ts makes its git spawns and its search fetch through nodeHostProcesses, and gitNoRepoAutomationEnvForLocalRepo takes an optional processes argument. scriptedCommands.testHarness.ts is a script table of commands and URLs that a test layer answers without a process or a socket. A contract test runs the Node and scripted layers on the same two commands. --- _Generated with `xum` • Model: `anthropic:claude-opus-5-5` • Thinking: `high` • Cost: `$91.97`_
…hared with LocalRuntime fakeRuntime.testHarness.ts is a Runtime on a memfs volume: no location, absent-path errors like LocalRuntime, exec from the script table of scriptedCommands.testHarness.ts plus the stream temp-dir cleanup, and idle() to drain fire-and-forget execs. createMemoryHost builds it on the same volume as the memory HostFiles. runtimeContract.test.ts runs the file contract on LocalRuntime and FakeRuntime, and file_read reads a file on it. --- _Generated with `xum` • Model: `anthropic:claude-opus-5-5` • Thinking: `high` • Cost: `$98.68`_
…lls through SessionFiles AgentSession reads and writes the auto-retry preference, the exclusions and the todo list through historyService.files, and the closed-chat marker sweep takes a SessionFiles argument that defaults to the host. AIService creates the sessions dir and deletes a workspace's session dir through it. SessionFiles gains writeFile for the preference write, which tests spy on. Three pairs leave the local/no-host-imports allow map (12 in 5 files -> 9 in 5). --- _Generated with `xum` • Model: `anthropic:claude-opus-5-5` • Thinking: `high` • Cost: `$104.24`_
… and honours an aborted exec Codex review of #7368: the built-in rm -rf entry now matches cleanupStreamTempDir, whose cwd is ~/.xum-tmp (createTempDirForStream), not tempDir(). An exec with an aborted signal rejects before it runs anything, as LocalRuntime does. writeFile copies each chunk. The normalizePath contract compares with each runtime's own path API, so the LocalRuntime case also holds on Windows. --- _Generated with `xum` • Model: `anthropic:claude-opus-5-5` • Thinking: `high` • Cost: `$104.24`_
Codex round 1 on #7370: the fault wrapper delegated the new writeFile member, but cutNextWrite applied only to appendFile and writeSync, so a cut on the auto-retry preference path stayed queued for a later write. A contract case on both layers covers it.
…ter the start rejects Codex round 2 on #7366 (re-review of the restacked head), two P2s: - commandLine joined file and args with spaces, so ["show", "a b"] and ["show a", "b"] shared a key. A token with whitespace, a quote or a backslash, or an empty one, is now JSON-quoted. - The scripted layer checked the abort signal only at the start. It now rejects once the signal aborts, as execFileAsync does after it kills the child ("Command killed by signal SIGTERM", signal SIGTERM). A case runs on both layers.
…ts cleanup rule refuses . and .. The scripted keys of #7366 now JSON-quote a token with a space, so FakeRuntime.exec passes the whole command string as the key. The rm -rf rule matched '..' too (merge advisor follow-up 1 on #7255): with the cwd ~/.xum-tmp it would remove the home of the memory volume.
…honor, by name Codex round 3 on #7366: the scripted layer ignored timeoutMs and maxOutputBytes. It now drops no option that a caller sets. A fixed outcome settles at once and reads no env, so timeoutMs, killTreeOnTermination and env hold for it. A function entry can be slow and gets only the call, so it refuses timeoutMs and env. An outcome with more output than maxOutputBytes is refused, and onStderrData is always refused. Each refusal names the option.
# Conflicts: # src/node/services/hostProcesses/scriptedCommands.testHarness.ts
Codex round 4 on #7368: FakeRuntime.exec ignored timeout. With the rules of #7366's scripted layer, it drops no option that a caller sets. The built-in rm -rf rule and a fixed outcome settle at once and read no env, so timeout and env hold for them (streamManager's cleanup passes timeout 10). A function entry refuses timeout and env, and pathEnv, hostEnv and forcePTY are always refused.
#7255 item 6 (Codex rounds 5 of #7368): readFile errors its stream on an abort before or during the read, ensureDir rejects before it makes the folder, and a function-backed exec entry refuses abortSignal by name, because the fake checks it only before the start. writeFile and stat keep ignoring their signal, as LocalBaseRuntime does.
…rules of the runtime under test The fixtures used the host path.join, which gives backslash paths on Windows, where FakeRuntime resolves POSIX paths. (#7255 item 4)
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
🟢 e2e stories (Haiku): 14 passed27 agent steps · 12 replayed from cache · 15 model calls · 46.5k tokens (25% cached) All 14 tests in 9 files
e2e 0.20.0 · 1m 23s · web · run artifacts 🟢 e2e Electron stories (Haiku): 3 passed3 agent steps · 3 model calls · 8.0k tokens (21% cached) All 3 tests in 3 files
e2e 0.20.0 · 18.6s · electron · run artifacts 🟢 e2e agent repros (Haiku): no tests selectedSpend: $0.00 of the $1.00 cap (proxy ledger) e2e 0.20.0 · 5.3s · 2 targets (web, phone) · run artifacts |
|
@codex review |
🛡️ Codex Security Review · Automatically triggeredSecurity review completed. No security issues were found in this pull request. Reviewed commit: Only the user who started this review can view the report in Codex. ℹ️ About Codex security reviews in GitHubThis is an experimental Codex feature. Security reviews are triggered when:
Once complete, Codex will leave suggestions, or a comment if no findings are found. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fdf8ed2789
ℹ️ 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".
…he consumer reads the end LocalBaseRuntime's pull checks the signal after each chunk, so an abort after the first chunk, before the consumer reads the end, errors its stream. The fake enqueued and closed in start, so it returned the whole file. It now reads with no read-ahead and checks the signal on each pull. A new file-contract case runs on both runtimes: LocalRuntime passed it 200 of 200 times before the fix, and FakeRuntime failed it 200 of 200 times.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: eb9b69692a
ℹ️ 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".
LocalBaseRuntime cancels its reader when the signal aborts, so an abort right after a read of a missing path starts errors the stream as aborted, not as ENOENT. The fake surfaced the memfs error. It now checks the signal before it wraps a read failure. A new file-contract case runs on both runtimes: LocalRuntime passed it 200 of 200 times before the fix, and FakeRuntime failed it 200 of 200 times.
Summary
A small test-only follow-up to 5a PR 10 (#7368) of phase 5 (Loop host I/O). It fixes 2 items of the #7255 follow-up list. Item 6:
FakeRuntimehonors an aborted signal asLocalBaseRuntimedoes. Item 4: the runtime contract builds each fixture path with the path rules of the runtime under test.Implementation
fakeRuntime.testHarness.ts(🤖 refactor: track the agent-loop host services refactor (phases 1 to 5) #7255 item 6):readFileerrors its stream when the signal aborts before the consumer reads the end.ensureDirrejects on an aborted signal before it makes the folder.execentry refusesabortSignalby name, because the fake checks the signal only before the start.writeFileandstatkeep ignoring their signal, asLocalBaseRuntimedoes. The fake does no more thanLocalBaseRuntimedoes.runtimeContract.test.ts:RuntimeUnderTestgives the runtime'spathmodule (pathfor LocalRuntime,path.posixfor FakeRuntime) in place of aresolvefunction. The fixtures callunder.path.joinin place of the hostpath.join, which gives backslash paths on Windows, where FakeRuntime resolves POSIX paths. This needs no new test.Validation
fakeRuntime.testHarness.ts, the 3 new FakeRuntime cases fail and the other 18 pass.bun test ./src/node/runtime/runtimeContract.test.ts ./src/node/services/tools/file_read.test.ts: 42 pass, 0 fail.make static-checkandmake lint-eslint.readFilereads with no read-ahead and checks the signal on each pull, so an abort after the first chunk, before the consumer reads the end, errors the stream, asLocalBaseRuntime's pull does. A new file-contract case runs on both runtimes. Before the fix it passed 200 of 200 runs on LocalRuntime and failed 200 of 200 on FakeRuntime. After the fix it passed 400 of 400. The tests of the 4 files that use the memory host or FakeRuntime: 82 pass.make static-checkandmake lint-eslint.LocalBaseRuntimecancels its reader on abort. A new file-contract case runs on both runtimes. Before the fix it passed 200 of 200 runs on LocalRuntime and failed 200 of 200 on FakeRuntime. After the fix it passed 400 of 400. The 4 test files: 84 pass.make static-checkandmake lint-eslint.Generated with
xum• Model:anthropic:claude-opus-5-5• Thinking:high• Cost:$131.21