@@ -167,6 +167,61 @@ oh-my-graph is **alpha software**. The graph YAML schema, the CLI, and the
167167
168168### Documented
169169
170+ - ** Every rule in the batch-lane idiom now ends in a disposition: the check
171+ that enforces it, named, or one sentence saying why it is judgement**
172+ ([ ` graphs/backlog-batch.yaml ` ] ( graphs/backlog-batch.yaml ) ). The header stated
173+ seven hard-won rules and left a reader to guess which of them anything
174+ enforced — a rule with a test behind it read exactly like one no code has
175+ ever looked at.
176+
177+ Three rules are mechanically checked, all three as tests over ` graphs/ ` in
178+ ` internal/graph/shipped_graphs_test.go ` , so a violation fails THIS repo's
179+ build rather than warning at a user's own graph:
180+ ` TestIndependentLanesFailIndependently ` (rule 5 — two or more weakly
181+ connected components in the resolved graph must come with
182+ ` on_fail: continue ` ), ` TestASessionGateCitesTheColdSafeFragment ` (rule 3 — a
183+ node that resumes a session and retries must have spliced ` e2e-verify ` , where
184+ the cold-safe wording exists once), and
185+ ` TestAGatingReviewCarriesItsRecoveryArc ` , extended to rule 6's second half:
186+ it already refused a narrowed review check with no ` feedback: ` arc, and now
187+ equally refuses an arc on a node whose check still accepts ` FINDINGS: ` — an
188+ arc the failing verdict can never reach. Rule 3's risky shape keeps its
189+ existing advisory warning from ` handoff.LintSessions ` ; the test guards only
190+ what the warning cannot, that the wording has not been copied out by hand.
191+
192+ Rules 2, 4 and 7 stay prose, each saying why in the header: rule 2 would have
193+ to read prompt prose for an instruction, the predicate family this repo
194+ measured and rejected at 110 noise in 114 hits
195+ ([ ` docs/measurements/0213-tool-grant-predicate.md ` ] ( docs/measurements/0213-tool-grant-predicate.md ) );
196+ rule 4's subject is a lane's diff, which does not exist when a graph is
197+ loaded; and rule 7 asks whether a repeat is a shape or a difference in a key,
198+ which is the judgement it exists to provoke.
199+
200+ Rule 1 — "lanes must not share files" — stays prose too, and was measured
201+ before it was written off, in
202+ [ ` docs/measurements/0034-lane-file-ownership-predicate.md ` ] ( docs/measurements/0034-lane-file-ownership-predicate.md ) .
203+ Over 45 graphs and 216 resolved nodes, only one graph can fire the predicate
204+ at all (a planned graph may not declare a ` worktree: ` ), and the lexical form
205+ produced ** 1 hit, of which the hand-check made 1 noise** — both lanes cite
206+ ` CONTRIBUTING.md ` as the address of the commit-trailer convention and neither
207+ edits it. Verdict: DO-NOT-SHIP. The command is the address for those numbers:
208+
209+ ``` sh
210+ go run docs/measurements/0034-lane-file-ownership-predicate.go
211+ ```
212+
213+ What survives of rule 1 reads no paths at all and is a test:
214+ ` TestAWorktreeGraphLeavesNoNodeOutsideALane ` refuses a graph that declares
215+ lanes and leaves some node without one, since that node runs in the user's
216+ own tree and so shares files with every lane at once.
217+
218+ No new ` lint ` sweep and no new load error — a new warning owes a measured
219+ noise rate, and the corpus that could measure one is n=1 across everything
220+ this repo ships. The header also settles the fragment question so it is not
221+ reopened: the lane shape is already a fragment,
222+ [ ` graphs/fragments/gated-lane.yaml ` ] ( graphs/fragments/gated-lane.yaml ) , and
223+ no second lane fragment is coming. Nothing in the graph body changed, and
224+ both runtimes' ` lint ` output for the eight shipped graphs is unchanged.
170225- ** ADR 0033 — the run, not the node, is the unit of engine-run evidence, and
171226 ADR 0030 is deliberately not extended one level down**
172227 ([ ` 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 ) ,
@@ -202,6 +257,37 @@ oh-my-graph is **alpha software**. The graph YAML schema, the CLI, and the
202257 while ` cmd/oh-my-graph/version.go:9 ` reads ` 0.11.0 ` . The clause that survived
203258 the deletion is the true half: a run that types nothing is byte-for-byte the
204259 run that shipped in v0.10.0.
260+ - ** ` graphs/backlog-batch.yaml ` 's header diagrammed four nodes the graph no
261+ longer has, and its rule 1 advised an edit that will not load.** ADR 0029
262+ folded lane A into a single ` use: gated-lane ` node, and commit ` d232ce4 `
263+ deleted ` dev-a ` /` e2e-a ` /` review-a ` /` pr-a ` — but that commit's diff on this
264+ file begins at ` @@ -45,15 +45,24 @@ ` , so it never reached the header. The
265+ runtime ids are ` lane-a/dev ` , ` lane-a/e2e ` , ` lane-a/review ` , ` lane-a/pr ` , as
266+ the file's own body comment already said (` graphs/backlog-batch.yaml:88 ` ) and
267+ as loading it prints:
268+
269+ ``` sh
270+ go run ./cmd/oh-my-graph run graphs/backlog-batch.yaml --dry-run \
271+ --input repo=/tmp --input checks_command=" make local" \
272+ --input task_a=x --input task_b=y
273+ # Graph "backlog-batch" (8 nodes): lane-a/dev, lane-a/e2e, lane-a/review,
274+ # lane-a/pr, dev-b, e2e-b, review-b, pr-b
275+ ```
276+
277+ The second line was worse than stale. Rule 1 offered "make dev-b depend on
278+ ` pr-a ` " as the way to serialize two overlapping tasks, and `depends_on:
279+ [ pr-a] ` is a load error — ` depends_on unknown node`,
280+ ` internal/graph/validate.go:454 ` — so a reader who took the advice got a
281+ graph that would not run. It now names ` lane-a/pr `
282+ (` graphs/backlog-batch.yaml:16 ` ). ` init ` emits this file and users copy it,
283+ which is why a stale comment here is a stale instruction to a stranger.
284+
285+ Comments only: no node, prompt, or key changed, the graph still validates at
286+ 8 nodes, and no verdict clause moved, so the qualifier sweep's counts are
287+ untouched. The remaining thirteen shipped graphs and fragments were audited
288+ against v0.11.0 in the same pass and left alone — none of them names ` auto ` ,
289+ so neither ` --accept-loaded-user-config ` nor anything else new in v0.11.0
290+ reaches them.
205291
206292## [ v0.11.0] - 2026-08-21
207293
0 commit comments