`bnode`'s header still said the generator "has to move together, and it needs
write-side capability this seam does not have". It has moved, and `origin` was
the write-side answer, so the section described a state two commits out of date —
the kind of stale map that sends the next person looking for a problem that is
already solved. Rewritten to say what runs on a cursor now, that `origin` is what
keeps `TLoc.lode` a `PNode`, and that the generator's own in-place rewrites run
on the origin (with the hazard spelled out: where a mutation is read back,
generation has to continue on the origin, because the buffer is a snapshot).
Two blockers were also described wrongly:
* THE ALIAS FAMILY is no longer blocked by field identity — that is exact on a
bridged buffer. I checked whether `isPartOf` could migrate now and it cannot,
for a different reason: every call site passes `d.lode` as one operand and that
is a `PNode`, so a generic `isPartOf` would still be handed a `PNode` on one
side and buy nothing. It moves when `TLoc.lode` does.
* `sym`'s note said `isPartOf` "CANNOT be migrated as written" without
qualifying that this is a FILE-path property; a bridged buffer hands back the
object it was given, and the grinder asserts exactly that.
And the cost, which I flagged twice as unmeasured and is now measured on a
50-module target:
baseline (PNode) 6.75s
bridge built, not read 6.79s -- encoding is inside the noise
generator driven off it 8.85s -- +31%
So the encoder is as cheap as claimed and the whole cost is in READING: `son` is
O(i), `kind` indexes a memo per call, `sym`/`typ` go through the nav, `origin` is
a hash lookup per location built. None of it is inherent and none of it has been
optimised. Since a compile is mostly frontend, codegen itself is slowed by well
over 31%.
Verified: both configurations build; cursor-driven and `PNode`-driven output
still identical.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XEF7FJvUkGKvG9LSGuEaNR