feat(cam-clear): island encirclement pass families #137

Merged
patman merged 3 commits from patman/island-families into patman/island-engagement 2026-08-24 02:25:47 +00:00 AGit
Owner

Island lane I-d. IslandFront, island_family, solve_island_step, island_pass_engagement, island_first_orbit_bound; ClearError::{IslandWrongWinding, IslandOffsetFailed}. Island pass engagements are REPORTED, not certified, in this commit — the margin bookkeeping lands in I-e3 (#140). Includes the OnBoundary oracle fix (narrow error match + checked_any guard) that root-caused a one-in-many-runs flake to a query degeneracy at exact-boundary sample points. Opus review PASS.

Island lane I-d. IslandFront, island_family, solve_island_step, island_pass_engagement, island_first_orbit_bound; ClearError::{IslandWrongWinding, IslandOffsetFailed}. Island pass engagements are REPORTED, not certified, in this commit — the margin bookkeeping lands in I-e3 (#140). Includes the OnBoundary oracle fix (narrow error match + checked_any guard) that root-caused a one-in-many-runs flake to a query degeneracy at exact-boundary sample points. Opus review PASS.
feat(cam-clear): island encirclement pass families
Some checks failed
CI / build-test (pull_request) Failing after 4s
d21b2fe317
Adds the per-island outward encirclement family builder, the construction
half of island-aware clearing (docs/superpowers/island-clearing-design.md,
step I-d / ID-6, ID-10). Each island gets its own ordered chain of CW
encirclement loops growing away from it, tightest orbit first, so the tool
can orbit an island the same way it walks the outer wall inward. The
coupled walk that decides where these chains actually stop is I-e; this
builds one island's family in isolation, far enough for that caller to
probe.

What it adds:

- `IslandFront { loops, max_engagement, certified }`, one island's chain
  plus parallel per-pass engagement bounds and certification flags.
- `island_family`, the walk: build the island's tool-center limit loop via
  `offset_closed(island, r)`, then step outward with `solve_island_step`
  until accumulated growth reaches `max_extent` or `MAX_PASSES` is hit.
- `solve_island_step`, the island analogue of `solve_ring`: bisects for the
  largest stepover in (floor, max_stepover] whose engagement stays at or
  below target. Growth uses a positive-distance `offset_closed` directly on
  the CW loop — per the design addendum, that is what dilates a CW loop
  outward; the `cleared_envelope` negative-then-reversed pattern would flip
  winding to CCW and mis-route engagement to the concave branch, undercounting
  by up to several tenths of a radian. There is no `min_convex_radius` floor
  to clamp toward on outward growth, so an offset failure here is a genuine
  construction limit (a concave notch collapsing as it is pushed out), not a
  topology to work around — it surfaces as `IslandOffsetFailed`.
- `island_pass_engagement`, the sampled exact-distance union bound (I-c's
  `island_union_engagement`) evaluated at `sample_points` stations along a
  pass against the previous pass's grown envelope. Sampled rather than
  closed-form because the envelope need not be convex, so the section-3(b)
  convex over-count shortcut does not apply (ID-8); the cost is samples-many
  stock queries per pass, fine at CAM precompute time (design intent #3).
- `island_first_orbit_bound`, the honest reported bound for the limit pass.
  Reading `island_pass_engagement` of the limit loop against the raw island
  measures penetration into the island, which is exactly zero by
  construction (the limit loop is tangent everywhere) and would report ~0
  while the tool is in fact buried. Instead each island segment is evaluated
  at full-radius penetration through the same closed forms I-c verified,
  the max is taken, and the result is floored at pi — the outward-semicircle
  -in-virgin-material argument is a whole-disk argument that holds
  regardless of local island shape, including at concave notches where the
  bare per-segment formula reads below pi.

Certification posture: every pass in an `IslandFront` is reported, never
target-gated — `certified` is all-false in this commit. The stepover walk
still target-gates its own stepover choice via `solve_island_step`'s
bisection, keeping engagement magnitudes sane; only the flag downstream
consumers read is honest that nothing here is a certificate yet. The
sampled union bound has no adversarial h-perturbation margin and no
inter-sample modulus of continuity, so between two sampled stations the
true engagement can peak above either reading with nothing bounding the
gap. The margin bookkeeping needed to promote entries to true is deferred
to I-e, and `certified` is kept as a `Vec<bool>` rather than dropped so
that promotion is per-pass and needs no shape change.

Invariants: islands must arrive CW-wound and a CCW one is refused loudly
(`IslandWrongWinding`) rather than silently re-oriented, since routing
depends on the caller's winding — `NestedRegion::classify` already
normalizes upstream of any real caller, so this catches a bypass. Loops are
emitted innermost-first and are CW throughout, never a `cleared_envelope`
-derived reversed loop. Overshoot contract, documented on the function: the
extent check runs before each step and a solved step adds a full stepover,
so the walk may exceed `max_extent` by up to one `max_stepover` — callers
must not treat it as a collision-safety bound, and I-e runs its own
`min_loop_gap` checks accordingly.

Known degenerate case, documented rather than papered over: a zero-area
island has signed area exactly 0.0, so `orient_ccw` is a no-op on it and
the winding check fires regardless of its actual orientation. It is
reported as `IslandWrongWinding` even though the real defect is zero-area.
cam-geom's `signed_area` is private to `orient_ccw`, so distinguishing the
two would mean widening cam-geom's public API — out of scope here.

Tests: `circular_island_hand_check_pins_exact_engagement` (closed-form
value pinned by hand); `island_family_first_orbit_engagement_is_not_near_zero`
(the tangency trap that motivated `island_first_orbit_bound`);
`square_island_family_pass_count_and_target_gated` (pass count and monotone
engagement on the design's flagship square-island fixture);
`tiny_island_below_tool_radius_still_builds_family`;
`island_family_refuses_ccw_island`;
`island_family_refuses_offset_collapse_at_sharp_concave_notch` (a V-notch
under the miter limit at any positive offset); and two oracle-direction
checks — `island_family_oracle_direction_holds_for_square_island` and the
`island_family_oracle_direction_holds_at_every_sampled_pass` proptest —
asserting the reported bound dominates exact `StockState::engagement` at
every sampled tool center.

Test-robustness fix folded in here (same owning commit as the tests it
touches): `assert_island_family_oracle_direction` unwrapped
`StockState::engagement`, which returns `QueryError::OnBoundary` when a
sampled tool center lands exactly on the feature being measured. Because a
pass and its feature are parallel offsets, that is a routine degeneracy of
the *query*, not an oracle violation, and the rest of the suite already
handles it with `Err(QueryError::OnBoundary) => continue`. Unwrapping made
these proptests fail intermittently. Their case count also goes from 20 to
64: at 20 the degeneracy surfaced roughly once in a blue moon and was not
reproducible run-to-run, which is exactly how it evaded earlier review; at
64 it surfaced immediately and stayed reproducible.

Co-authored-by: patman-assist <patrick-ai@kgroo.co>
chore: normalize comments
Some checks failed
CI / build-test (pull_request) Failing after 5s
1c8cc53d52
Co-authored-by: patman-assist <patrick-ai@kgroo.co>
style: rustfmt --edition 2024 drift fix
All checks were successful
CI / build-test (pull_request) Successful in 8m40s
3c5a636918
Reformats files that predate the runner's current rustfmt; no code changes.

Co-authored-by: patman-assist <patrick-ai@kgroo.co>
patman merged commit 52d875eb66 into patman/island-engagement 2026-08-24 02:25:47 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
patman/KGROO!137
No description provided.