Dane Sabo d8d5dd9c17 Shared-vertex registry on ParcelSet (no-drift guarantee)
The first half of the eventual full DCEL — vertex identity. Every
parcel polygon vertex now resolves to a stable VertexId via a
spatial-hash lookup at EPS_GEOM resolution. Coincident positions
across two parcels resolve to the same VertexId, so adjacent
parcels share one physical vertex.

ParcelSet::move_vertex(vid, new_pos) updates the registry's
position AND writes through to every parcel's polygon at the
recorded index. Adjacent parcels' shared boundaries can never drift
apart — they are the same vertex, mutated once.

The deform pipeline now propose-then-apply: deform_parcel_after_road_move
returns proposed (VertexId, new_pos) moves rather than mutating in
place. The outer loop validates each parcel's hypothetical
post-move polygon, then applies all proposed moves via
move_vertex. Conflicting proposals on the same vertex are
last-one-wins, but in practice the deform parameterization makes
all referrers agree by construction.

New regression test: shared_vertex_no_drift_under_repeated_edits.
50 small random node moves plus an inverse; asserts every shared
boundary vertex is bit-for-bit identical across every parcel that
references it.

Edge identity (parcel-layer half-edges) is the next milestone — it
enables split/merge ergonomics. Vertex identity alone is enough
for the no-drift contract this session was scoped to deliver.

Journal §11 session 4 entry adds D17 (registry), D18
(write-through), D19 (propose-then-apply), and the milestone-0.5
queue.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 15:23:13 -04:00
..