spec: J3 checked over every build of four files, not argued (#179) - #226
Merged
Merged
Conversation
The J3 proposition was the one claim in this repository that asserted instead of gating. Rule-to-fixture coverage is checked both ways, `UNCOVERED.md` is shrink-only, and `corpus.test.ts` carries three assertions whose only job is to stop a vacuous pass. J3's proposition had a nine-line prose sketch, and #180 found two defects in it by reading. `spec/taint-model.test.ts` enumerates every build of four files and checks the claim on each. 8,503,056 of them: every import relation excluding self-imports, every capture relation inside that import relation, and every assignment of J2 tentative verdicts. Relations are bitmasks and each check collects counterexamples rather than asserting per build, which is the difference between three seconds and several minutes. WHAT IS CHECKED. T(B) is closed under Succ. A running file never leaves a folded file below it, which is the forward edge. A capturer never outlives what it captured from, which is the backward edge. No running file holds a second object of a folded file's entity, which is the proposition in case 1's form. FOUR VACUITY GUARDS, because a check nothing can fail is a picture. The instance #179 asked for by name: a file that imports a running module and never references the binding still folds. Taint flows from a tainted file to what it IMPORTS and never to its importers, so this has to exist, and case 2 of the sketch asserted the opposite. A model that cannot produce it is not modelling this specification. Deleting the forward edge breaks a check. Deleting the backward edge breaks a different one. Neither is decorative. The lemma `f ⇝ g` implies `f → g` is shown load-bearing by exhibiting the build it excludes: a capture that is not an import, where the capturer runs and reconstructs the entity while the captured-from file still folds and holds its own. `taint.md` states the lemma and never checked it. NOT ALLOY, which #179 proposed. The method is what matters: enumerate every build in a bounded scope and check the claim rather than read a proof. Bounded enumeration does that in the suite everything else runs in and adds no Java toolchain to CI. The scope is stated the way F-Depth's bounds are, because a bounded check that does not say its bound is worth nothing. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AzfJnYw9p6rAxhJqXK3CPv
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #179, by a different instrument than it proposed. Reasoning below — redirect me if you disagree.
The gap it names
That's right. Coverage is checked both directions,
UNCOVERED.mdis shrink-only,corpus.test.tshas three anti-vacuity assertions. J3's proposition had prose, and #180 found two defects in it by reading.Not Alloy
#179 proposed an Alloy model. The method is the thing, not the tool — as the issue itself puts it, "Alloy does not read proofs, it checks claims". Bounded exhaustive enumeration does exactly that, runs in the suite everything else runs in, and adds no Java toolchain to CI.
Scope, stated the way
F-Depth's bounds are: every build of four files — every import relation excluding self-imports, every capture relation inside it, every assignment of J2 tentative verdicts. 8,503,056 builds, verified as exactly3^(n²−n) × 2^n. A cycle, a diamond, and a chain of three with a capture across it all fit inside four. Runs in 3.4s.What is checked
T(B)is closed underSuccFour vacuity guards
The instance #179 asks for by name. A file that imports a running module and never references the binding still folds. Taint flows from a tainted file to what it imports, never to its importers — so this must exist, and case 2 of the sketch asserted the opposite (#180's second defect). A model that cannot produce it isn't modelling this specification.
Each edge is load-bearing. Delete the forward edge and a check fails; delete the backward edge and a different one fails. Neither is decorative.
The lemma is load-bearing.
f ⇝ gimpliesf → gis stated intaint.mdand never checked. The model exhibits the build it excludes: a capture that is not an import, where the capturer runs and reconstructs the entity while the captured-from file still folds and holds its own. Two objects for one entity, which is what the proposition forbids.One implementation note
The first version called
expect()inside the enumeration and took longer than a 10-minute timeout. Relations are bitmasks now and each check collects counterexamples for a single assertion — three seconds instead of minutes. Worth knowing if anyone widens the scope later.taint.mdgains three lines pointing at the check and its scope.Verification
121 tests in 19 files, typecheck clean, voice gate clean, prose lint 51 with no regressions,
npm run docs:buildclean.🤖 Generated with Claude Code
https://claude.ai/code/session_01AzfJnYw9p6rAxhJqXK3CPv