feat(pr-workflow): add lane-graphs — a router contract and three executable lanes - #107
Draft
MajorLift wants to merge 2 commits into
Draft
feat(pr-workflow): add lane-graphs — a router contract and three executable lanes#107MajorLift wants to merge 2 commits into
lane-graphs — a router contract and three executable lanes#107MajorLift wants to merge 2 commits into
Conversation
…cedure Determinism belongs on the envelope and not on the inquiry. Computing a merge-base, checking a probe loaded, verifying a mutation landed where it was aimed — none of that needs judgement, and all of it has been got wrong by hand. Which measurement answers a claim still does. Five nodes per graph, two of which exist only because they were missing when something published anyway: reading the treatment back off disk, and naming the observation it should produce. A run whose mutation silently changed shape, or that went red somewhere other than where it aimed, satisfied every other check. The router contract carries the part that keeps routing honest. A router over enough lanes always finds a best score, so no-match has to be a first-class result rather than a fallback into the nearest lane, and an unrouted read of the mechanism runs regardless of what matched — the catalog is a list of questions someone already thought of, and the findings worth having sit outside it. Three lanes converted from prose: mutation power, base-against-branch, and render delta. Each states its own blind spot in its output, because a green result that does not say what it declined to measure reads as broader than it is.
MajorLift
marked this pull request as draft
August 3, 2026 22:16
…aring a schema
The three .graph.json specs name an `executor` and nothing parses them. A run
could skip a node and still describe itself as having followed the graph,
because nothing held the description to the file — which is the failure the
whole package is about, one level up.
What this can and cannot do is worth being exact about, since overstating it
would reproduce that failure. The check, run and expect fields are natural
language; no interpreter evaluates them and this one does not pretend to. A
node's verdict is supplied by whoever ran it.
What is mechanised is the part that was actually being skipped:
- every node must carry a verdict
- a pass must name its evidence, because a pass with an empty evidence field
is a claim about a run, which is refused everywhere else in this package
- `absent` is a first-class outcome, reported rather than silently dropped
- a ledger entry naming no node in the graph is an error, not ignored
- a graph with an unanswered node cannot report complete
Structural validation refuses a graph missing a baseline or a prediction,
those being the shape of every vacuous run: a treatment applied to nothing, or
a result compared to no stated expectation.
graph-run.mjs <graph.json> validate structure
graph-run.mjs <graph.json> --scaffold emit a blank ledger
graph-run.mjs <graph.json> --ledger <l.json> check a filled-in ledger
Controls: all three graphs validate; blank ledger exit 1; fully answered exit
0; one node silently removed exit 1; pass with empty evidence exit 1; unknown
ledger entry exit 1.
This was referenced Aug 6, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds
lane-graphs: a router contract, three lanes converted from prose to executable graphs, and the interpreter that holds a run to them.Why
Today's evidence lanes are prose. A reader follows them by hand, and the mechanical parts get got wrong — repeatedly, in ways that produce a clean artifact:
$SHA^..$SHAinstead of the pull request's rangeawk -vescape processingNone needs judgement to check, and each is one node in a graph.
The split
Routing is judgement, execution is not. Choosing which measurement answers a claim requires reading the change. Computing a merge-base, verifying a probe loaded, reading a mutation back off disk — none of that requires reading anything.
Five nodes per graph, and a graph missing any is a script:
Reading the treatment back, and naming the prediction, exist because they were missing when something published anyway.
The router contract, and the two clauses that matter
No-match is a first-class result. A router over enough lanes always finds a best score. That score means nothing if nothing fit, and a graph run on a claim it does not measure produces a clean green answering a question nobody asked.
An unrouted read runs regardless of what matched. The catalog is a list of questions someone already thought of, so anything outside it is invisible to routing by construction. In the trial that produced this skill, the most valuable finding came from reading a mechanism rather than executing a lane — any router would have matched that change to its signature lane, run it, gone green, and stopped.
Plus: the route is published with the result, so a reader who disagrees with it can say so; and each graph states its own blind spot, because a green that does not say what it declined to measure reads as broader than it is.
Three graphs
assets/*.graph.json— declarative, executed byevidence's existing run workflow and runners:mutation-powerbase-branch-proofrender-deltaEach carries a
does_not_coverlist in its own output.What holds a run to the graph
A spec that names an
executorno one parses lets a run skip a node and still describe itself as having followed the graph — the failure this package is about, one level up.scripts/graph-run.mjscloses that.Worth being exact about its limits, since overstating them would reproduce the same failure. The
check,runandexpectfields are natural language. No interpreter evaluates them and this one does not pretend to — a node's verdict is supplied by whoever ran it. Routing stays judgement, as the router contract above says.What is mechanised is the part that was actually being skipped:
passmust name its evidence — a pass with an empty evidence field is a claim about a run, which is refused everywhere else in this packageabsentis a first-class outcome, reported rather than silently droppedStructural validation refuses a graph missing a
baselineor aprediction, those being the shape of every vacuous run: a treatment applied to nothing, or a result compared to no stated expectation.Exit 0 = valid / every node answered and passing. Exit 1 = a node failed, is unanswered, or the ledger does not match the graph. Exit 2 = usage or parse error.
When a lane should not get a graph
Graphs cost maintenance and drift silently — a defect can sit in one for weeks while every run looks correct. Build one when the measurement runs often, its preconditions have been got wrong by hand, and its result is checkable without interpretation. Leave prose where the interesting part is the reading: policy diffs, retention reviews, supply-chain disposition.
The downside, stated plainly
A deterministic graph makes wrongness consistent. A flaky procedure fails visibly; a deterministic one fails identically forever and reads as evidence. Two large graphs reviewed during this work were better engineered than anything here — reproducible, checksummed, hundreds of nodes — and their assertions keyed on a per-case sentinel rather than on absence, so a regression leaking a different value passed every run. This skill does not solve that. It asks each graph to publish what it did not measure, which is the smallest honest mitigation.
Depends on
evidence(#84) for the runners and the run workflow, andfalsifiers-first/instrument-check/coverage-partition(#106) — four## Relatedlinks resolve on their merge.Test plan
node .github/scripts/lint-skill-entry.mjs— 0 errorsnode --test test/*.test.mjs— 61/61Controls on the interpreter:
absent)UNANSWERED baselinepasswith empty evidenceAn earlier version of those controls reported three false passes:
echo "$(printf ...) exit=$?"resets$?via the command substitution before it is read, so the controls were measuringprintf. Worth recording, given what this script is for.This branch alone does not work
The installer resolves one source directory. It does not follow
## Relatedas a dependency edge, does not fetch other refs, and reports a dangling reference as a warning rather than an error — because forward references across open pull requests are expected. So a checkout of this branch installs only the skills on it, with every cross-branch reference dead.To get a tree that actually runs:
Merges clean onto
main. Yields all elevenpr-workflowskills plusevidence, and lints at 0 errors. Three## Relatednames still dangle —react-render-delta,race-condition-repro,lavamoat-policy— because those engines ship in #43, #97 and #83.Worth knowing that the combination is also where defects surface: an error caught only with #99 and this set together — a description advertising a command the installer does not emit — passes on every branch individually.
Draft: these files are pending removal
The three
assets/*.graph.jsonfiles on this branch have moved to a standalone runners repository (v0.1.0). That repository is the source; the copies here are temporary. They remain only so this branch can be run and tested on its own while the extracted repository is reviewed.Once that review lands, they come out and the skill references the runners by pinned tag.
Why the interim needs watching. Two copies of these files is the arrangement that already failed: CI executed the runners from a branch by ref, four fixes landed on the copy it was reading, and none reached the copy under review — including a mutation runner that rewrote the line it was asked to apply, reported the full suite as having run, and published a falsification for a mechanism it never touched. That fix is cited in this description and was, until it was reconciled, still live in the code this branch ships.
So while both copies exist:
The graphs are not in that comparison yet — they were copied after it was written. A copy made without adding it to the check is a copy nobody is watching, which is the failure in miniature.
What is still open, and it is layout rather than content. A graph reads as documentation and executes as configuration, so whether it belongs to the skill or the runners has not been settled — and the interpreter that reads them inherits the same open question. The router contract, the five-node shape and the ledger rules do not depend on that call and are reviewable now.