Skip to content

The general 3-D outcrop cap: a zone may meet any boundary - #589

Merged
lmoresi merged 10 commits into
bugfix/fault-clip-boundaryfrom
feature/fault-outcrop-3d-cap
Aug 18, 2026
Merged

The general 3-D outcrop cap: a zone may meet any boundary#589
lmoresi merged 10 commits into
bugfix/fault-clip-boundaryfrom
feature/fault-outcrop-3d-cap

Conversation

@lmoresi

@lmoresi lmoresi commented Aug 16, 2026

Copy link
Copy Markdown
Member

Stacked on #582 (base is its branch); only the last three commits are this PR.

A fault zone specified past the mesh boundary now embeds whatever that boundary is: a tilted or rotated wall, a box edge, a faceted sphere. The NotImplementedError at the old _trace_wall_code — "the zone outcrops on a non-axis-aligned boundary" — is gone, and the function with it.

What the cap is now

The cap over the outcrop bowl is re-triangulated per coplanar boundary region, each piece meshed flat in its region's own plane, so the cap sits exactly on the faceted surface and volume conservation survives to 1e-12. Where the band crosses a crease between regions, the two sides segment the crease line differently — the bowl's nodes are mesh vertices, the band's crossing nodes are assembly nodes — so a 1-D overlay merges both node sets by arc coordinate and keeps each elementary sub-segment for the side(s) whose bowl covers it and the band does not. A sub-segment covered from one side only must be a whole mesh edge, because a cavity-shell face matches it in the fill's closed surface; anything else is a refusal, not a crack.

The frame rule (_outcrop_frame_3d) separates two notions the third dimension forces apart. Where the cavity may open is by smooth wall: coplanar regions grouped across low-dihedral creases (under 45 degrees), so a faceted sphere is one wall and its bowl legitimately spills onto facets beside the band's own, while a box's other walls stay refused across their sharp edges. What the carve may delete is by shape: band-covered vertices, single-region interiors, and interior vertices of straight creases between touched regions. A vertex where three or more regions meet — a box corner, every vertex of a faceted sphere — is the domain's shape and is never deleted off the band. A protected vertex whose whole cell star drops is not stranded: it is a collar node, and the gap fill's tets reference it. That is how a curved boundary keeps its faceting through the surgery.

Wall labels are restored per removed face (the 2-D per-segment rule of the corner fix, one level up), so a bowl spanning Top and Front restores each wall's own labels. The Euler gate now demands conservation of the input's Euler number rather than the value 1: a spherical shell is S²×I, Euler 2, and was refused before for its topology rather than for any defect. The same assumption remains in place_sheet and remove_embedded, marked TODO(BUG).

Evidence

  • The box oracle did not move: the full placement suite (0853–0856, 0859) passes unchanged, 62 tests.
  • New test_0860_outcrop_general_boundary_3d: a rotated box (no wall axis-aligned), a band across the Top/Front box edge (trace on both walls, each wall's labels restored on its side), and a spherical shell outer surface. Each runs its negative control first — the identical census on an interior twin counts no trace — and each ends in the P2 Poisson oracle, exact through the zone.
  • Parallel: the rotated-box outcrop added to ptest_0855 passes at np=2 and np=4; the trace count (28 facets) is identical at np=1, 2 and 4 with the info dict identical on every rank.

Known limits, stated as refusals

  • A band running along a domain crease (rather than across it) refuses with the reason.
  • A band outline node landing within rounding of a kept mesh vertex refuses: the 2-D imprint collapse (_collapse_boundary_imprints) has no 3-D counterpart yet.
  • place_sheet's outcrop stays box-framed, per the plan's own advice — unify after, not during.

Underworld development team with AI support from Claude Code

…h walls

The zone outcrop no longer needs an axis-aligned wall. The cap over the
bowl is re-triangulated PER COPLANAR BOUNDARY REGION, each piece meshed
flat in its region's own plane, so the cap stays exactly on the faceted
surface and volume conservation survives. Where the band crosses a
crease the two sides segment the line differently (mesh vertices against
assembly nodes), so a 1-D overlay merges both node sets by arc
coordinate and keeps each elementary sub-segment for the side(s) whose
bowl covers it and the band does not; a one-side segment must be a whole
mesh edge, because a cavity-shell face matches it.

The frame rule (_outcrop_frame_3d) separates the two notions the third
dimension forces apart. Where the cavity may OPEN is by SMOOTH WALL —
coplanar regions grouped across low-dihedral creases — so a faceted
sphere's bowl legitimately spills onto facets beside the band's own
while a box's other walls stay refused. What the carve may DELETE is by
shape: band-covered vertices, single-region interiors, and interior
vertices of straight creases between touched regions; a vertex where
three or more regions meet is the domain's shape and is protected. A
protected vertex whose whole cell star drops is not stranded: it is a
collar node, and the gap fill's tets reference it — that is how a
curved boundary keeps its faceting through the surgery.

Wall labels are restored per removed face (the 2-D per-segment rule one
level up): each new wall triangle takes the labels of the removed face
it lies on, so a bowl spanning several walls restores each wall's own.
The Euler gate now demands CONSERVATION of the input's Euler number
rather than 1 — a spherical shell is S^2 x I, Euler 2, and refused
before for its topology, not for any defect. The same assumption in
place_sheet and remove_embedded is marked TODO(BUG).

_trace_wall_code and its refusals are deleted; the box path runs
through the general machinery and the box oracle tests are unchanged.
Driven on a rotated box (no wall axis-aligned), a band across the
Top/Front box edge (trace on both walls), and a spherical shell outer
surface (75 trace facets, 6 vertices removed): volume conserved to
1e-12 in each.

Underworld development team with AI support from Claude Code
…n a sphere

Three configurations, each the failure mode of a different assumption
the box-framed cap made: a rotated box (no wall axis-aligned; the
single-region collar), a band across the Top/Front box edge (the crease
overlay conforms the two sides' differing segmentations, and each
wall's labels are restored on its own side), and a spherical shell
outer surface (every facet its own region, every vertex protected
faceting — the case the trace design exists for). Each runs its
negative control first — the identical census on an interior twin
counts no trace — and each ends in the P2 Poisson oracle, exact for a
quadratic through the zone. Volume conserved to 1e-12 throughout; the
shell's Euler number 2 comes through the conservation gate.

The parallel file gains the rotated-box outcrop at np>=2 with the same
mesh and patch as the serial test: the info dict is identical on every
rank and the trace count matches the serial value (28 facets at
np=1, 2 and 4), so the general path is partition-independent. No
boundary face is left without a wall label at any rank count.

The spherical control sits mid-gap of a 0.75-thick shell: a one-cell
chain from a victim corner spans h, so an interior zone needs
~(clearance + 1) * h to spare on both sides — thinner shells refuse
interior zones at this resolution by the carve's own clearance gate.

Underworld development team with AI support from Claude Code
The collar-vs-bowl consistency check raised on the surgery rank inside
the relabel block, which is outside any try — a hang at np>=2. It now
sets the block's failure and flows through the allgather like every
other refusal there.

Underworld development team with AI support from Claude Code
@lmoresi

lmoresi commented Aug 16, 2026

Copy link
Copy Markdown
Member Author

Adversarial review (self)

We reviewed the three commits against the plan's gates and our own claims. Findings, most severe first.

1. A rank-local raise shipped in the first commit and would hang at np≥2. The collar-vs-bowl consistency check raised on the surgery rank inside the relabel block, which is outside any try — exactly the defect class the file's own comments warn about. Found by re-reading the diff, not by any test: the parallel tests pass because the check never fires on healthy geometry. Fixed in the third commit by routing through the block's collective failure. A test that forces this refusal at np≥2 does not exist and would need deliberately inconsistent geometry; we did not construct one.

2. The general outcrops are 2–4× more slivery than the box outcrop. Minimum dihedral angles, same mesh scale (cellSize 0.12, width 0.05): interior zone 9.5°, axis-aligned box outcrop 13.8°, rotated box 6.4°, box-edge crossing 3.6°, spherical shell 3.1°. The mechanism is the one the 2-D corner work already met: the band outline lands where it lands, and a collar polygon between an outline node and a nearby kept mesh vertex is thin. The 2-D cure (_collapse_boundary_imprints) has no 3-D counterpart; until it does, near-coincidence refuses at rounding distance but produces slivers just above it. All fills pass the conformity gates and the P2 oracle is exact — the slivers are a quality cost, not a correctness one.

3. A dead end we built and removed. Our first treatment of stranded protected wall vertices kept one cell of the vertex's star ("rescue"). It produced floating kept islands the fill wrapped as bubbles (global Euler defect, measured on the sphere) and was replaced wholesale: a protected vertex needs no kept cell, because the collar re-triangulation references it and the gap fill's tets give it cells. The final code is simpler than what it replaced; the connectivity gate we wrote for the islands went with the rescue that caused them.

4. The Euler gate was wrong before this PR, for domains nobody could reach. != 1 encodes a ball; a spherical shell is Euler 2. The general clip made shells reachable, so the thin-volume gate now demands conservation of the input's number. The identical assumption remains live in place_sheet and remove_embedded — a sheet placed inside a spherical shell refuses today for its topology. Marked TODO(BUG) at both sites rather than fixed, per scope discipline.

5. Untested paths we know about. The polygon-nesting logic in _outcrop_collar_3d is exercised only at depth ≤ 1 (outer ring plus hole); depth-2 nesting (an island inside a hole) is written but unreached. The three refusal guards — band along a crease, outline node within rounding of a kept vertex, a band node splitting a one-side crease edge — fire on geometry none of our cases construct; they are read-verified only. The 45° smooth-wall threshold means a curved boundary faceted coarser than ~45° facet-to-facet splits into separate walls and refuses; documented at the constant, not tested.

6. Partition independence is asserted, not proven, for the sphere. The np=1/2/4 identity (trace 28) is measured on the rotated box only. The sphere runs serial-only; its parallel behaviour rests on the same gather-first mechanism the box exercises, which is an argument, not a measurement.

Underworld development team with AI support from Claude Code

The same gate place_thin_volume already fixed: demanding global Euler
number 1 encodes a ball-topology domain, and a spherical shell —
S^2 x I, Euler 2 — was refused for its topology rather than for any
defect of the surgery. Both gates now compare against the input mesh's
own number. Pinned by a regression test: a sheet embeds mid-gap in a
spherical shell and its removal clears the label again, both passing
their volume and conservation gates.

Underworld development team with AI support from Claude Code
@lmoresi

lmoresi commented Aug 17, 2026

Copy link
Copy Markdown
Member Author

Review finding 4 is resolved in 41eb60a rather than left as a TODO: place_sheet and remove_embedded now gate on conservation of the input's Euler number, the same fix place_thin_volume carries. A sheet embeds mid-gap in a spherical shell and removes again, pinned by a regression test in test_0854. Every placement primitive now works in non-ball domains.

Underworld development team with AI support from Claude Code

The gate catches unmeshed solids — an O(1) relative defect — but its
reference, OCC's getMass on the clipped boolean, is only accurate to
~5e-7 relative when the domain tool carries many faces (measured on a
16.6k-facet adapted spherical boundary: the honest mesh volume exceeds
the reported CAD mass before any snap runs). At 1e-9 the gate refused
correct assemblies; it now allows 1e-6, far above the kernel noise and
far below any real missing-solid defect.

Underworld development team with AI support from Claude Code
OCC's boolean leaves clipped nodes up to ~4e-7 off the tool's own
planes on O(1) geometry against a many-faceted tool; the 1e-9 snap
missed them, so a crease-crossing node of the band outline was not
recognised as on-crease and the collar meshed a 2-metre sliver beside
the crease (measured on a 1000 km megathrust against an adapted
spherical boundary; the 2-D fill then refused with moved nodes). The
snap tolerance now sits above that noise and below any layer mesh
size, and candidates are masked by distance to the boundary FACETS
first — the planes are infinite, and at this tolerance every point in
space is near some plane of a many-faceted tool.

Underworld development team with AI support from Claude Code
Two mechanisms a 1000 km outcrop band forced, plus the diagnostic that
found them. _collapse_boundary_imprints_3d is the 2-D imprint collapse
one dimension up: where the band outline grazes a boundary vertex
(measured: a 2.4 m gap the collar meshed as a sliver and the fill
refused as moved nodes), the outline is rerouted THROUGH the vertex —
the nearest outline node moves onto it, or the outline edge splits at
it with every incident tetrahedron bisected. A move or split must keep
every incident cell's volume healthy, else the vertex is skipped and
keeps its sliver (the status quo, not a defect); the band still tiles
the same faceted surface, so the domain's shape is untouched.

An outline edge lying ALONG a crease is no longer refused when the
cavity covers both sides: the band reaches the crease there, so the
edge bounds the collar piece on the FAR side of the crease, not the
owning band triangle's own region. The refusal remains for a band
bounded by a crease with no bowl beyond it.

A collar piece that fails to mesh now names its pinch — the thinnest
node-to-segment gap and the node kinds — which is what separated this
sliver class from the OCC placement noise the snap fix covers.

Known limit, measured and deliberately not papered over: refining a
SPHERICAL boundary projects new facet vertices onto the true sphere,
and the creases between the resulting nearly-coplanar sub-facets are
laterally fuzzy at (placement noise)/sin(theta) — wider than the
band's own feature spacing, which defeats the crease overlay. A
widened, fuzz-aware overlay tolerance was tried and withdrawn: it
traded the sliver for misclassified chains on the honest-crease tests.
Outcrops on adapt-refined spherical boundaries stay refused by the
fill's own gates until the crease representation is rethought.

Underworld development team with AI support from Claude Code
@lmoresi

lmoresi commented Aug 17, 2026

Copy link
Copy Markdown
Member Author

Review addendum: what a 1000 km outcrop band taught us

We drove the general cap at Earth scale — a 1000 km, 4 km-wide megathrust band against a spherical shell, background mesh ~350 km — and it found four defects the 300 km tests could not see. Three are fixed on this branch, one is characterised and open.

Fixed. (1) OCC's boolean mass on a many-faceted tool is only accurate to ~5e-7 relative, so the 1e-9 meshed-vs-CAD gate refused correct assemblies; the gate now runs before the snap and allows 1e-6 (807a912, restructured in db68864). (2) OCC leaves clipped nodes up to ~4e-7 off the tool's own planes; the snap now covers that noise, masked to the boundary facets so infinite-plane projection cannot reach interior nodes (34ea192). (3) The band outline grazes the wall's own vertices — measured, a 2.4 m gap the collar meshed as a sliver — and _collapse_boundary_imprints_3d now reroutes the outline through such vertices, with a volume guard so a move or split can never flatten a cell; on-crease outline edges are reassigned to the far collar rather than refused (db68864). All 31 placement oracles pass throughout.

Open, characterised. Refining a spherical boundary projects new facet vertices onto the true sphere; the creases between the resulting nearly-coplanar sub-facets are laterally fuzzy at (placement noise)/sin(theta) ~ 1e-4 — wider than a 4 km band's own feature spacing — and the crease overlay cannot classify crossings against them. A fuzz-aware tolerance was tried and withdrawn: it traded the sliver for misclassified chains on the honest-crease tests. Until the crease representation is rethought, outcrops on adapt-refined spherical boundaries refuse at the fill's own gates; the plain-shell 1000 km case also still trips a skin/cap facet overlap that is not yet diagnosed. Negative results reported as found; the collar refusal now names its pinch (gap and node kinds), which is the diagnostic that separated all four causes.

Underworld development team with AI support from Claude Code

@lmoresi

lmoresi commented Aug 18, 2026

Copy link
Copy Markdown
Member Author

Adversarial review — fault-placement stack (#582, #589)

Reviewed together. Each already carries its own review; this adds the
relationship between them, which neither says.

S1. #589 is stacked on #582. pr582 is an ancestor of pr589. Both edit
src/underworld3/utilities/place_surface.py and
tests/parallel/ptest_0855_place_thin_volume_parallel.py; #589 adds
test_0854_place_sheet.py and test_0860_outcrop_general_boundary_3d.py on top
of #582's test_0855_place_thin_volume.py and test_0859_domain_boundary_tool.py.

Consequences for the backlog:

Recommended order: #582, then #589.

S2. Both touch ptest_0855, which is a ptest_ file. Those are not
collected by a default pytest tests/ run — they are driven under mpirun
explicitly. Two PRs editing the same manually-driven parallel test is the case
where a regression is least likely to be noticed by CI. Worth confirming the
combined file runs at np=2 and np=4 after both land, rather than after each.

Underworld development team with AI support from Claude Code

The sheet path joins the general boundary machinery: one clip, one
frame, one collar (maintainer ruling 2026-08-18 — multiple placement
paths are themselves the defect). The Sutherland-Hodgman box clip and
the wall-code frame are deleted.

The discrete clip primitive cuts the authored triangulation against the
gathered boundary complex directly: per-component outward orientation
(a shell's inner surface signs opposite to its outer), signed-distance
classification, sequential cuts by the COPLANAR REGIONS' planes — a box
wall cuts as one plane however it is faceted, or the two triangles
sharing a cut edge key their cuts by different facets and the sheet
tears (measured: a duplicated node on the box top wall). Side cuts are
re-derived from the original sheet edge's endpoints and interned by
(edge, region), so neighbours whose sides are truncated differently
produce the bitwise-identical node (measured: ~1e-17 duplicate pairs on
the sphere without it). A crossing that can touch a locally concave
crease (an inner boundary) refuses loudly — the polyline cut is not
built — and every kept node is gated inside the domain on exit.

The carve takes the frame's two masks (open_deletable / open_near) like
the volume's carve, with the same protected-collar-node rescue; the
outcrop frame accepts a trace CHAIN of edges as the footprint alongside
a band of triangles; and the collar embeds the chain through its pieces
instead of cutting a hole — chain nodes at crease crossings land ON the
crease and enter the 1-D overlay as 'a' nodes, the runs between
crossings embed per region (_gmsh_fill_2d now takes several polylines),
free ends as gmsh's ordinary free-end embed. A trace edge along a
crease, or off the bowl, refuses with the reason. The overlay's local
loop variable is renamed crease_chain — it shadowed the new parameter,
which made the volume path read a stale trace.

The trace chain's edges carry <label>_trace in the result, the wall's
labels are restored per removed face (the volume path's rule), and the
counts are gated collectively. Box oracle unchanged (test_0854, 8/8;
area matches Sutherland-Hodgman bit-for-bit in the spike); the sphere
outcrop that could not run at all now embeds with volume conserved and
the P2 oracle exact (test_0860); trace counts identical at np=1/2/4
(ptest_0854).

Underworld development team with AI support from Claude Code
Claude-Session: https://claude.ai/code/session_01WDKP73LD3dCFQSNgEXbbw9
The hybrid-seam study measured the defect this guards against: a split
surface terminating against something that cannot slip ends as a free
crack tip, slip pins to zero, and the composite is worse than either
pure representation (74.6% vs 100/105%). The outcrop is that join one
level up, so the acceptance test is kinematic — measured slip > 0 at
the trace against a pinned control — not mesh gates alone.

The placement half asserts today: every trace edge on the wall AND
bounding a labelled fault face, the wall's labels restored beside it.
The kinematic half attempts split_along_label_3d through the wall and
SKIPS at its daylighting refusal — the body below the gate is the
acceptance criterion, ready to run when feature/fault-split-node learns
to duplicate the trace chain.

Underworld development team with AI support from Claude Code
Claude-Session: https://claude.ai/code/session_01WDKP73LD3dCFQSNgEXbbw9
The boundary snap's tolerance was raised to 1e-6 to cover OCC's ~4e-7
boolean placement noise (34ea192), but the test's untouched-control
point stayed at 2e-9 — inside the new tolerance, so it snapped and the
test failed. The control moves to 2e-5: above the tolerance, below any
real feature scale. A branch push does not trigger CI, which is how
this shipped red.

Underworld development team with AI support from Claude Code
Claude-Session: https://claude.ai/code/session_01WDKP73LD3dCFQSNgEXbbw9
@lmoresi

lmoresi commented Aug 18, 2026

Copy link
Copy Markdown
Member Author

The sheet path joins the general machinery (111ae09..24cbd56)

place_sheet now clips, carves and caps against the mesh's own boundary — the Sutherland–Hodgman box clip, the wall-code frame and the single-loop rim cap are deleted. The discrete clip cuts the authored triangulation directly (no OCC): per-component outward orientation, signed-distance classification, sequential cuts by the coplanar regions' planes, cut nodes interned by (original-edge, region) identity. The carve takes the frame's two masks like the volume's carve; the collar embeds the trace chain through its pieces instead of cutting a hole, with crossings on the creases via the existing 1-D overlay. The trace chain's edges carry <label>_trace through to the wall — the splittable trace the split machinery needs for a daylighting fault (test_0861 holds the kinematic acceptance criterion, gated on the split side's refusal until feature/fault-split-node lands).

Evidence: box oracle unchanged (test_0854 8/8; clip area matches Sutherland–Hodgman bit-for-bit); the spherical sheet outcrop that previously could not run at all embeds with the trace labelled, volume conserved to 1e-12 and the P2 oracle exact (test_0860, 4/4 with interior negative control); trace counts identical at np=1/2/4; full suite 1505 passed.

Adversarial review (our own)

Defects found and fixed before the push:

  • Coplanar facets tore the sheet. Cutting per facet plane keyed the two triangles sharing a cut edge by different (coplanar) facets of one wall — a duplicated node on the box top wall. Cuts now key and compute by the coplanar REGION's plane.
  • Sub-segment interpolation tore the sphere. A side truncated by an earlier plane interpolated its next cut from the sub-segment, its neighbour from the full edge: ~1e-17-apart duplicate pairs. Side cuts now re-derive from the original sheet edge's endpoints.
  • The collar's overlay shadowed the new chain parameter (for chain in chains.values()), so the VOLUME path read a stale crease chain as a sheet trace and indexed with tuples — caught by test_0860's box-edge case, renamed crease_chain.
  • petsc4py segfault in our own census: getStratumIS on an empty stratum hands back an IS whose getIndices SEGVs (PETSc traps it, so it presents as a silent pytest death, exit 59). Guarded by getStratumSize first — the same trap class as the Null_Boundary lesson.
  • Pre-existing red test: 34ea192 widened the snap tolerance to 1e-6 and left test_0859's untouched-control at 2e-9, inside it. A branch push does not trigger CI, which is how it shipped red. Fixed (24cbd56).

Known limitations, deliberately loud rather than fixed here:

  • A crossing that can touch a locally concave crease (an inner boundary) refuses — the polyline cut is not built. On adapted spheres with fuzzy creases the refusal may now fire at the clip rather than the fill's gates; same posture as the crease-classification redesign note, earlier trigger.
  • Tolerances are absolute (clip 1e-12, membership 1e-9), consistent with the subsystem; at 1000 km-in-metres scale the rounding floor approaches them. Campaign-wide, not new here.
  • The bbox near-set is a superset heuristic: an over-keep is caught by the every-node-inside exit gate (refusal); an over-clip cannot happen where the boundary is locally convex; a torn configuration surfaces at the fill's PLC as a loud error. No silent path found.
  • The shell sheet outcrop's min cell volume is ~1e-10 — the sliver follow-on already recorded for general outcrops. Sheets have no 3-D graze collapse; the collar's near-coincidence refusal is the guard.

🤖 Generated with Claude Code

https://claude.ai/code/session_01WDKP73LD3dCFQSNgEXbbw9

@lmoresi

lmoresi commented Aug 18, 2026

Copy link
Copy Markdown
Member Author

Merging as the second half of the #582 stack (#582 landed as 87232f0). Its CI was red when we reviewed; it re-ran against a development that now contains #582 and is green — the failure was the stack, not the change.

Per S2 in the cluster review, both PRs edit ptest_0855_place_thin_volume_parallel.py, which is a ptest_ file and so is not collected by a default pytest tests/ run. The combined file is worth a run at np=2 and np=4 now that both halves are in, rather than after each.

@lmoresi
lmoresi merged commit 112c277 into bugfix/fault-clip-boundary Aug 18, 2026
1 check passed
@lmoresi

lmoresi commented Aug 18, 2026

Copy link
Copy Markdown
Member Author

The daylighting ruling lands (aa79ec5, ae7f9f6)

Maintainer ruling (2026-08-18): split-node faults do not split through the surface. A fault stops an element or two below, blind, with a damaged region above carrying the deformation to the surface. This supersedes the split-through-the-wall acceptance test_0861 first carried; the body gated on a daylighting split is removed.

The kinematic acceptance is now validated by running, not gated. The listric handover rule (a contact tip inside weak material is free; a tip at the weak zone's edge is pinned) turned vertical against a FREE surface: a blind frictionless split fault two cells under the top, driven in antisymmetric dip-slip, solved bare / damage-abutting / damage-enclosing. Measured (probe in ~/+Simulations/blind_fault_surface_expression/): near-tip slip 0.45 / 0.65 / 0.80 of peak, surface localization 37% / 44% / 50% — strict ordering on both, enclosing the tip worth 1.77x over bare pinning, and the abutting seam (the hybrid-seam defect) measurably worse than the enclosed tip. The overlap margin is the deliberate design parameter.

place_sheet(..., setback=d) does the deliberate part: the job is still to figure out the intersection so the fault can stop before it hits it — it just never meshes or splits all the way there. The sheet clips against the boundary offset inward by d, arrives blind with a strictly interior rim, and split_along_label_3d takes it as it stands; the would-be intersection with the true boundary comes back as info['surface_trace'] — the damage region's locator. Verified end-to-end in test_0861: place with setback, trace located on the true wall, shallowest sheet vertex exactly a setback below it, split succeeds with the Plus side carrying every placed face.

Adversarial notes on our own additions: an all-rim corner face (two side-rim originals + cut nodes) admits no triangulation the split accepts, at any sheet density — fixed by longest-interior-edge midpoint splits. A centroid split was tried first and rejected on measurement: inside a sliver corner face it drove the gap fill to 1e-23 cell volumes and a P2 error of 0.64 on the shell outcrop, caught by the P2 oracle after every topological gate passed — the #520 lesson holding again. The blind-fault probe's margins are modest at unit scale (the far field dominates a 1x1 box); the committed thresholds hold generous slack under the measured values.

🤖 Generated with Claude Code

https://claude.ai/code/session_01WDKP73LD3dCFQSNgEXbbw9

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant