Skip to content

spawn_process never throws for a binary it cannot start, benchctl's tests go green on Windows, and CHANGELIST.md covers the 298 merged PRs it had lost since the RC2 gate - #4050

Merged
borisbat merged 3 commits into
masterfrom
bbatkin/benchctl-windows
Sep 16, 2026
Merged

borisbat merged 3 commits into
masterfrom
bbatkin/benchctl-windows

Conversation

@borisbat

Copy link
Copy Markdown
Collaborator

Behavior changes: spawn_process never throws for a binary it cannot start - on Windows the handle now reads as an exited child (exit 127, no output) the way POSIX always reported it; utils/benchctl's test suite is green on Windows; CHANGELIST.md's 0.6.4 block gains the 298 merged PRs it had lost since the RC2 gate.

Why. Windows learned an unstartable binary at CreateProcess and threw; POSIX reports it through the child's own _exit(127). One contract split at the one place a supervisor cannot catch it without try / recover, and benchctl's tests found it - red on Windows since they landed. And the changelist's coverage stopped at #3786 (Aug 19): 224 of the 236 PRs merged since were uncited, seven arcs had no heading.

What changes.

  • spawn_process (Windows) builds a dead-at-birth handle on a failed CreateProcess - reaped, exit 127, stdout closed, pid 0 - so process_poll / process_wait / process_drain / close_process read it like any reaped child. src/builtin/ARCHITECTURE.md sec.8 carries the mechanism (cited from the site with the C++ pointer form); with_process's docstring and the handmade page state the contract.
  • tests/fio/test_process.das gains test_process_cannot_start: poll 127, wait 127, drain nothing, pid 0 on Windows / real on POSIX. utils/benchctl/tests/test_bench_cli.das spawns get_host_binary() instead of bin/daslang.
  • CHANGELIST.md: every substantive merged PR since v0.6.3 placed by arc; new subsections for libDaScriptNano, dasLLAMA text-to-speech, the DAP debugger + daslang -lib, and the document system ([arch] citations, REVIEW.das gates); the iquant tier, the idot lattice and the benchmark stand under their sections.

Observable behavior.

  • with_process(["/nonexistent"]) $(p) { process_poll(p) } answers 127 on Windows where it panicked before.
  • utils/benchctl/tests: test_bench_cli 3/3, test_bench_runner 13/13 on Windows (were 1 failed + 2 errors).
  • CHANGELIST.md's 0.6.4 block cites 725 PRs where it cited 427.

Where to look. src/builtin/module_builtin_fio.cpp (the !ok branch of the Windows spawn); src/builtin/ARCHITECTURE.md sec.8; tests/fio/test_process.das; CHANGELIST.md.

Validation, claims, ledger

Validation

  • tests/fio/test_process.das --test-names test_process_cannot_start: 2 tests, 2 passed on the rebuilt runtime. Negative control: on the previous runtime the cell's first statement is a thrown error (spawn_process: CreateProcess failed), i.e. an error, not a failed assertion - the test cannot pass without the change.
  • utils/benchctl/tests/test_bench_cli.das: 3/3; test_bench_runner.das: 13/13 - both on Windows, both red before (the CI utils-tests gate runs them on Linux, where they were always green, which is how the Windows red went unseen).
  • Preflight --only format,lint,review-md,docs over the changed set: 10 passed, 0 failed - format, lint (6 files clean on host and linux-mirror rails), review-md, das2rst, imgui2rst, vulkan2rst, stubs, uncategorized, untracked, sphinx-html.
  • The changelist audit: a read-only agent paged every closed PR against master through the GitHub API (gh pr list --limit 1000 caps at exactly 1000 and silently dropped one), giving 899 merged in scope (2026-06-10 .. 2026-09-16); 427 cited in the 0.6.4 block; 472 uncited, of which 174 are cited under the 0.6.3 heading; 4 phantom #N tokens, all legitimate (three fixes #issue, one MoltenVK#2793). The 298 placed here were grouped by the block's own section headings; the agent's per-PR one-liners were checked against titles and bodies for the entries that name behavior.

Claims - stated, not tested

  • The changelist entries summarize PR titles and bodies; they were not re-verified against the code of each PR.
  • (noise)-class PRs - data-only record re-mints, deploy path one-liners, changelist and version housekeeping, dependabot - are deliberately not listed, following the omission policy CHANGELIST: 0.6.4 coverage extended to master (the RC1 gate) #3768 stated at RC1. They are enumerated in the audit report if that policy should change.

Not done

Copilot AI lite review requested due to automatic review settings September 16, 2026 20:19
…ests go green on Windows, and CHANGELIST.md covers the 298 merged PRs it had lost since the RC2 gate

A binary that cannot be started is an exited child, on every platform. POSIX always reported it
that way - fork succeeds, the exec fails in the child, the child _exit(127)s, the parent holds a
live handle to a process that has already ended - while Windows learned the failure at
CreateProcess and threw, so a supervisor could not survive an unrunnable binary on one platform
without try / recover, which the runtime does not offer for soft failures. spawn_process now
builds, at CreateProcess, the handle the POSIX path ends up with: reaped, exit 127, stdout closed,
pid 0, no process or job handle, and every lifecycle call reads it the way it reads any reaped
child. process_pid answers 0 on Windows for such a child and the real pid on POSIX, the one
visible difference, and the reason a supervisor that needs "did it start at all" reads the exit
code. src/builtin/ARCHITECTURE.md sec.8 carries the mechanism, cited from the site; the
with_process docstring and the builtin's handmade page state the contract; tests/fio/test_process
pins it (poll 127, wait 127, drain nothing, the pid per platform) - on the old runtime its first
assertion is a panic, not a failure.

utils/benchctl's tests were red on Windows since they landed: test_bench_runner's unrunnable-binary
cell died at that throw, and test_bench_cli spawned "bin/daslang" where the same file passes
get_host_binary() three lines below. Both green now, 3/3 and 13/13.

CHANGELIST.md: an audit of every PR merged into master since v0.6.3 against the 0.6.4 block found
899 in scope, 427 cited, 472 not - 174 of them credited under the 0.6.3 heading (post-RC work through
2026-07-02, left there pending a release-boundary ruling) and 298 simply absent, almost all of them
the 236 PRs merged after the RC2 gate (#3786, 2026-08-19), of which 224 were uncited. Every substantive
one is placed now, grouped by arc in the block's own style; data-only re-records, deploy one-liners
and process housekeeping stay out, as the RC1 changelist's own omission policy set. Seven arcs had no
heading at all and get one: libDaScriptNano, dasLLAMA text-to-speech, the DAP debugger with daslang
-lib, and the document system - [arch] citations and REVIEW.das gates - plus the iquant tier, the idot
lattice and the nightly benchmark stand under their existing sections. Four phantom citations were
checked: three are issues cited as "fixes #N", correctly, and MoltenVK#2793 is an upstream issue whose
number collides with a daScript PR.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Newly added architecture documentation contains an objectively incorrect claim about try/recover availability and should be corrected before approval.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

This PR aligns spawn_process failure semantics across platforms (Windows now reports an unstartable binary as an already-exited child with exit code 127, matching POSIX), fixes utils/benchctl tests to run correctly on Windows by invoking the current host binary, and updates CHANGELIST.md to restore missing merged PR coverage in the 0.6.4 section.

Changes:

  • Windows spawn_process no longer throws on CreateProcess failure; it returns a “dead-at-birth” process handle (reaped, exit 127, no output, pid 0).
  • Adds a regression test for “cannot start” behavior and updates benchctl CLI tests to use get_host_binary().
  • Expands CHANGELIST.md 0.6.4 entries to include previously missing merged PRs and new subsections.
File summaries
File Description
utils/benchctl/tests/test_bench_cli.das Uses get_host_binary() instead of bin/daslang to make tests work on Windows layouts.
tests/fio/test_process.das Adds test_process_cannot_start to assert “no throw, exit 127, no output” contract and platform-specific pid expectations.
src/builtin/module_builtin_fio.cpp Implements Windows “dead handle” return path on failed CreateProcess to match POSIX exec-failure semantics.
src/builtin/ARCHITECTURE.md Documents the unified cross-platform contract and Windows mechanism for spawn_process cannot-start cases.
doc/source/stdlib/handmade/function-fio-spawn_process-0x5eca268e4ba0b640.rst Updates stdlib docs to state the new non-throwing cannot-start behavior and pid differences.
daslib/fio.das Updates with_process docstring to reflect the new “cannot start => exit 127, no throw” contract.
CHANGELIST.md Restores/extends 0.6.4 changelist coverage with missing merged PRs and new topical subsections.
Review details
  • Files reviewed: 7/7 changed files
  • Comments generated: 3
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread tests/fio/test_process.das Outdated
Comment thread src/builtin/ARCHITECTURE.md Outdated
Comment thread tests/fio/test_process.das Outdated
…e anchor, and the architecture note stops claiming try / recover is absent

Copilot round on #4050. get_running_platform_name is the non-folded runtime query, the right one
for a platform branch a test takes at run time; the test's comment cites the section by its
{#child-cannot-start} anchor the way the C++ site does, so section renumbering cannot orphan it;
and the mechanism sentence now says what it meant - an expected failure is never routed through
the panic path - rather than implying try / recover does not exist.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings September 16, 2026 20:25

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The new POSIX test assumes process_poll returns 127 immediately, but it can legally return process_running briefly after fork(), making the test potentially flaky under load.

Get a fresh assessment by requesting another Copilot review.

Review details
  • Files reviewed: 7/7 changed files
  • Comments generated: 1
  • Review effort level: Lite

Comment thread tests/fio/test_process.das Outdated
…acing its own exec failure cannot fail the assertion

Copilot round two on #4050. process_poll is waitpid(WNOHANG): right after fork the child may not
have reached _exit(127) yet, and the poll answers process_running for that window. process_wait
under the platform guard goes first and reads 127; poll then re-reads the code from the reaped
child, which is the contract the test pins.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings September 16, 2026 20:30

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The behavioral change is narrowly implemented, consistent with existing POSIX behavior, and is covered by a targeted new test plus corresponding documentation updates.

Review details
  • Files reviewed: 7/7 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

@borisbat
borisbat merged commit ed42c0d into master Sep 16, 2026
36 checks passed
@borisbat
borisbat deleted the bbatkin/benchctl-windows branch September 16, 2026 21:28
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.

2 participants