Skip to content

Commit e8f0c39

Browse files
jitokimoh-my-graph
andauthored
feat(graphs): every batch-lane rule now ends in a disposition (#237)
* docs(measurements): rule 1 fires once in 45 graphs, and that once is noise Measure the batch-lane survey memo's rule-1 candidate — "two lanes in one graph must not touch the same file" — before any lint is written, because this repo rejected a predicate at 110 noise in 114 hits two days ago and an unmeasured noise rate does not ship here. The probe parses, never greps: shipped graphs go through graph.LoadFile so every fragment `use:` is spliced before a node is counted, and each planned graph.json in the operator corpus goes through graph.Parse. Population 45 graphs (8 shipped + 37 planned from 339 run directories), 216 resolved nodes. The number that decides it is not the hit count but the firing population: 1 of 45 graphs declares two lanes. Not one planned graph declares a lane at all, and cannot — validatePlannedNodeWorktree rejects `worktree:` on an unreviewed plan — so no amount of extra operator history would grow it. The single hit is CONTRIBUTING.md, quoted by both lanes as the address of a commit-trailer convention and edited by neither: 1 noise in 1 hit. Even at zero noise the predicate would judge text it cannot see, since which files a lane owns arrives in --input and `lint` takes no --input. Every narrowing that would clear the hit is fitted to it and re-measured against the same one graph, and a test over shipped graphs only would be red today for the same reason. VERDICT: DO-NOT-SHIP. Rule 1 stays prose. Nothing in the engine changes: the probe carries //go:build ignore, so `go build ./...` and `go test ./...` do not see it. Signed-off-by: jitokim <pigberger70@gmail.com> Co-Authored-By: oh-my-graph <graphs@oh-my-graph.dev> * test(graphs): the three batch-lane rules a parser can decide become assertions The survey memo triaged the six hard-won rules in graphs/backlog-batch.yaml's header. Three of them have a predicate that reads only declared fields, and until now nothing held them: the header stated them, and drift was free. Rule 5 — independent lanes fail independently. Weakly connected components of `depends_on` over the RESOLVED graph (lane A is one authored node that splices into four, so the file's `nodes:` list reads 2 where the run has 8); two or more components must come with `on_fail: continue`. Measured over the eight shipped templates: exactly one is multi-component — backlog-batch — and it declares it at :84. Rule 3 — cold-safe session prompts. `handoff: session` + `retry` starts the retried attempt cold; LintSessions already warns about it, and stays advisory. What is checkable is that the wording which survives a cold attempt exists once, in e2e-verify, and that every shipped gate of this shape CITES it rather than restating it. Four do: lane-a/e2e, e2e-b, and dev-review-pr's and self-dev's e2e. Rule 1 residual — a node with no `worktree:` in a graph whose other nodes have one runs in the user's own tree, so it shares files with every lane at once. That is the one collision the schema can decide; the rest of rule 1 stays prose, measured in docs/measurements/0034 (DO-NOT-SHIP). All three are tests over graphs/, never lint sweeps. A new sweep owes a measured noise rate and the corpus that could produce one does not exist — n=1 across everything this repo ships — and each rule's named false positive (a deliberate fail-fast batch, an honest hand-written cold-safe prompt, a coordinating node outside every lane) is a legitimate graph a warning would reach a user with. Here the cost is a CI failure the rule's own author fixes. Each carries the zero-population guard the gating-review test already uses: if the shape it judges disappears from graphs/, the test says so instead of passing while asserting nothing. Each was confirmed to bite by mutating backlog-batch.yaml — halt, a lane-less dev-b, a hand-written e2e-b — and the mutation was reverted. Signed-off-by: jitokim <pigberger70@gmail.com> Co-Authored-By: oh-my-graph <graphs@oh-my-graph.dev> * test(graphs): the gate pair is symmetric, and now the test that pins it is too "Ship both or neither" is stated three times in the graphs — backlog-batch's rule 6, review-style.yaml, gated-lane.yaml — and TestAGatingReviewCarriesItsRecoveryArc held only one direction of it. A narrowed check with no arc failed the test. An arc with no narrowing hit the `continue` on the advisory branch and passed. That half is not symmetric decoration. A `feedback:` arc on a review whose success_check still accepts `FINDINGS:` cannot be reached by the verdict it was written for, so the finding it was meant to repair rides into the PR body instead — while the graph, and the run's disclosure line, read like a lane that gates. Stated exactly, because "the arc never fires" would be one word too strong: a review fragment declares no `verify`, so nonzero_exit and a reply that is neither verdict can still reach the arc. Re-running the implementer over a crashed or malformed review repairs nothing, because nothing was found. Dead as a repair round is the claim, and it is the claim the doc comment makes. No shipped graph is in this shape today — lane B advises with no arc, on purpose — so this fires on nothing and guards the next author. Confirmed to bite by giving review-b an arc; the mutation was reverted. Signed-off-by: jitokim <pigberger70@gmail.com> Co-Authored-By: oh-my-graph <graphs@oh-my-graph.dev> * docs(graphs): every batch-lane rule now ends in a disposition Three of the seven rules name the check that enforces them and whether it warns or refuses; four say in one sentence why they are judgement and stay prose. Rule 1's disposition carries the measurement that rejected its lexical form (1 hit, 1 noise, DO-NOT-SHIP) rather than implying the rule is checked; what survives of it is one test that reads no paths at all. Rule 7 also settles the fragment question so the next author does not reopen it: the lane shape is already graphs/fragments/gated-lane.yaml, and a second lane fragment is not merely redundant — its dev prompt quotes {{ feedback.review }}, which is a load error for a citing node that declares no arc, so an advisory lane cannot cite it at all. Header and comments only: every changed line in this diff begins with `#`, and both runtimes' lint output for the graph is byte-identical to before. Signed-off-by: jitokim <pigberger70@gmail.com> Co-Authored-By: oh-my-graph <graphs@oh-my-graph.dev> * docs(changelog): the batch-lane formalisation, including what it refused to ship One Unreleased entry under Documented. It names the three tests that now enforce rules 3, 5 and 6 over graphs/, the advisory lint that already covered rule 3's risky shape, and the four rules that stay prose with the reason each. The entry carries the measurement rather than only the outcome: 1 hit and 1 noise across 45 graphs and 216 resolved nodes, verdict DO-NOT-SHIP, with the path to docs/measurements/0034-lane-file-ownership-predicate.md and the command that recomputes it. A changelog that reported only the tests would read as if rule 1 had been checked. No release, no tag, no version string touched. Signed-off-by: jitokim <pigberger70@gmail.com> Co-Authored-By: oh-my-graph <graphs@oh-my-graph.dev> --------- Signed-off-by: jitokim <pigberger70@gmail.com> Co-authored-by: oh-my-graph <graphs@oh-my-graph.dev>
1 parent d7efe95 commit e8f0c39

5 files changed

Lines changed: 979 additions & 9 deletions

File tree

CHANGELOG.md

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,61 @@ oh-my-graph is **alpha software**. The graph YAML schema, the CLI, and the
144144

145145
### Documented
146146

147+
- **Every rule in the batch-lane idiom now ends in a disposition: the check
148+
that enforces it, named, or one sentence saying why it is judgement**
149+
([`graphs/backlog-batch.yaml`](graphs/backlog-batch.yaml)). The header stated
150+
seven hard-won rules and left a reader to guess which of them anything
151+
enforced — a rule with a test behind it read exactly like one no code has
152+
ever looked at.
153+
154+
Three rules are mechanically checked, all three as tests over `graphs/` in
155+
`internal/graph/shipped_graphs_test.go`, so a violation fails THIS repo's
156+
build rather than warning at a user's own graph:
157+
`TestIndependentLanesFailIndependently` (rule 5 — two or more weakly
158+
connected components in the resolved graph must come with
159+
`on_fail: continue`), `TestASessionGateCitesTheColdSafeFragment` (rule 3 — a
160+
node that resumes a session and retries must have spliced `e2e-verify`, where
161+
the cold-safe wording exists once), and
162+
`TestAGatingReviewCarriesItsRecoveryArc`, extended to rule 6's second half:
163+
it already refused a narrowed review check with no `feedback:` arc, and now
164+
equally refuses an arc on a node whose check still accepts `FINDINGS:` — an
165+
arc the failing verdict can never reach. Rule 3's risky shape keeps its
166+
existing advisory warning from `handoff.LintSessions`; the test guards only
167+
what the warning cannot, that the wording has not been copied out by hand.
168+
169+
Rules 2, 4 and 7 stay prose, each saying why in the header: rule 2 would have
170+
to read prompt prose for an instruction, the predicate family this repo
171+
measured and rejected at 110 noise in 114 hits
172+
([`docs/measurements/0213-tool-grant-predicate.md`](docs/measurements/0213-tool-grant-predicate.md));
173+
rule 4's subject is a lane's diff, which does not exist when a graph is
174+
loaded; and rule 7 asks whether a repeat is a shape or a difference in a key,
175+
which is the judgement it exists to provoke.
176+
177+
Rule 1 — "lanes must not share files" — stays prose too, and was measured
178+
before it was written off, in
179+
[`docs/measurements/0034-lane-file-ownership-predicate.md`](docs/measurements/0034-lane-file-ownership-predicate.md).
180+
Over 45 graphs and 216 resolved nodes, only one graph can fire the predicate
181+
at all (a planned graph may not declare a `worktree:`), and the lexical form
182+
produced **1 hit, of which the hand-check made 1 noise** — both lanes cite
183+
`CONTRIBUTING.md` as the address of the commit-trailer convention and neither
184+
edits it. Verdict: DO-NOT-SHIP. The command is the address for those numbers:
185+
186+
```sh
187+
go run docs/measurements/0034-lane-file-ownership-predicate.go
188+
```
189+
190+
What survives of rule 1 reads no paths at all and is a test:
191+
`TestAWorktreeGraphLeavesNoNodeOutsideALane` refuses a graph that declares
192+
lanes and leaves some node without one, since that node runs in the user's
193+
own tree and so shares files with every lane at once.
194+
195+
No new `lint` sweep and no new load error — a new warning owes a measured
196+
noise rate, and the corpus that could measure one is n=1 across everything
197+
this repo ships. The header also settles the fragment question so it is not
198+
reopened: the lane shape is already a fragment,
199+
[`graphs/fragments/gated-lane.yaml`](graphs/fragments/gated-lane.yaml), and
200+
no second lane fragment is coming. Nothing in the graph body changed, and
201+
both runtimes' `lint` output for the eight shipped graphs is unchanged.
147202
- **ADR 0033 — the run, not the node, is the unit of engine-run evidence, and
148203
ADR 0030 is deliberately not extended one level down**
149204
([`docs/adr/0033-the-run-is-the-unit-of-evidence-not-the-node.md`](docs/adr/0033-the-run-is-the-unit-of-evidence-not-the-node.md),

0 commit comments

Comments
 (0)