diff --git a/drawfence.go b/drawfence.go index d1ebc31..77d9a25 100644 --- a/drawfence.go +++ b/drawfence.go @@ -225,7 +225,8 @@ func newDrawWalk() *drawWalk { } // walk follows what rendering n renders. A repeat renders over draws of its own, so the walk stops -// there. +// there. A cell whose row the pins keep out has no case: a pinned table renders its pinned row +// alone, so that cell never renders on this route. func (w *drawWalk) walk(n node, at drawAt) { v := nodeVisit{n, at.group, at.rowsKey()} if w.seen[v] { diff --git a/family.go b/family.go index a8003bf..a4f9929 100644 --- a/family.go +++ b/family.go @@ -103,8 +103,9 @@ func checkFamilies(reads []pathRead) error { } // replayPairs replays every two reads of one draw group that can render together into -// one draws, the earlier read first. A pin conflicts with one earlier pin, never with a -// combination, so pairs find every conflict a full replay would. +// one draws, the earlier read first. Pairs find every conflict a full replay would: a +// read pins a row's ancestors with it, and clash judges a row against one pinned table, +// so a conflict is between two reads' pins and a third read adds nothing to it. func replayPairs(reads []pathRead) error { for i, r := range reads { if r.tr == nil { @@ -216,8 +217,9 @@ func checkOwnFamily(t *template) error { return nil } -// alternatives reports whether two reads sit in different rows of one table: rows the walks pinned, -// or rows of one whole draw. +// alternatives reports whether two reads never render together: one read renders one row of a +// table, so reads under different rows the walks pinned, or under different rows of one whole +// draw, never meet. // docs/decisions.md#the-rows-of-a-table-are-alternatives func alternatives(a, b drawAt) bool { return a.pins.differs(&b.pins) || a.wholePins.differs(&b.wholePins) diff --git a/holdfence.go b/holdfence.go index b6dea2f..e249fb5 100644 --- a/holdfence.go +++ b/holdfence.go @@ -18,7 +18,7 @@ func heldCheck(path string, n node) error { readers := boundReaders(t.ops, t.bound) for _, head := range heldHeads(t) { if _, isPath := t.bound[head]; isPath && isRef(head) { - continue + continue // held for the render: drawCheck compares it across the render and its groups } if err := checkHeadHeld(t, head, readers); err != nil { return fmt.Errorf("%s: %w", path, err) diff --git a/todo.md b/todo.md index 793e5f5..8c1298b 100644 --- a/todo.md +++ b/todo.md @@ -21,11 +21,6 @@ Self-sufficiency 5.6), every seat capped by Locality, and all nine naming This round, in order: -- State at each draw fence, in one line at the code, the rule it enforces, where a - `docs/decisions.md` link stands in for it today: the clash drop in `drawWalk.walk`, - `alternatives`, `replayPairs`' claim that pairs find every conflict, and - `heldCheck`'s skip of a reference path. Seven seats could not say why the fences - are complete without the decision bodies. - Hold the draw fences to what render does: a test rendering seeded draws that fails where a read the render makes falls outside what `drawWalk` gathered. Today the two models agree by a comment on `renderEdges`, and a new render route drifts silently.