Repository navigation
fix(oracle-gaps): the daemon reloads every module a run read, so its reports match a cold run - #37
Merged
Merged
Conversation
The grammar gains one warm context (`--contexts 1`), where every run of a check takes the same context in a fixed order. The constructed history "an edit after a hang replaced the only context" has a hanging test in file a and a judging test in file b, and edits file b's helper. It enters the new required state of that name: the edit changed the cold result after the daemon's previous check cut a run off and so replaced the context that had read every file. On the parent commit the history fails law 9 at once: after the helper edit the daemon reports f1's delete-call mutant killed, while the cold run reports it survived (ORACLE_SEED=20261105 ORACLE_PATH=27). Co-authored-by: Isaac <no-reply@databricks.com>
A warm context invalidates, at the start of a check, every module whose text changed since a context recorded reading it. Only a single run (`unit`) recorded its reads. A batch of mutant copies loads its file's modules too, but recorded nothing. When a hang replaced the context that had recorded a module, no context kept the record, so another context, or the replacement, kept the old module after an edit, and the daemon reported results from before the edit. Each batch run, and each hung copy's confirming run, now goes through `batchIn`, which records the modules of its copies' files in that context before it runs them. Co-authored-by: Isaac <no-reply@databricks.com>
The grammar gains `lazyGate`: file b's verdict also waits on `tests/lazy.ts`, which the test imports only where its output differs, so no unmutated run loads it. The new edit `lazy` changes that module. The gate is open before any edit, so the model needs no change. The constructed history "an edit to a module that only mutated runs load" enters the new required state "edit lazy changed the cold result". On bf440ae the history fails law 9 at once: after the lazy edit, the daemon reuses a kill of f0's delete-call mutant that read the old module (ORACLE_SEED=20261105 ORACLE_PATH=28). The state of the replaced-context history is renamed to what it measures: "an edit that changed the cold result after a hang replaced the only context". The limits record that law 9's edits come only between checks, so an input that changes while a run runs has no witness. Co-authored-by: Isaac <no-reply@databricks.com>
…ch run The capture's closing row lists the files of the modules each copy evaluated, which include a module that only a mutated branch imports at run time (Vitest's importDurations leaves it out). A run is stored under its file's unmutated inputs and those modules, for single runs and batch copies alike. Each run is bracketed: startIn invalidates a known input that changed since the context read it, also during this check, and takes the inputs' hashes at the start. settleIn records what the run read in the context's ledger, invalidates an input that changed while the run ran, and then does not store the run. Co-authored-by: Isaac <no-reply@databricks.com>
Co-authored-by: Isaac <no-reply@databricks.com>
…e batch The constructed history "a lazy module loaded before a hang in the same batch" runs one context with the lazy gate. File b tests an `if (x > 4)` function with a judging test (input 1) and a hanging test (input 7), so one batch runs the if-true mutant, which loads tests/lazy.ts and is killed, and then a mutant that hangs. It enters the new required state "a lazy edit changed the cold result after a batch was cut off". On 7870d09 it fails law 9 (ORACLE_SEED=20261105 ORACLE_PATH=29): the copies before the hang were stored without their evaluated modules, so the daemon reused the kill after the lazy edit. The review found the history. Co-authored-by: Isaac <no-reply@databricks.com>
…its own The copies that finished before a hang cut their batch off now carry the modules they evaluated as inputs, as every other batch copy does. The capture lists only the modules marked evaluated: the worker's map keeps every module it ever evaluated, and a copy's module reset only marks them unevaluated, so a copy listed the modules of the copies before it. settleIn hashes each path once. Co-authored-by: Isaac <no-reply@databricks.com>
Co-authored-by: Isaac <no-reply@databricks.com>
Each of the three new constructed histories has a fixed-seed, a random, and a determinism unit. Each history's three units go to one shard (e2e-1 to e2e-3); they cost 3 to 13 s each locally. Co-authored-by: Isaac <no-reply@databricks.com>
🦋 Changeset detectedLatest commit: 9c18836 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars.
|
commit: |
This was referenced Nov 12, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The gap CLI's daemon (
--daemon) could report a result from before an edit. A cold run of the same state reported a different result, which breaks law 9 of the end-to-end gap oracle ("incremental equals cold"). This change closes two ways that a stored or cached run went stale. A warm context now records every module that a run evaluates, batch runs included. A stored run now lists the modules that it really loaded, also a module that only a mutated branch imports.What went wrong
A warm context keeps the modules it loaded. At the start of each check, the runner invalidates a module that changed, but only in contexts whose ledger records that they read it. A stored unit is reused while the hash of each of its inputs is unchanged. Two gaps broke this.
A replaced context took its record with it. Only a single run (
unit) recorded its modules in the ledger. A batch of mutant copies loaded the same modules but recorded nothing. The defect needs three conditions:b.test.ts. That context recordstests/strict.ts.b.test.tscopies, which loadedstrict.tstoo.At the next check no ledger names
strict.ts, so no context invalidates it. In the failing trace the edit flipsstrict, which gates file b's verdicts. The cold run reportssrc/sut.ts#f1:delete-callsurvived. The daemon recomputes the unit with the oldstrict.tsloaded and reports a kill.A module that only a mutated branch loads was no input. The runner stored a batch copy under its file's unmutated inputs. It assumed that a mutant changes no import. A mutated branch can reach a dynamic
import()that the unmutated run never took. Vitest'simportDurationsalso leaves out a module imported at run time. An edit of that module then changed nothing that the stored unit recorded. The daemon reused a verdict that read the old module, also with one context.The fix
unitsBatchand the second run of a hung copy, go through one helper,batchIn. A single run goes throughunit. Both now bracket the run withstartInandsettleIn.startIninvalidates each known input that changed since the context read it, also during this check, and takes the inputs' hashes at the start.settleInrecords what the run read in the context's ledger. If a known input changed while the run ran, it invalidates that input and does not store the run.__vitest_worker__.evaluatedModules). The worker's map keeps every module it ever evaluated, and the copy's module reset only marks them unevaluated. So the row lists only the modules marked evaluated, which are the copy's own.importsOfadds them to a run's inputs, for single runs and batch copies alike. This includes the copies that finished before a hang cut their batch off. A run is stored under its file's unmutated inputs and the modules it loaded beyond them.servedHashstays. The lookup and the ledger both need the hash of what a context serves. A context that serves an authored patch serves other text than the instrumented source.How the oracle reaches it
This change adds two generator dimensions, an edit, and two constructed histories:
contextscan now be 1. With one context, every run of a check uses the same context in a fixed order. A hang then always replaces the context that read every file.lazyGatemakes file b's verdict wait ontests/lazy.ts, which the test imports only where its output differs. The new editlazychanges that module. Its gate is open before any edit, so the model needs no change."an edit that changed the cold result after a hang replaced the only context" has three parts. They are a hanging test in file a, a judging test in file b, and the helper edit. It enters a required state of the same name. The state requires two conditions: the daemon's previous check cut a run off, and the edit changed the cold result. Whether the replacement read the edited file again is not observed. The history's order makes it read the file.
"an edit to a module that only mutated runs load" has three parts. They are one function, a judging test in file b with the lazy gate, and the lazy edit. It enters "edit lazy changed the cold result".
"a lazy module loaded before a hang in the same batch" has one context, the lazy gate, and the lazy edit. File b owns an
if (x > 4)function and tests it twice: a judging test with input 1 and a hanging test with input 7. One batch runs theif-truemutant, which loads the lazy module and is killed, and then a mutant that hangs. The history enters "a lazy edit changed the cold result after a batch was cut off". Which copy loaded the module is not observed. The history's order puts it before the hang.Each history costs 3 to 13 s locally. Since the e2e oracle registers its campaign parts as units (#35), each history has a fixed-seed, a random, and a determinism unit.
scripts/e2e-shards.mjsputs each history's three units in one shard, and its check passes. CI still runs only the fixed-seed units. Both run in every campaign, so CI's fixed-seed job checks them.Evidence
ORACLE_SEED=20261105 ORACLE_PATH=27 ORACLE_PROPERTY=oracle-gaps.reportfails law 9 in 9 s. The difference is "after helper, the daemon's report differs from the cold run's at src/sut.ts#f1:delete-call".ORACLE_PATH=28fails law 9 in 3 s. The difference is "after lazy, the daemon's report differs from the cold run's at src/sut.ts#f0:delete-call".ORACLE_PATH=29fails law 9 in 12 s. The difference is "after lazy, the daemon's report differs from the cold run's at src/sut.ts#f1:if-true". The review found this history.-t 'fixed seed 20261105: a lazy module loaded before a hang in the same batch'.-t "fixed seed 20261105", 305 s locally). The fast gap suites pass (31,249 tests). The full end-to-end oracle passes all 13 tests (2,768 s locally, under a load average of 14 to 23). Its fixed-seed reach has no state that the parent reached and this run misses.testthenhelper, checked cold and through the daemon. On the parent, the daemon differs from the cold run at 8 mutants after the helper edit. With the first fix it differs at none.importDurationsand misses a module imported at run time. The gap suites run only on Vitest 4.Scope check
These other evidence keys were checked for the same per-context staleness:
This pull request and its description were written by Isaac.