docs(simulation): PR #218 round 3 — the round-2 fix outran its own documentation

Three findings, all doc-accuracy, and all the same root cause: folding the
spacing predicate into the ring walk changed what three comments describe, and
two of those comments were written by this same PR one round earlier.

TYRE 1 — road_graph.rs's T-1206 gap-closure comment cited `nearest_land_cell`,
which round 2 made `#[cfg(test)]`. A reader chasing that name lands on a
test-only function and reasonably wonders whether they are looking at dead
code. Repointed to `nearest_cell_matching`, and the paragraph's closing claim
that "T-1206 guarantees the placement pixel is land" is corrected: it has been
land-AND-spacing-or-skip since round 2.

TYRE 2 — `max_land_search_ring`'s doc named the same test-only wrapper as the
thing that walks the bound. It now names the production consumer and both
callers.

TYRE 3 — the D-211 amendment was written in round 1, before round 2 existed,
and still described a land-only correction. It now carries a dated refinement
recording what the code actually does: the walk satisfies BOTH of step 4's
promises in one search, and SKIP therefore also fires where land exists but
none of it clears spacing within the bound. The no-re-decision conclusion is
unaffected — position remains a deterministic, non-fabricated function of seed
and terrain — and the refinement notes the spacing promise is step 4's alone,
since Tier A/B/C placements sit on their matched attractor and were never
subject to it.

HOSHE's three findings were the same three hunks, observed uncommitted while
the review ran: accurate content, but not in the branch tip, so the PR would
have merged a governance record that misdescribes its own commit. That is this
commit.

Both reviewers independently confirmed what the round-2 fix claims. Tyre traced
the ring geometry and tie-break order by hand against the spacing predicate;
Hoshe re-ran the full 267-body corpus scan live (850s) and reproduced the
figures exactly — 267 bodies, 267 reaching Layer 3, 344 placements, 109
synthetic, 0 in water, 0 spacing violations.

The shared-ring-search-helper retraction is confirmed and settled, with NEW
grounds rather than a restatement: round 2 strengthened the case for keeping
them separate, since this walk is now parameterized by an arbitrary predicate
over native u16 terrain coordinates while road_graph's is a RouteGrid method
over downsampled routing cells with a fixed cost test and an unrelated bound.

22 module tests green; clippy and fmt clean.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-08 10:53:33 +02:00
co-authored by Claude Opus 5
parent fc55bd897f
commit d5e617eff6
3 changed files with 21 additions and 12 deletions
+4 -2
View File
@@ -268,8 +268,10 @@ fn hungarian(cost: &[Vec<i64>]) -> Vec<usize> {
const MIN_SPACING: u16 = 15;
/// T-1206 — ocean-mask guard search bound. Bounded ring-expansion search
/// radius (cells) `nearest_land_cell` will walk from a water-arithmetic
/// synthetic position before giving up.
/// radius (cells) [`nearest_cell_matching`] will walk from a water-arithmetic
/// synthetic position before giving up. That is the production consumer —
/// reached from `synthetic_attractor` with the land+spacing predicate, and
/// from the test-only `nearest_land_cell` wrapper with a trivial one.
///
/// **Sized empirically, not by analogy.** An early draft mirrored
/// `road_graph::COASTAL_ANCHOR_MAX_RING` (3) scaled up an order of magnitude
+14 -9
View File
@@ -104,18 +104,23 @@ const MIN_CELL_COST: u32 = RIVER_COST;
/// the fix). `synthetic_attractor` now takes an `Option<&TerrainAnalysis>`
/// and, when supplied, guards the arithmetic position: already-land stays
/// byte-identical (verified unmoved on all 63 real land-arithmetic
/// placements), water gets nudged to the nearest land cell via a
/// deterministic ring-walk (`nearest_land_cell`, the same tie-break pattern
/// as this file's own `nearest_passable_cell` below, at native/working-grid
/// resolution rather than the routing grid's downsample), and a city with no
/// land within the bounded search radius is SKIPPED entirely (never
/// fabricated, never a panic — reported via the existing Phase-5
/// name-fulfillment warning). This routing relaxation still degrades
/// placements), water gets nudged to the nearest acceptable cell via a
/// deterministic ring-walk (`nearest_cell_matching`, the same tie-break
/// pattern as this file's own `nearest_passable_cell` below, at
/// native/working-grid resolution rather than the routing grid's downsample),
/// and a city with no such cell within the bounded search radius is SKIPPED
/// entirely (never fabricated, never a panic — reported via the existing
/// Phase-5 name-fulfillment warning). "Acceptable" is BOTH of D-211 step 4's
/// promises since the PR #218 round-2 fix: land AND at least `MIN_SPACING`
/// from every already-placed city, so correcting one can never quietly spend
/// the other. SKIP therefore also fires where land exists but none of it
/// clears spacing within the bound. This routing relaxation still degrades
/// gracefully for the coastal-cell/downsample case it was built for (anchors
/// to the nearest passable cell within `COASTAL_ANCHOR_MAX_RING`, or leaves
/// it unrouted beyond that) — the two fixes are independent and both apply
/// (T-1206 guarantees the placement pixel is land; this relaxation still
/// covers the routing CELL being water-majority at downsample granularity).
/// (T-1206 guarantees the placement pixel is land and correctly spaced, or
/// that the city is skipped; this relaxation still covers the routing CELL
/// being water-majority at downsample granularity).
///
/// The fix anchors routing to the NEAREST passable routing cell (ring-expansion
/// search, deterministic tie-break) rather than the settlement's own impassable