Skip to content

Release 0.3.1 - #39

Merged
IonDen merged 5 commits into
mainfrom
fix/0.3.1-honest-outcomes
Oct 28, 2026
Merged

IonDen merged 5 commits into
mainfrom
fix/0.3.1-honest-outcomes

Conversation

@IonDen

@IonDen IonDen commented Oct 23, 2026 •

Copy link
Copy Markdown
Owner

Why

A working intervention could be reported as a supervisor failure. When a limit was hit, the supervisor sent TERM or KILL to the command's process group. If every process in that group had already exited but none was reaped yet, which is what a command that is slow to tear down looks like, Darwin refused the signal with EPERM. The supervisor read that refusal as a failure and exited 70 (supervisor_failure), although the intervention had worked and the command was gone. This reproduces on macOS 27.0.1.

What changed

In run, a refused group signal now counts as "the command has ended" when a rescan finds no live member in the group. The intervention stands, child_status records the command's own exit, and the exit code is 75. A refusal against a group that still has a live member, or one that cannot be scanned, stays a failure (70). Exit codes and their meanings are unchanged, and report schema v1 is unchanged: such a signal is recorded as process_missing, and permission_denied now means a live member remained. observe is not changed: it still records a group signal as delivered or refused, without the liveness check.

The Python client got two fixes. CheckpointWorker.poll() keeps the callback's own exception as __cause__ on CheckpointCallbackError, so a traceback shows why the save failed. import mlx_guard now succeeds when the package metadata is missing; start(), supervisor_argv() and load_report() then raise SupervisorDiscoveryError (start() before it launches anything) instead of leaking an importlib.metadata error, and reading mlx_guard.__version__ raises importlib.metadata.PackageNotFoundError.

Exit 74 for a report path that is already in use now says journal target already exists; choose a new --report path. The docs also state a limit plainly: if the supervisor itself is killed with SIGKILL, the command keeps running and only the hidden journal remains.

scripts/calibrate-host.sh also reads core counts correctly on macOS 27, which reports them in a new four-part form. Before, the provenance line on an M1 Max said "0 Performance and 8 Efficiency"; the measurements were never affected.

How to verify

The new real-process tests live in crates/mlx-guard-test-support/tests/runtime_ended_during_escalation.rs and crates/mlx-guard-test-support/tests/supervisor_killed.rs, plus a retry case in crates/mlx-guard-cli/tests/shell.rs.

cargo test -p mlx-guard-test-support --test runtime_ended_during_escalation
cargo test -p mlx-guard-test-support --test supervisor_killed
cargo test -p mlx-guard-cli --test shell
uv run --locked pytest python
uv run --locked pytest python/tests/test_calibrate_host_hardware.py

supervisor_killed needs the mlx-guard binary built first (cargo build -p mlx-guard-cli --bin mlx-guard).

Notes

This is the 0.3.1 release PR. The version bump and release notes are in it. Because the change touches the intervention path, the reference calibration and the long-run soak were re-captured on macOS 27.0.1 on the M1 Max 32 GB host, and every bound passes. The evidence is in evidence/v0.3.1/m1-max-32gb/. It was captured at the commit before the version bump, so its binaries report 0.3.0; the supervisor code is identical to the release.

Two figures moved against the 0.2.0 capture on macOS 26.6.2, and both still pass. The Metal visible-delta error rose from 3.03% to 4.03% of the 64 MiB buffer (the bound is 10%). The 16-member sampler used 1.90% of one core, up from 1.59% (the bound is 2%), which leaves the least room of any bound on this host. The other rows differ from 0.2.0 by amounts that are small against their bounds. These numbers describe this host, this commit and a debug build, not a universal limit.

…d ending

On macOS a signal to a process group whose members have all exited but are not yet reaped fails with EPERM. During an escalation the supervisor now rescans the owned group by exact identity and records such a refusal as process_missing when no live member remains, so a working intervention exits 75 instead of 70.
@IonDen IonDen self-assigned this Oct 23, 2026
@IonDen IonDen added bug Something isn't working documentation Improvements or additions to documentation labels Oct 23, 2026
@IonDen
IonDen marked this pull request as ready for review October 28, 2026 18:39
@IonDen
IonDen force-pushed the fix/0.3.1-honest-outcomes branch from 9a8af02 to 5177a5e Compare October 28, 2026 19:40
Bump the version to 0.3.1 and rewrite the release notes. Add the 0.3.1 reference calibration and soak bundles, captured on macOS 27.0.1 at the previous commit, and move the evidence links to them.

Render the calibration provenance core count from the text report, because macOS 27 reordered the fields of the JSON core code, and pass the hardware report to the helper on stdin instead of in argv.

Read __version__ on access, so the package imports without its distribution metadata and the SupervisorDiscoveryError fallback is reachable.

Order the escalation tests' fixture events so the ended-group case is reached by construction, and let the supervisor-kill test clean up after an early failure.
@IonDen
IonDen force-pushed the fix/0.3.1-honest-outcomes branch from 5177a5e to 20ba309 Compare October 28, 2026 19:59
@IonDen
IonDen merged commit a4c0d44 into main Oct 28, 2026
5 checks passed
@IonDen
IonDen deleted the fix/0.3.1-honest-outcomes branch October 28, 2026 20:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant