GeezerVisonThe World Wide Web, restored to 800 pixels of glory. | |||||||
| Home|About|Gaming cabinet|Archives|How it works|Starter sites | |||||||
GeezerVison is showing github.com — feat(oracles): owns on oracleProperty; a run that judges nothing fails; namespaced output by KyleAMathews · Pull Request #11 · TanStack/oracles Conversation
|
🦋 Changeset detectedLatest commit: e4dc69f 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 |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars.
|
Sorry, something went wrong.
There was an error while loading. Please reload this page.
The gap report reads `owns` statically and refuses a non-literal list, but the runtime accepted `owns: []`, which owns nothing and hides every gap. oracleProperty now requires a non-empty array of strings, and its doc comment says so. Law: `owns`, when given, is a non-empty literal list of strings (maintainer decision, 2026-11-10: oracleProperty takes owns). Authority: the same decision, and the review finding 9 on this PR. Reach: the self-oracle's ownsMode `empty` is drawn by the generated draft and a fixed history names it. RED: `npx vitest --run --config vitest.oracle-framework.config.mjs` on the parent commit: "fixed history: owns given as an empty list fails to load" fails (1 failed, 101 passed). GREEN: same command after the change: 102 passed. Mutant: the parent commit's runtime (accepts `[]`) is the mutant; the fixed history rejects it. Limits: the self-oracle covers the runtime check only; the static resolution of owns (finding 3) is not yet covered by a static law. Co-authored-by: Isaac <[email protected]>
… writes Findings 1 and 6: the bundle relocation and the absoluteImports plugin resolved a workspace dependency's bare imports from the wrong directory. Bundles go back to the dependency's own .oracle-gaps folder, where bare imports resolve as the dependency does. The --out namespacing stays. The constructed history for a bundle in the package's state is removed. Limit (recorded in the oracle's law): a dependency's bundle is a known stray write (date-fns report). The stray-write check excludes exactly that file name, and nothing else. Finding 5: the runtime-fault pin in resolveHistory no longer forces a whole-file owner. It pins only ownerless to false for faults that reach the run. withDeclaration alternates declareOracle and oracleProperty and pins one owned function (file a's first function), not a whole file, so a constructed history is not refused for want of an owner. Finding 4 and 10: README names .oracle-gaps-* for .gitignore and says why the runner's copies sit beside the config. The changeset is minor, since it removes the public OracleLaw.owner field. Law: a run writes outside its output directory and the package's .oracle-gaps only the known bundle stray write. Authority: the coordinator's decisions on this PR (findings 1, 4, 5, 6, 7, 10). Reach: every required state of oracle-gaps.report is entered by the fixed seed 20261105 (the test's constructed-history check passes). RED: `sh ~/.cache/oracle-grammar/shared/e2e-lock.sh npx vitest --run --maxWorkers=2 --config oracle-gaps/vitest.config.mjs gap-report-oracle -t "fixed seed"`. Before the owner pin: the constructed history "a stale authored mutant and a reformat" did not enter its states. Before the exclusion: "the run wrote deps/state-dep/.oracle-gaps/bundle-*.mjs". GREEN: the same command passes (1 passed, 12 skipped). Mutant: the bundle relocation and absoluteImports, which the revert removes; no separate mutant run. Limits: the bundle in a dependency's folder is not fixed. The harness files at the package root (.oracle-gaps-PID*) are removed on close, so the stray check cannot see a killed run's leftovers. Co-authored-by: Isaac <[email protected]>
The CLI prints `output: <path>` after each check, so a caller can find the run's directory. Pruning of old run directories is left for a follow-up. Co-authored-by: Isaac <[email protected]>
The run refused when no owns entry named a --source file, so a helper module owned only through an entry in another file was refused. The check now asks whether any function of a selected source has an owner, through the call trees (owners.ownsAny). Law: a selected source is refused only when no function of it, and no whole file, has an owner (analysis.mjs, maintainer decision 2026-11-08 on call-tree ownership). Reach: a focused regression, tests/oracle-gaps-owns-through-calls.test.ts. The static oracle's grammar does not generate a history where the owning entry is in another file, so the generated grammar does not reach this. RED: against 5ed5ae0's analysis.mjs, the run throws "no file owns any selected source: no owns entry names a --source file". GREEN: the owner of src/b.ts's helper is the test file. Limits: the generated static grammar does not reach a cross-file owner. Co-authored-by: Isaac <[email protected]>
Co-authored-by: Isaac <[email protected]>
Co-authored-by: Isaac <[email protected]> # Conflicts: # packages/eslint-plugin-oracles/tests/oracle-property-only-oracle.property.test.js # packages/oracles/oracle-gaps/gap-report-static-oracle.property.test.mjs # packages/oracles/tests/oracle-property-self-oracle.test.ts
A bad owns entry in a run that owns no selected source was refused as "no file owns any selected source", which hid the entry the author must fix. The analysis now checks each entry before the no-owner refusal. The static oracle gains the reach state "refused badEntry with no owner" and a constructed history for it (RED on 60cb448, GREEN here; the old order as a mutant fails both seeds). The model orders refusals by phase: declaration faults, no oracle file, and no owner come from the analysis before any test runs, then the runtime faults, now tagged `runtime`. Co-authored-by: Isaac <[email protected]>
commit: |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
With #11 merged, the README sample type-checks and the gap check counts it as an oracle file. It still left one gap: `>` to `>=` differs at clamp(-0, 0), and the histories never generated -0. The example now covers its type's domain, as the design skill teaches: -0 is in the grammar, a constructed history enters "negative zero at max", and the gap check kills all three mutants. Co-authored-by: Isaac <[email protected]>
#11 removed law.owner; two .js/.mjs oracle files that the typecheck does not read kept the field. Co-authored-by: Isaac <[email protected]>
…med gap output (#12) * test(oracles): the classify oracle law for survivor classes and directive messages (RED) Law: every survivor gets exactly one class from what the run measured (not-judged, indeterminate, dead-code, branch-never-taken, not-infected, not-observed); every gap's message is one directive from its kind's fixed set, built from run data, with no exit; the boundary hint adds its sentence; the stdout summary lists each gap once under its function, groups unowned warnings by function with counts, and the streamed gap lines equal the stdout's gap lines, each once; the kills-by-law section directs one next step. Authority: v20 design grammar decisions 10 and 11, the v20.1 amendments (C1, C12, indeterminate), the 2026-11-10 "no outs" decision, and the coordinator's unowned-grouping and kills-law items. Reach: constructed histories for each new class (a comparison whose operands never tie; the same with the boundary hint; a tie that shows nothing; a dead logical swap; an infected survivor no observation shows; a branch with one outcome) and the random grammar, which generates binary-swap mutants with operand pairs, original operators, and evidence tags. The fixed-seed run reaches the new states through constructed histories. RED (parent, before production): `pnpm --filter ... vitest --run --config oracle-gaps/vitest.config.mjs gap-report-classify` on origin/main: 11 of 11 fail. The parent report prints the 2254-shaped survivor with "Either the mutant is equivalent (say why; a maintainer approves it), or ..." (scratch check: exit phrase present: true). The calibration and the fixed-seed run fail on the missing compressed stdout (no renderStdout), the parent's classes, and the parent's messages. GREEN: pending (next commit). Mutant: pending (next commit). Limits: the e2e oracle (gap-report-oracle) still predicts the old class names until its model is updated; it runs only at the end, under the fixed-seed filter. * feat(oracles): survivor classes with directive messages, compressed stdout, streamed gaps (GREEN) Survivors get one class from what the run measured: not-judged (a changed value no law rejected), indeterminate, dead-code (the evidence tag that no input distinguishes the mutant), branch-never-taken (an `if` whose other outcome no owner history took; names the outcome to add), not-infected (a comparison whose operators agreed on every operand the owners reached; prints those operands; the boundary tag adds "Add a boundary history with -0 and 0."), and not-observed (infected, no observation changed; names the infecting test). Every gap's message is one directive built from run data, with no equivalence, approval, limit, or question. Failure classes keep their outcomes and get directive messages. The capture records the first operand pair of each comparison in a test (capture-setup.mjs `cmp`), so not-infected can print the operands. report.mjs: the full report (summary.md) keeps its shape; its unowned warnings are grouped by function with counts; the kills-by-law section gives one next step. renderStdout prints the totals, one legend line per class (its directive with placeholders), every gap once under its function (owners once per function, package-relative), unowned counts per function, and the paths of the full report and results.json. stream.mjs: gapLine (one form for the stream and the summary), progressLine (a count every 25 mutants), baselineLines (each oracle file's result and a failing law's replay). check.mjs prints the baseline, each gap as it is judged, and returns the compressed summary. Law: decision 11 of the v20 design grammar (survivor classes by what the CLI measured), decision 10 (messages leave no outs), v20.1 C1 and C12, the indeterminate class, the boundary and dead-code tags from #8, and the coordinator's unowned-grouping and kills-law items. Reach: gap-report-classify-oracle constructed histories for each new class, the random grammar's binary-swap mutants with operand pairs and evidence, and the 2254-shaped infected survivor. Reach states: not judged, branch never taken, not infected, not infected with a boundary hint, not observed, dead code, indeterminate, unreached. RED (parent, 454a546's parent 1f5ac22 plus the RED oracle): 11 of 11 fail (gap-report-classify, `pnpm vitest --run --config oracle-gaps/vitest.config.mjs gap-report-classify`). A scratch render of the 2254-shaped survivor on the parent prints "Either the mutant is equivalent (say why; a maintainer approves it), or ..." and the exit check reports it. GREEN: gap-report-classify 11/11 pass. gap-report-static, probe-form, and mutant-validity pass with it (31,244 tests in all four fast oracles). Mutant: (1) drop the not-infected branch in classify.mjs: the oracle fails. (2) add "or equivalently" to the not-observed directive: fails the message law. (3) drop not-observed gaps from renderStdout: fails the stdout law. Each was restored byte-identical after the run. Limits: the classify oracle emulates the capture from records, so it does not check that capture-setup.mjs records operands from a real run; the e2e oracle does (fixed-seed run, next commit). The model's fallback for a background-only reach names "the owner tests" (no test infected it) and is a choice this commit makes to match the message: flagged for the maintainer. Authored survivors get not-observed or not-judged until authored mutants are instrumented (C6, a later PR). The streamed-line law is checked here on the printer and in the e2e on real runs (next commit). The allowed(...) alternative and run-to-run change are out of scope. Co-authored-by: Isaac <[email protected]> * fix(oracles): a crash's message names the error and the law it needs A crashed mutant's message said "write a law that rejects this crash", which does not say that production threw without a law judging it. The message now quotes the error and directs the driver: record the error as an observation and state the law that decides if this input may throw. Failure classes keep their outcomes; only the message changes (decision 10: no outs). Law: decision 10 (messages leave no outs), and the coordinator's field item from a mitt run: two crashed mutants came from a TypeError that escaped the driver, and the agent had no directive for it. Reach: the classify oracle's constructed crash history and the random grammar's crash effect. RED: the previous report.mjs (the commit before this one) with the new directive regex in the oracle: 2 of 11 fail (`crashed` message mismatch). GREEN: 11 of 11 pass. Mutant: the old wording ("write a law ... rejects this crash") fails the new directive law, as the RED shows; a message with an exit word is rejected by the exit law. Limits: the message quotes the first line of the error, at most 120 characters; a longer error is truncated in the message and whole in the report's Detail line. Co-authored-by: Isaac <[email protected]> * fix(oracles): stream every authored gap, and name an unapplied mutant's line The fixed-seed e2e streaming law (added in the next commit) found two gaps in the streamed lines of the first version of this change: 1. An authored mutant whose `find` no longer matches is `does-not-apply`, and the authored loop skipped it before its streamed line. It is now streamed once, after the authored phase, with every other authored gap. 2. Such a mutant has no line, so its gap line read `Lundefined`. It now reads `L?`, which says the line is unknown. The legend's crash directive now shows the error as a placeholder instead of "(no message)". Law: the streaming law of the gap-report e2e oracle (law 11): the streamed gap lines are the report's gaps, each printed once, none missing. Authority: the 2026-11-10 maintainer decision that results stream as they are judged, and decision 10 (one clear line per gap). RED: the e2e fixed-seed run on the previous commit (bc37fd4) with the streaming law: "the streamed gap lines are not the report's gaps: 0 streamed, 1 reported", on a history with a stale authored mutant (the first run, and a second run with the `Lundefined` line still in place). GREEN: the e2e fixed-seed run after this change: 1 passed, 12 skipped (13). Mutant: removing the authored streaming loop fails the same law (the RED above). Limits: the streaming law is checked on the cold CLI's stderr; the daemon streams its reply's stderr to the same lines, which the e2e's law 9 compares only through the report, not the stream. The streamed-line law is checked only in the fixed-seed subset. Co-authored-by: Isaac <[email protected]> * test(oracles): the gap-report e2e model predicts the survivor classes and checks streaming The model: survivors are not-judged (a changed observation), indeterminate, branch-never-taken (an `if` whose line one outcome never took), not-infected (a comparison no owner run infected; the interpreter records the infected comparison sites, including the loop and until comparisons), and not-observed (infected, no observation changed). Authored survivors are not-judged or not-observed, since authored mutants are not instrumented. The e2e check adds law 11, streaming: the gap lines the CLI streams to stderr as each mutant is judged are the report's gaps, each once. The class names in the reach states and the law's prose follow the same vocabulary. Law: decision 11 of the v20 design grammar (survivor classes by what the CLI measured), and the streaming decision of 2026-11-10 (results stream as they are judged). Reach (fixed-seed run): branch never taken 3, not infected 5, not judged 4, not observed 4 histories, and the streamed-line law checked on every history that the e2e runs. RED: the e2e model before this commit predicted generator-gap and comparison-gap, and the CLI reports the new classes, so the fixed-seed run could not pass (the first run in the previous commit's RED). GREEN: fixed-seed run: 1 passed, 12 skipped (13), 186.9 s, under the shared e2e lock. Mutant: the streaming law rejects a CLI that omits an authored gap (the previous commit's RED). Limits: the infection model covers the comparison sites the interpreter runs (conditions, loops, until). The e2e fixtures generate no dead-code or boundary-hint evidence, so those classes are covered by the classify oracle only. Only the fixed-seed subset ran; the full e2e runs in CI. Co-authored-by: Isaac <[email protected]> * chore: changeset for the gap report's directives and output Co-authored-by: Isaac <[email protected]> * chore: shorten a changeset sentence Co-authored-by: Isaac <[email protected]> * fix(oracles): classify survivors from the mutant's own site; add not-distinguished Review round on the survivor classes: - branch-never-taken reads the mutant's own `if` site: an if-true changes its condition only where it was false, an if-false only where it was true, and the class applies only when that infection is absent (the sibling lookup is gone). RED on 809c8b9: the classify oracle's constructed case "an if-false that always saw true" got branch-never-taken where not-observed is owed. - Code that runs when a file loads the module infects every test of that file, and a nondeterministic test's infection and operands judge nothing. RED on 809c8b9: the constructed case "a comparison infected only at module load". - New class `not-distinguished` for the operators whose infection the capture does not measure (a loop's condition, an undefined call value, a dropped field, a skipped call, a logical operator). Its directive names the input that distinguishes the mutant. RED on 809c8b9: "mutant m0: not-observed, owed not-distinguished". Mutant: classing those operators as not-observed fails the classify oracle on both seeds. - framework-error and crashed messages name the check and the law; the dead-code header is exempt from the directive rule. - The e2e model follows the same rule: its unmeasured set matches classify.mjs, and the old probe guard's if-false and `!==` sites are infected (the guard is true under test). A new witness (a cache write no observation reads) keeps "not observed" reached, and the e2e oracle now reaches "not distinguished". GREEN: fast gap oracles 31,244 of 31,244; e2e fixed seed passes (reach: not observed 4, not distinguished 2, not infected 5, branch never taken 3, indeterminate 3); tsc and eslint clean. Co-authored-by: Isaac <[email protected]> * chore(oracles): drop the last law.owner lines in untyped oracle files #11 removed law.owner; two .js/.mjs oracle files that the typecheck does not read kept the field. Co-authored-by: Isaac <[email protected]> --------- Co-authored-by: Isaac <[email protected]>
…r internal error (exit 3), never a stack trace (#14) * refactor(oracles): remove law.owner Code ownership belongs to established tools such as CODEOWNERS (maintainer decision, 2026-11-10: "No law.owner"). The OracleLaw type loses its owner field, the manifest record stops writing it, and every law literal in the oracle files drops its owner line. Evidence: - Law: no behavior law. A removal of a manifest field the repo never reads (ORACLE_MANIFEST is written, not consumed, in this tree). - Reach / RED / Mutant: not applicable; no behavior changes. - GREEN: pnpm typecheck passes after the removal. - Limits: the removed field was only written, so no consumer changed. Co-authored-by: Isaac <[email protected]> * feat(oracles): take owns on oracleProperty `oracleProperty` takes `owns`, a literal list of source paths or functions the oracle owns. The gap report reads it statically, so a non-literal list fails registration. This makes `oracleProperty` the declaration as well as the campaign API. Law: `owns`, when given, must be an array of strings; anything else fails registration (maintainer decision, 2026-11-10: `oracleProperty` takes `owns`; the gap report reads it statically). Authority: /Users/kyle.mathews/.cache/oracle-grammar/v20-design-grammar/freeze.md, "Remove declareOracle". Reach: the self-oracle's registration generator draws `ownsMode` (none, list, string, bad entry) on fixed seed 20261108 and random seed; the fixed histories `owns given as a string fails to load`, `owns with a non-string entry fails to load`, and `a literal owns list loads` are its replay examples. RED: on the parent oracle-property.ts (b81b7b6), `pnpm exec vitest --run --config vitest.oracle-framework.config.mjs -t owns` fails 2 of 3 (the string and non-string-entry cases). GREEN: the full framework suite passes (`vitest --run`, 54 tests; `vitest.oracle-framework.config.mjs`, 101 tests), `--maxWorkers=2`. Mutant: dropping only the per-entry check (`owns.every((entry) => true)`) fails the non-string-entry case; the string case stays rejected by the Array.isArray check. Limits: the static reader in oracle-gaps reads `owns` in a later commit; this commit covers registration only. Non-literal values built at runtime are rejected only when they are not arrays of strings; a literal array of computed strings is not distinguished. Co-authored-by: Isaac <[email protected]> * feat(oracles): read owns from oracleProperty in the gap report The gap report reads `owns` from `oracleProperty` calls as well as `declareOracle`, statically, as a literal list. A test file that calls either is an oracle file. A run with no oracle file, or whose owns entries name no selected source, is refused with one diagnostic, so no mutant reads as unowned by accident. Law: an oracle file's `owns` entries own the functions their static call tree reaches, whichever declaring call names them; a run that owns no selected source is refused (maintainer decision, 2026-11-10: `oracleProperty` takes `owns`; a run with zero oracle files fails). Authority: ~/.cache/oracle-grammar/v20-design-grammar/freeze.md, "Remove declareOracle" and "A run with zero oracle files fails". Model: the static oracle's history grammar gains a declaration dimension (declareOracle, oracleProperty, both, neither), an ownerless flag, and the constructed histories `owns read from oracleProperty`, `owns read from both declarations`, `refused without an oracle file`, and `refused without an owner`. `neither` survives only a fault-free history, since a fault injects an entry into an oracle file. Constructed histories build from a base whose first function is owned and whose ownerless flag is off, so a random base cannot silently empty their ownership. Reach (static oracle, fixed seed 20261105 run, 40 histories each): `owns read from oracleProperty` 3 and 8 (both runs), `owns read from both declarations` 5 and 6, `refused without an oracle file` 4 and 4, `refused without an owner` 4 and 8. Every required state is entered, or the run fails. RED: on HEAD (23a544c) with owners.mjs and analysis.mjs unchanged and this commit's model and static oracle overlaid: `pnpm exec vitest --run --config oracle-gaps/vitest.config.mjs gap-report-static` fails 2 of 11 (fixed seed and random seed): `ownership` violation, `src/sut.ts:f0:31:if-true#0: unowned, owed owned`. GREEN: the same command on this commit, 11 of 11 pass. Mutant 1: `readOwns` reads only `declareOracle` (the old reader). Fails: `the analysis refused: no oracle file` on an oracleProperty-only fixture. Mutant 2: the zero-oracle-file refusal removed. Fails: `the refusal does not name no oracle file` (the static oracle's refusal law). Limits: the static oracle checks ownership, refusal and keys in-process. Whether a mutant owned through oracleProperty is killed is the end-to-end oracle's (not run here). The owns entries are read from the static tree only; no `oracleProperty` call that builds its owns list at runtime is accepted (the reader refuses it, as it does for declareOracle). Co-authored-by: Isaac <[email protected]> * feat(oracles): namespace each gap run's output and bundles under the package Law: a run writes only under its output directory and the package's .oracle-gaps. Each run's default output is a directory of its own under <pkg>/.oracle-gaps/out, and workspace bundles go to <pkg>/.oracle-gaps/bundles, not into a dependency's directory. Authority: maintainer decision of 2026-11-10 (namespacing of runs). Evidence: - Reach: the e2e constructed history "a workspace dependency bundled into the package's state" and the static constructed histories (every run's default output, three runs: two of one package, one of a sibling). - Static RED: HEAD args.mjs/check.mjs with the new static test, 10 of 11 failed with "output namespace" (/tmp/f1/red-static-HEAD.log). - Static GREEN: 21 of 21 fast gap oracles passed (/tmp/f1/fast-final.log). - e2e RED: HEAD check.mjs, fixed seed 20261105, "output namespace" at checkpoint cli: the run wrote deps/state-dep/.oracle-gaps/bundle-*.mjs outside its output directory (/tmp/f1/red-stray2.log). - e2e GREEN: fixed seed 20261105, 1 passed (/tmp/f1/green-B.log). - Mutant: bundle path reverted to the dependency's directory; the fixed-seed e2e fails with "output namespace" at checkpoint cli (/tmp/f1/mutant-stray.log). - Limits: the e2e runs only the fixed seed; the random campaign is not run for this change. The bundle resolution plugin (absoluteImports) is covered only by the constructed history, not by a dedicated law. Co-authored-by: Isaac <[email protected]> * chore: changeset for owns on oracleProperty and namespaced output Co-authored-by: Isaac <[email protected]> * fix(oracles): reject an empty owns list in oracleProperty The gap report reads `owns` statically and refuses a non-literal list, but the runtime accepted `owns: []`, which owns nothing and hides every gap. oracleProperty now requires a non-empty array of strings, and its doc comment says so. Law: `owns`, when given, is a non-empty literal list of strings (maintainer decision, 2026-11-10: oracleProperty takes owns). Authority: the same decision, and the review finding 9 on this PR. Reach: the self-oracle's ownsMode `empty` is drawn by the generated draft and a fixed history names it. RED: `npx vitest --run --config vitest.oracle-framework.config.mjs` on the parent commit: "fixed history: owns given as an empty list fails to load" fails (1 failed, 101 passed). GREEN: same command after the change: 102 passed. Mutant: the parent commit's runtime (accepts `[]`) is the mutant; the fixed history rejects it. Limits: the self-oracle covers the runtime check only; the static resolution of owns (finding 3) is not yet covered by a static law. Co-authored-by: Isaac <[email protected]> * fix(oracles): revert bundle relocation, pin one owner, document stray writes Findings 1 and 6: the bundle relocation and the absoluteImports plugin resolved a workspace dependency's bare imports from the wrong directory. Bundles go back to the dependency's own .oracle-gaps folder, where bare imports resolve as the dependency does. The --out namespacing stays. The constructed history for a bundle in the package's state is removed. Limit (recorded in the oracle's law): a dependency's bundle is a known stray write (date-fns report). The stray-write check excludes exactly that file name, and nothing else. Finding 5: the runtime-fault pin in resolveHistory no longer forces a whole-file owner. It pins only ownerless to false for faults that reach the run. withDeclaration alternates declareOracle and oracleProperty and pins one owned function (file a's first function), not a whole file, so a constructed history is not refused for want of an owner. Finding 4 and 10: README names .oracle-gaps-* for .gitignore and says why the runner's copies sit beside the config. The changeset is minor, since it removes the public OracleLaw.owner field. Law: a run writes outside its output directory and the package's .oracle-gaps only the known bundle stray write. Authority: the coordinator's decisions on this PR (findings 1, 4, 5, 6, 7, 10). Reach: every required state of oracle-gaps.report is entered by the fixed seed 20261105 (the test's constructed-history check passes). RED: `sh ~/.cache/oracle-grammar/shared/e2e-lock.sh npx vitest --run --maxWorkers=2 --config oracle-gaps/vitest.config.mjs gap-report-oracle -t "fixed seed"`. Before the owner pin: the constructed history "a stale authored mutant and a reformat" did not enter its states. Before the exclusion: "the run wrote deps/state-dep/.oracle-gaps/bundle-*.mjs". GREEN: the same command passes (1 passed, 12 skipped). Mutant: the bundle relocation and absoluteImports, which the revert removes; no separate mutant run. Limits: the bundle in a dependency's folder is not fixed. The harness files at the package root (.oracle-gaps-PID*) are removed on close, so the stray check cannot see a killed run's leftovers. Co-authored-by: Isaac <[email protected]> * fix(oracles): print the run's output path The CLI prints `output: <path>` after each check, so a caller can find the run's directory. Pruning of old run directories is left for a follow-up. Co-authored-by: Isaac <[email protected]> * fix(oracles): accept a source owned through another file's call tree The run refused when no owns entry named a --source file, so a helper module owned only through an entry in another file was refused. The check now asks whether any function of a selected source has an owner, through the call trees (owners.ownsAny). Law: a selected source is refused only when no function of it, and no whole file, has an owner (analysis.mjs, maintainer decision 2026-11-08 on call-tree ownership). Reach: a focused regression, tests/oracle-gaps-owns-through-calls.test.ts. The static oracle's grammar does not generate a history where the owning entry is in another file, so the generated grammar does not reach this. RED: against 5ed5ae0's analysis.mjs, the run throws "no file owns any selected source: no owns entry names a --source file". GREEN: the owner of src/b.ts's helper is the test file. Limits: the generated static grammar does not reach a cross-file owner. Co-authored-by: Isaac <[email protected]> * chore(oracles): rename a regression local that shadows its import Co-authored-by: Isaac <[email protected]> * fix(oracles): name a bad owns entry before the run's lack of an owner A bad owns entry in a run that owns no selected source was refused as "no file owns any selected source", which hid the entry the author must fix. The analysis now checks each entry before the no-owner refusal. The static oracle gains the reach state "refused badEntry with no owner" and a constructed history for it (RED on 60cb448, GREEN here; the old order as a mutant fails both seeds). The model orders refusals by phase: declaration faults, no oracle file, and no owner come from the analysis before any test runs, then the runtime faults, now tagged `runtime`. Co-authored-by: Isaac <[email protected]> * test(oracles): check that every gap CLI run ends with a report, never a stack trace Law 11 of the gap report oracle: a refusal exits 2 and prints one refused:/fix: block with no stack frames, and writes results.json and summary.md to the run's output directory. The static oracle adds a generated argument-refusal dimension that runs the real CLI, cold and with --daemon; the end-to-end oracle checks every refusal kind, cold and through the daemon. Red on the parent: every refusal exits 1 with a stack trace. Co-authored-by: Isaac <[email protected]> * test(oracles): generate a --mutants directory that does not exist The argument-refusal dimension of the static gap report oracle gains a --mutants path that does not exist. Red before the fix: the run reads the directory, fails with ENOENT, and ends as an internal error (exit 3) rather than a refusal. Co-authored-by: Isaac <[email protected]> * feat(oracles): end every gap CLI run with a report, never a stack trace A refusal (bad arguments, a broken owns declaration, no oracle file or owner, test.projects, a Vitest that does not load, a failing owner, a bad authored mutant) is one Refusal error with a cause and one fix. ending.mjs turns any thrown error into the run's ending, for a cold run and a check through the daemon alike: a refusal exits 2 with a refused:/fix: block and writes results.json and summary.md to the output directory once the arguments name one; any other error is an internal error that exits 3 and keeps its stack in error.log. The daemon sends the error that ended a check, and the CLI ends with it. Arguments are now validated against the usage text: unknown options, options with no value, a missing --package or --mutants directory, a bad --seed, count, limit, or --pool refuse the run. Co-authored-by: Isaac <[email protected]> * test(oracles): a refusal of the arguments names no output directory The end-to-end oracle's outsideSource fault is a refusal of the arguments, which name no output directory until they parse (law 11), so its refusal is judged without results.json. Also reflow two daemon comments. Co-authored-by: Isaac <[email protected]> * test(oracles): generate a refusal longer than a pipe's buffer The end-to-end oracle's brokenVitest history found a refusal whose fix line never reached the reader: the CLI exits at once, and on macOS a write to a pipe is asynchronous, so stderr is cut at 64 KB. The static oracle's unknown-option fault can now be long past that buffer. Red on the current CLI: the refusal printed no fix line. Co-authored-by: Isaac <[email protected]> * fix(oracles): exit the gap CLI only after its output is written On macOS a write to a pipe is asynchronous, so process.exit cut a long refusal (or summary) off at the pipe's 64 KB buffer and lost its fix line. The CLI now exits once stdout and stderr have written everything. Co-authored-by: Isaac <[email protected]> * test(oracles): generate the review's misclassified endings From an independent review of the gap CLI's endings. The static oracle's argument dimension gains a --source that is missing or is a directory, --mutants files that are not JSON, lack a field, or repeat an id, and an explicit --out that holds an earlier run's results.json and error.log, which the refusal must replace and remove. The end-to-end grammar gains a config that throws when it loads, a config with no default export, a setup file that throws, and a check from a second install of the CLI while the first install's daemon serves the package. Every e2e refusal now knows its output directory, since --out is given. Red on 9598153: a missing or directory --source and a non-JSON mutant file end as internal errors (exit 3); a refusal of the arguments ignores --out. Co-authored-by: Isaac <[email protected]> * test(oracles): judge the static half by the analysis's own refusal A runtime fault (a config that does not load, a failing owner) is found only when the runner starts. The static oracle now expects the refusal the analysis gives the same plan without the fault, since the model names a config that does not load before ownership. Its sibling package for the output-namespace law holds the source files that --source must name. Co-authored-by: Isaac <[email protected]> * fix(oracles): refuse the author's own files instead of calling them internal errors From an independent review of the gap CLI's endings. A --source that is missing or a directory, a --mutants file that is not JSON, and a Vitest config that throws or has no default export are the author's to fix, so each refuses the run (exit 2) and names the file, where each ended as an internal error. A refusal of the arguments is written to the --out they name, and every ending removes the other ending's files there. The daemon serves only a CLI of its own code: a request carries the CLI's code identity, and a daemon of other code declines it so that the CLI starts its own; a reply the CLI cannot read is an internal error, never exit 0. An error outside the awaited check ends the run once, as an internal error. Co-authored-by: Isaac <[email protected]> * chore: name the review's refusals and the daemon's code check in the changeset Co-authored-by: Isaac <[email protected]> * test(oracles): a check from another install is no edit of the package The other install words its summary otherwise by construction, so its check does not count as an edit that changed the cold result, and the next edit is compared with the state before it. Co-authored-by: Isaac <[email protected]> * fix(oracles): name a config fault before the analysis's refusals in the model The run loads the package's Vitest and config before it analyzes: check.mjs warms the contexts, then passes their test files to `analyze`. So a Vitest that does not load, and a `test.projects` config, are found before a broken declaration or a run that owns nothing. The model named them after the no-owner refusal (an ordering from #11 that no fixed seed reached). The e2e oracle gains the state "a config fault in a run that owns nothing" and a constructed history for it (test.projects, nothing owned). RED (old order): "the refusal does not name owns any selected source: refused: the package's Vitest config defines test.projects". GREEN: the e2e fixed seed passes and reaches the state once. Co-authored-by: Isaac <[email protected]> --------- Co-authored-by: Isaac <[email protected]>
There was an error while loading. Please reload this page.
Successfully merging this pull request may close these issues.
There was an error while loading. Please reload this page.