/todo/DIFF/DIFF-016 landed the conflict render, but its whole axis is gated on PATCH rows: expectedCtx returns null when patchTheirs() is empty, and a merge-get writes no patch row. So a conflicted file diffs as ordinary green/red — the woven both-sides tokens are indistinguishable from a hand edit, which is exactly what /todo/DIS/DIS-080 made the diff view responsible for. The wtlog already carries the two pointers the EXPECTED reading needs; nothing new has to be written.
views/diff/diff.js:392-398 — expectedCtx() starts with expected.theirsShas(log) and returns null on an empty list; shared/expected.js:22-25 — that list is wtlog.patchTheirs(), PATCH rows only.views/diff/diff.js:398 builds cons: log.conflicts() and NOTHING reads it —
grep finds no consumer, though /todo/ULOG/ULOG-004 goal 2 named the diff yellow spans as one.f.txt woven to XY): diff --color paints 48;5;217 + 48;5;157, the LOCAL rm/in washes; no 153/117 blue-orange, no 229/227 yellow.be/test/diff/20-patch-conflict PASSes with cq 227 — a patch-row conflict does wash yellow.curTip IS theirs (measured 56cfcde0) and the barrier row before it names the pre-get base (fc8ff3f3) — the same backward scan conflicts() already runs stops on exactly that row.put row is path-only, no blob sha), and the EXPECTED model never needs them — the ours axis is "wt != EXPECTED".A live con path diffs in CONFLICT MODE, rendered identically to patch mode.
be/test/diff/20-patch-conflict (asserts cq 227) regolds, patch-mode output changes too.conflicts() returns the barrier sha and the pre-barrier tip alongside each path (accessor change, NO new ulog rows).shared/expected.js expectedOf(k, path, base, shas, cache) is reused as-is with base = the pre-get tip and shas = [the get's sha].--plain output stays byte-identical — provenance is a COLOUR distinction, asserted on --color SGR digits (DIFF-016's deliberate no-fallback ruling).con row stays path-only unless gritzko rules otherwise — base+theirs are derivable from row order.conflicts() stays: with yellow gone, the file-level
conflict signal is status ! + the banner, so it is load-bearing, not a fallback.conflictOrigins() → [{path, base, theirs}]); conflicts() KEEPS returning bare paths — post.js:886 and classify string-test it, and a shape change means a lockstep edit in two parallel ticketsexpectedCtx from that when patchTheirs() is empty; keep the patch arm untouchedec.cons — the path-granular cross-check DIFF-016 specified and never wired20-patch-conflict regolds off yellow, --plain byte-identical, pty renderrow that ROUTES here reads as an ordinary edit; the nav itself already spells diff <path>.