Repository navigation
v1.5.0 — Threads that take turns, an evidence bundle, and recovery
Four days, 72 commits and seventeen entries since v1.4.0. One trace-contract version, v18, and it is the one that judges a process whose threads take turns writing. The full section is CHANGELOG.md at this tag.
Read this first if a target of yours was refused multiple_threads_detected. Two writing threads of one process are judged now when every two of their writes are ordered by a thread creation or a join the shim recorded, and refused when any two are not (#539, contract v18, ADR 0067). The shim records pthread_join, pthread_detach and which thread created each new one; the engine passes the write between threads only where a recorded creation or join orders it. virtualenv 20.31.2 — writes, creates a worker that writes, joins it, writes again — is judged, PASS in both observation modes. beets 2.1.0's writers are pipeline siblings ordered by a queue the shim cannot see, and it stays refused, with a refusal that now names both threads, both operations, and that no recorded creation or join orders one before the other.
What a FAIL hands the person who has to fix it.
- An evidence bundle, and
sideeye evidence <case.json>to render it (#607, ADR 0071). A FAIL writes<work>/evidence/NNNNNN.jsonbeside its case: every path whose before, completed and crashed states differ, whether it existed before, whether its old bytes survive at another path in the judged state, whether the define declared it scratch, the operations either side of the crash point, what the built-in layer and the checker saw, the replay command, and the run's own caveats. Every field is measured orunknown, and there is no severity. The report names the bundle in a newevidencefield and line; the case file is unchanged. - A declared recovery, reported beside the verdict and changing none of it (#606, ADR 0072).
[recovery] commandandcheckinsideeye.toml, or--recoverywith--recovery-check, run after the exploration has decided the verdict, against each saved FAIL's crash state rebuilt from its snapshot:pass,failorunknowninearliest.recoveryandchecker_earliest.recovery, arecoveryline, and the bundle'srecovery.result. The recovery checker is trusted only after it rejects a corrupted state and accepts what the recovery leaves on the completed one;failmeans the recovery ran, ended and was rejected, and everything else isunknown. Where the engine can make cgroups each recovery runs in one of its own. Replay accepts the two flags and the replay line prints them.
--json seals its own report (#597, ADR 0068). When the JSON report is in place, the last line sideeye writes to stderr is sideeye: json sha256=<hex>;, the digest of exactly the bytes it wrote, or sideeye: json sha256=none; when it could not write one — so a reader that gets the file through a directory the judged program can also write can tell sideeye's report from one rewritten after. Not a report-schema change.
Refusals and pages that say more. Under --observe wrappers on Linux, oracle_missed_operation now points at --observe syscalls and names where that mode's hazards are written, and the failures a process that mode killed produces take a step that says so instead of fix_define (#599, ADR 0069). On macOS, a crash point reached on a worker thread — a pthread or a GCD block — now kills the world instead of refusing kill_did_not_land (#569). The pages now say that macOS does not judge a target that replaces its own image (#571).
Records. Twenty targets in four slates with v1.4.0: eight counterexamples, seven of them one window in seven languages — the file opened for truncation and the process dead before the write — two reported upstream (codespell-project/codespell#4025, rubocop/rubocop#15720). Five targets past earlier walls: Bun, markdownlint-cli and google-java-format FAIL in the same window, xz PASS, ninja FAIL on an output it rebuilds. Five whose state lives outside version control: aws-cli (every profile's keys), neovim (history and registers), jbang and pyenv FAIL, hatch PASS; aws/aws-cli#10648 and neovim/neovim#41940 reported. cargo re-met in both observation modes (#538). What a whole exploration costs and how much of it repeats, measured over 123 judged runs: not a bottleneck at this scale, and among the 50 worlds walked one by one, every repeated outcome is a world that did not fail. The funnel from a define to an upstream fix is a counted record (#605, ADR 0070).
Inside. The loop-closure judge calls its steps only against digests the launcher took itself and runs from bytes it verified, rebuilds everything outside the agent's tree from the seal, and resolves the path spellings a transcript writes (#510, #512, #513, #515, #592, ADR 0066). class-exclusions.tsv states the criterion its rows meet, and a check holds each row to it (#598).
Upgrading. Saved cases from v17 replay as case_no_longer_applies; re-record them. A v17 shim under this engine refuses contract_version_mismatch. The unknown_reason closed set is unchanged at 34 members; next_step gains observe_syscalls and syscalls_may_have_killed, and recovery.result is a new closed set of three, present only when a recovery is declared. With --json, stderr's last line is now the seal line.
Known. A recovery's pass from a tool that decides by modification time or permission can be manufactured by the rebuild, which carries restore-time timestamps and fixed modes; ninja's is one, and the record says so. On macOS, and on Linux where no cgroup can be made, a process one recovery leaves can reach the next. A ptrace-grade observer for file I/O that bypasses libc is still after 1.0 (#217).