GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

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

@KyleAMathews

@KyleAMathews KyleAMathews commented Nov 10, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

An oracle can now declare the code it owns directly on oracleProperty. A gap run that judges nothing now fails. Before, it reported "0 gaps".

oracleProperty({
  id: 'parse',
  owns: ['src/index.ts#parse'],
  // law, model, histories, driver, check …
})

Why it matters

The gap CLI treated a test file as an oracle only when it called declareOracle. oracleProperty and declareOracle were separate calls. A file with only oracleProperty ran as a test, but the CLI did not see it as an oracle. The run then exited 0 with "0 gaps", and every mutant was an unowned warning. TanStack DB's worked example, collection-gc-transaction-oracle, has that shape, so an adopter who copied it got a clean report that judged nothing. The maintainer decided to remove declareOracle. This PR is the first step.

What changes

  • oracleProperty takes owns. The meaning is the same as in declareOracle: a file or a function (src/x.ts#fn) whose static call tree the oracle owns. The option must be a literal list. A string, or a list with an entry that is not a string, fails to load.
  • The gap CLI reads owns from oracleProperty and from declareOracle. A file that calls oracleProperty is an oracle file.
  • A run with no oracle file fails with one diagnostic. A run in which no file owns a selected --source also fails.
  • law.owner is removed. It referred to TanStack DB's coverage map, and tools such as CODEOWNERS own that job.
  • Each run writes under <package>/.oracle-gaps/out/<run>/ by default, and the CLI prints that path. Before, the default was a /tmp/oracle-gaps that every package and run shared.

Evidence

  • owns on oracleProperty: RED on the parent fails 2 of 3 owns cases in the framework self-oracle. GREEN passes the framework suite, 102 of 102, including the empty-list case. Mutant: dropping the check of each entry fails the bad-entry case.
  • The CLI reads owns: RED on the parent fails the static oracle's ownership law, 2 of 11. GREEN passes 11 of 11. Mutants: ignoring oracleProperty calls, or removing the zero-oracle refusal, each fail.
  • Namespaced output: RED on the parent fails the static namespace law (the default output is not under the package's .oracle-gaps/out). GREEN passes the fast gap oracles, 21 of 21, and the e2e fixed seed.
  • Ownership through another file: RED on the parent refuses --source src/b.ts when src/a.ts#run calls a helper in src/b.ts. GREEN finds the helper's owner. A focused regression test covers it, because the static grammar does not generate a cross-file owner.
  • The e2e oracle's constructed histories now pin a declaration and an owner. The new refusals had refused some of those histories before they reached their states.
  • Refusal order: CI on the merge commit found a defect. When a run owned nothing and had a bad owns entry, the CLI refused it as "no owner" and did not name the entry. RED: the static oracle, with a new reach state and a constructed history for that state, fails both seeds on the merge commit. GREEN: the analysis checks each entry before the no-owner refusal, and the fast gap oracles pass, 21 of 21. The e2e fixed seed passes. Mutant: the old order fails both seeds. The model now lists the refusals in the order the CLI finds them. The analysis refusals come first: a broken declaration, then no oracle file, then no owner. A fault that only the test runner can find comes after them.
  • Typecheck passes.

Review round

A high-effort code review found ten problems:

  • Moving the workspace bundles into the package broke how a dependency's own imports resolve under pnpm. That move is reverted, so bundles stay in each dependency's .oracle-gaps folder (a known limit, below).
  • A source that an oracle owns only through another file's call tree was refused. The refusal now runs after ownership is computed. A focused regression shows the fix.
  • oracleProperty now rejects an empty owns list.
  • The end-to-end pin forces only an owner, not whole-file ownership, and the constructed histories alternate the two declaration forms.
  • The changeset is minor, because it removes a public field.

Limits

  • declareOracle stays during the migration. TanStack DB moves owns into its oracleProperty calls, and then a later PR removes declareOracle.
  • Workspace bundles are still written into each dependency's .oracle-gaps folder. A dependency's imports must resolve from its own location.
  • Harness copies (.oracle-gaps-<pid>*) stay next to the package's config and tests, because Vitest needs them there. Add .oracle-gaps* to .gitignore. The daemon socket stays in the temporary folder, with a name from the package's hash.
  • An oracleProperty call whose owns the CLI cannot read (a spread, a computed list, a quoted key) makes the file an oracle file with no entries. If that file fails with no mutant active, the run stops with a misleading cause. The CLI reads only a direct call by the name oracleProperty, not an alias or a namespace member. Call it by its name, with a literal owns list.
  • Output directories under .oracle-gaps/out/ are not pruned yet.
  • The e2e oracle ran only the fixed seed for this change. CI runs it.
  • When no --seed is given, the CLI does not yet choose one seed for the whole run. That is a separate fix.

This pull request and its description were written by Isaac.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
KyleAMathews and others added 5 commits November 10, 2026 12:00
@KyleAMathews Isaac
refactor(oracles): remove law.owner
b81b7b6
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]>
@KyleAMathews Isaac
feat(oracles): take owns on oracleProperty
23a544c
`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]>
@KyleAMathews Isaac
feat(oracles): read owns from oracleProperty in the gap report
b9d048d
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]>
@KyleAMathews Isaac
feat(oracles): namespace each gap run's output and bundles under the …
e7b3531
…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]>
@KyleAMathews Isaac
chore: changeset for owns on oracleProperty and namespaced output
053a622
Co-authored-by: Isaac <[email protected]>
@changeset-bot

changeset-bot Bot commented Nov 10, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: e4dc69f

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@tanstack/oracles Minor

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

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@coderabbitai

coderabbitai Bot commented Nov 10, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown

Important

  • Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

Run configuration

  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: f72c0ee3-eff1-4925-8894-1d80e2a0e505
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

  • X
  • Mastodon
  • Reddit
  • LinkedIn
All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@KyleAMathews KyleAMathews mentioned this pull request Nov 10, 2026
docs(oracles): ship setup, design, and review skills, with a prompt to try them #7
Open
KyleAMathews and others added 7 commits November 10, 2026 16:03
@KyleAMathews Isaac
fix(oracles): reject an empty owns list in oracleProperty
73fe356
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]>
@KyleAMathews Isaac
fix(oracles): revert bundle relocation, pin one owner, document stray…
5ed5ae0
… 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]>
@KyleAMathews Isaac
fix(oracles): print the run's output path
62eabed
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]>
@KyleAMathews Isaac
fix(oracles): accept a source owned through another file's call tree
b78c83f
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]>
@KyleAMathews Isaac
chore(oracles): rename a regression local that shadows its import
5eca08e
Co-authored-by: Isaac <[email protected]>
@KyleAMathews
Merge remote-tracking branch 'origin/main' into feat/owns-harness-stops
60cb448
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
@KyleAMathews Isaac
fix(oracles): name a bad owns entry before the run's lack of an owner
e4dc69f
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]>
@pkg-pr-new

pkg-pr-new Bot commented Nov 11, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/TanStack/oracles/@tanstack/eslint-plugin-oracles@11
npm i https://pkg.pr.new/TanStack/oracles/@tanstack/oracles@11

commit: e4dc69f

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@KyleAMathews
KyleAMathews merged commit d1b508a into main Nov 11, 2026
8 checks passed

Uh oh!

There was an error while loading. Please reload this page.

@KyleAMathews
KyleAMathews deleted the feat/owns-harness-stops branch November 11, 2026 00:53
KyleAMathews added a commit that referenced this pull request Nov 11, 2026
@KyleAMathews Isaac
docs(oracles): the README example covers -0 and reaches zero gaps
6bf40d8
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]>
KyleAMathews added a commit that referenced this pull request Nov 11, 2026
@KyleAMathews Isaac
chore(oracles): drop the last law.owner lines in untyped oracle files
b467f32
#11 removed law.owner; two .js/.mjs oracle files that the typecheck does
not read kept the field.

Co-authored-by: Isaac <[email protected]>
KyleAMathews added a commit that referenced this pull request Nov 11, 2026
@KyleAMathews Isaac
feat(oracles): survivor classes with directive messages; short, strea…
5331fbd
…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]>
This was referenced Nov 11, 2026
test: adopt @tanstack/oracles d1b508a (owns on oracleProperty, no law.owner) TanStack/db#2407
Merged
feat(oracles): every gap CLI run ends in a report: refused (exit 2) or internal error (exit 3), never a stack trace #14
Merged
KyleAMathews added a commit that referenced this pull request Nov 11, 2026
@KyleAMathews Isaac
feat(oracles): every gap CLI run ends in a report: refused (exit 2) o…
5db40e8
…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]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

No reviews

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

1 participant

@KyleAMathews
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.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.