Roshera

Sheet 03 Cases 6

Sheet 03 — casebook

Five of these six
are failures of silent success.

Not one of them is a crash. A crash is the easy case: it announces itself, it has a stack trace, and nothing downstream is built on top of it. These are the other kind — where the kernel returned a confident, well-formed, wrong answer.

A phantom revolve that served the wrong geometry. A section that reported the uncut area. A marcher whose output was, in the source's own words, silent noise. A union that dropped two faces. A drill that reported four holes while removing no material.

Each is reproduced here with the verbatim source text, the exact figures, and the commit that closed it. Where a case is weaker than its reputation, it says so — including one whose documentation outlived the bug it described.

Provenance Every quotation on this page is verbatim from the repository — commit messages, doc comments, error definitions, test assertions. Figures that could not be confirmed first-hand against source were cut rather than rounded, including three that had circulated internally as fact.

Case 01 — the phantom effect

An integer that meant something else in the next process

The timeline is event-sourced: a model is rebuilt by replaying what happened to it. A revolve was recorded as revolve_face carrying the kernel's internal profile face id — a handle that is meaningful only inside the session that minted it.

On a forty-five-event log, one such id no longer resolved, and boot quarantined honestly. The other did something far worse: it resolved to an unrelated live face that happened to share the number, and the replay silently revolved the wrong geometry. A served event, a plausible solid, no error anywhere.

The fix is at the recording root, not in replay, and the reasoning is stated where the guard lives:

// Resolving `face_raw` by raw fallback would revolve whatever UNRELATED
// live face happened to share that numeric id — a silent wrong-solid (or,
// when the id resolved to nothing buildable, a phantom served event with no
// geometry). Such an event is unreplayable by construction: fail LOUD as a
// dangling reference so boot QUARANTINES honestly at it, never serves a
// phantom.
replay.rs:1414verbatim

Legacy events of that shape are now refused rather than migrated. There is no lossy upgrade path, because any upgrade would have to guess which face was meant.

#[error("dangling reference in {kind}: {entity} no longer resolves")]
DanglingReference { kind: String, entity: String }
replay.rs:128a reference-durability failure, not a numeric one

The regression test does not check that replay fails. It checks that replay fails for the right reason — seeding a box that owns faces 0 to 5, then replaying a revolve_face naming face 3, which would otherwise succeed by coincidence.

/// Mutation proof: delete the `id_remap.contains_key(&face_raw)` guard in
/// the `revolve_face` arm and this regresses — the kernel revolves the box's
/// face 3 (a coincidental success, or a `KernelError` that is not `Dangling`)
replay.rs:2056regression guard
The worst class of lie A crash loses you an operation. A quarantine loses you a session. This lost you the truth — a stored history that replayed into a different part than the one it recorded, with every layer reporting success.
Found by the system, in production This was not caught by a test. Durability quarantine surfaced it within hours of shipping, on a real log, because boot refuses to serve a prefix it cannot prove. "a booted model is proven, not assumed … the tail is refused rather than served as a subtly-wrong model."
"durability: QUARANTINE — the log contains an
 event this kernel cannot faithfully replay;
 serving the clean prefix and refusing the
 tail. is_sound={}"
durability.rs:310quarantine
Case 01FIXED
events in log
45
recorded miss
face_id=166
commit
f1a417bd
replay arms added
2
void 22×12 22×12 22×12 22×12 remaining material = 1056 mm² SECTION THROUGH BOTH BORE AXES
60×40×40 block, two Ø16 through-boresreported 4000
Case 02 — the arithmeticFIXED
undrilled rectangle
2400 mm²
truth, axis plane
1056 mm²
reported by the bug
4000 mm²
truth, offset plane
≈1307 mm²
commit
11be5412

Case 02 — the confident wrong area

A fast path guarded by an invariant that stopped being true

Sectioning a cross-drilled block through both bore axes returned a number larger than the undrilled block — 4000 mm² where the solid rectangle is 2400 and the true cruciform is 1056. It also drew a phantom diagonal edge across the void.

What makes this case instructive is that the code was not wrong when it was written. A tier-one bounding-box fast path assumed analytic faces are never boolean-trimmed. That held — until booleans began trimming analytic faces, at which point a cross-drilled bore wall started carrying the other bore's Steinmetz curve as a trim boundary.

the tier-1 bbox fast path assumed analytic faces are never boolean-trimmed;
a cross-drilled bore wall carries the other bore's Steinmetz curve as a trim
boundary, so section generators ran straight across the drilled-away void and
chained into a self-overlapping loop
commit 11be5412defect 1 of 3

Two further defects sat underneath: the winding test broke on full-wrap trim loops, and the seam force-include bypassed the hole test entirely. The two Steinmetz scallops, joined at their tangency points, form a single closed loop whose lifted polygon is not closed in the universal cover — so the membership test mis-unwrapped it.

The fix does not repair that winding test. It routes around it, into an even-odd membership test in quotient parameter space, behind a new soundness gate that asks whether the face's UV domain is actually rectangular before taking the shortcut. The real content of the fix is checking the assumption instead of inheriting it.

The assertion carries the diagnosis in its own failure text:

"axis-plane cruciform area {area:.2} vs analytic {expected:.2} (rel {rel:.4});
 caps={} — full-rect 2400 means the void was not subtracted at all"
section_cruciform.rsregression guard, 4 tests

Case 03 — the marcher that never marched

Two hundred thousand steps, two millimetres of progress

Surface–surface intersection for pairs with no closed-form solution falls back to marching: predict along the tangent, correct back onto both surfaces, repeat until the curve closes. The boolean engine carried its own copy of that marcher, and the copy had two problems that compounded.

The first is arithmetic. The step size is tied to the distance tolerance — tolerance.distance() × 10, which with a 1e-6 tolerance gives a step of 1e-5 world units. The hard cap is 200,000 steps. So the reach of a single trace is two world units per direction. A Ø100 ring has a circumference near 314. The marcher could traverse about two per cent of it before hitting the cap.

The second is what happens at the cap. The partial trace is discarded with Ok(None) — a return value indistinguishable from "these surfaces do not intersect". And because the seed grid samples 0..=20 in both parameters, 441 candidate seeds feed the loop, each one re-running the same doomed two-per-cent trace, because this copy of the marcher had no seed-consumption array.

// HARD STEP CAP per direction. The marching step is tied to the distance
// tolerance (≈1e-5), so a curve on unit-scale primitives needs ~10^6 steps;
// for a pair with NO analytic SSI arm (cone×cylinder, cone×sphere, …) the
// march can also fail to ever close → a true HANG that freezes the kernel
// (the worst failure class).
boolean.rs at 763e9e16verbatim

The cap was added as an explicit safety measure, and the commit that added it refused to overstate what it had done: "This stops the freeze; it does NOT make cone∘cylinder geometrically correct (the marched curve is discarded)." A hang became a wrong answer, knowingly, as the lesser evil — and it was labelled as such.

The structural cause: one marcher got the fixes, its twin did not

A separate commit hardened the canonical marcher — adding alternating projection, curvature-adaptive stepping, periodic seam wrap, one curve per branch, citing Patrikalakis and Maekawa. Its diagnosis of the original defect is the best sentence in this casebook:

The general surface-surface marcher (the freeform fallback the analytic
QSIC producers gate ahead of) did not actually march.

correct_to_intersection took the predicted point but ignored it (_predicted),
re-projecting from the anchor's own (uv1,uv2). The anchor already lies on the
intersection, so the corrector returned the anchor unchanged and every trace
collapsed to one repeated point. The analytic paths masked it; the marcher
output was silent noise.
commit efb090ccverbatim

That commit touched the canonical implementation and one new test file. It did not touch the boolean engine's copy — which is precisely why the copy was still marching two per cent of a ring, 441 times, a year later.

The canonical marcher had the same disease, differently

Measuring rather than assuming turned up a second finding: the canonical implementation is also geometry-blind. A nominal chord of 0.01, a maximum step factor of 8 and a cap of 4,000 steps give a scale-independent maximum reach of 640 world units — regardless of how large the feature is. On a circle of circumference 2,720.699 it traced 639.660 and stopped. Not a bug in the tracing; a constant that assumed a scale.

The fix derives the chord from the geometry instead: the bounding diagonal of the seed cloud divided by 64, floored at the tolerance. Both scales now trace with the same sample count, and the test binary went from 11.34 s to 0.02 s. Separately, the step budget was hoisted to be per surface pair rather than per seed, so an unmarchable pair costs one budget instead of one per seed — 1.2 million evaluations where it previously cost about 24 million.

And then the interesting part: the bug was load-bearing

The obvious next move is to delete the duplicate and call the canonical one. That was attempted, and it broke a shipped watertightness test — a frustum union that had been watertight came back with 198 boundary edges.

The reason is worth sitting with. That test passes today because the marcher is broken. Its twenty seeds all hit the step cap, the tracer returns no curves at all, and the part is then built correctly by an entirely different route — the coincident-rim weld path. Give it a working tracer and it produces a curve fragment that the imprint pipeline then mishandles into a doubled edge.

The root cause was not what anyone thought — including us

The first diagnosis was that the fragment lay exactly on the shared rim, and that the imprint pipeline failed to recognise a partial arc as boundary-coincident. That framing was published on this page. It was wrong, and measuring rather than reasoning is what caught it.

Instrumenting the coincidence predicate gave the fragment's actual residual against the rim: 3.948 × 10⁻², where rim-coincidence would be around 10⁻⁷. The fragment is not on the rim. It is 0.04 away from it.

The reason it is 0.04 away is the real finding, and it is a soundness problem in its own right. The marcher's step law targets a fixed turn per step — 0.2 radians — which fixes the chord at a constant fraction of local radius, roughly half a per cent. That is a shape-fidelity criterion. It is scale-free, which sounds like a virtue, and it is entirely independent of the distance tolerance the caller passed in.

So at a radius of 6, handed a tolerance of 10⁻⁶, the marcher returns a polyline sitting 0.03 to 0.04 away from the true curve — about thirty thousand times coarser than requested — and says nothing. Every consumer downstream believes it received geometry accurate to the tolerance it asked for. The marcher does not honour its own contract, and that only became visible when unification pointed its output at a pipeline that actually requires tolerance-accurate input.

The principled fix is to bound the chord by the caller's tolerance rather than by turn angle. It was implemented, and it is correct and bounded on the original case. It also makes the frustum union hang — no completion in fifteen minutes — for reasons not yet diagnosed. It was reverted rather than left in the tree.

So: one real imprint defect found and fixed along the way, a wrong root cause corrected by measurement, the true root cause identified and its fix deferred because it exposes something worse. The duplicated marcher still exists. All of that is written down as debt rather than rounded up into a claim of completion.

Citation notice Line numbers for this case are cited against committed 763e9e16. The step size and budget are fixed; the duplicated implementation is not, and the reason is in the body — removing it regresses a test that passes only because the marcher is broken.
An honest note on the mutation proof The first mutation — disabling seed consumption — did not fail the new test: deduplication masked it, and four times the work still fitted inside the budget. The budget was tightened on that evidence until the mutation was caught. A mutation test that passes when it should fail is a test that was not yet measuring what it claimed.
Case 03 — the arithmeticPARTLY FIXED
step size
1e-5
step cap
200,000
reach per direction
2 units
Ø100 ring circumference
≈314
traced before discard
≈2 %
candidate seeds
441
seed consumption
none
The RED evidence Before the canonical fix, a sphere–sphere overlap traced 11 points, n_distinct=1, bbox_diag=0.0000 against an expected 2.4495 — a "curve" that was one point repeated eleven times. After: 1 closed circle, 69 distinct points, bbox_diag=2.4491.
The weakest case here, kept deliberately Its headline artifact is a stale comment. Its face counts live in commit prose rather than in assertions. And the error type it was reputed to produce does not occur in that file at all. It is included because a casebook that only prints its strong cases is doing the thing this kernel exists to prevent.
Case 04FIXED
repro banked
11:42:40
fixed
14:14:00
elapsed
2 h 32 m
failure signal
edges_used_once
edges
1, 5, 9, 10

Case 04 — idempotence

A ∪ B = A, except the second time

If B is contained in A, unioning them should return A unchanged. It did — once. Applied a second time, with the operand's faces coincident with the earlier union's imprint, it produced an open shell: four edges used exactly once, where a closed solid requires two.

The cause was a face that vanished quietly. Region extraction returned zero loops, the fragment loop therefore iterated nothing, and the only short-circuit that would have preserved the face fired earlier in the pipeline:

split_face_by_curves silently DROPPED any face whose post-arrangement
extract_regions returned 0 loops (the fragment loop iterates nothing; the only
unsplit short-circuit fires pre-arrangement). Trigger: a repeated coincident-
contained union whose re-imprint cuts diverge in vertex identity (the chamfer's
corner-clip) -- both coincident +X caps hit 0 loops and vanished; Union's
OnBoundary from_a-only rule dropped B's twin -> open shell (edges 1,5,9,10).
commit 955f9f7verbatim

The chamfer is what made it reproduce: its corner-clip caused the re-imprint to diverge in vertex identity, so the second union's cuts were not recognised as the same cuts. A control case without the chamfer does not reproduce, and is kept as a documented control rather than deleted.

The fix is a post-arrangement fallback — zero extracted loops with active cuts means preserve the face unsplit — and it was mutation-proven: disabling the fallback returns the identical open shell.

The part worth admitting

The test's own doc comment still says it is left #[ignore]d and instructs the reader to run it with --ignored. That is no longer true: the attribute is gone, the test runs, and the defect was fixed two and a half hours after the repro was banked. The comment outlived the bug it described. Documentation rot in a codebase whose thesis is that it cannot lie is worth printing rather than quietly correcting.

Case 05 — two layers agreeing on a lie

Four holes reported, no material removed

A bolt pattern on an off-origin part was drilled around the world origin. The agent received "holes: 4" and a sound certificate, and the volume never changed.

It took two independent failures to produce that, one on each side of the language boundary. The tool schema had no center parameter, so the argument was silently stripped before the request was ever sent — the structural-typing default that exists as a safety feature, acting as a data-loss channel. And the kernel, on receiving a difference whose tool never touches the target, returned a copy of the target as 200 and SOUND.

The second half is the one that matters here, because the first is a schema bug and the second was a philosophy bug. A cut that removes nothing is now a typed refusal:

"Difference tool does not intersect the target: the operands are disjoint,
 so the cut would remove nothing (target returned unchanged is not a result
 this kernel reports as success)"
operations/mod.rs:286DisjointDifference

The gate is deliberately narrow, and the narrowness is the interesting engineering. It fires only when faces were selected and neither operand contributed contact — so annihilation, where A is wholly inside B, still falls through to an empty result, and enclosed voids keep B's faces and never trip it.

if matches!(operation, BooleanOp::Difference) && !selected_faces.is_empty() {
    let any_contact = intersections.iter().any(|fi| { !fi.curves.is_empty() || ... });
    let tool_contributed = selected_faces.iter().any(|f| f.from_solid == solid_b);
    if !any_contact && !tool_contributed {
        return Err(OperationError::DisjointDifference);
    }
}
boolean.rs:596the gate

Mutation proof, from the commit: hardcoding the cylinder centre back to the origin goes red — caught by the new refusal rather than by the geometry.

Why two layers matter Either failure alone would have been visible. The schema strip alone would have drilled the wrong place and shown it. The blessing alone would have needed a caller who already passed the wrong centre. Together they produced a confident, certified, entirely wrong result — which is the argument for typed refusals at every layer rather than validation at one.
Case 05FIXED
reported holes
4
material removed
0
status returned
200 SOUND
now
400 boolean_disjoint
retryable
no

Case 06 — the institutional response

Where "I don't know" is a return value

The five cases above share a shape: the kernel had something true to say and said something else. The response was not more tests. It was making refusal and uncertainty into first-class types, so that the honest answer is expressible.

A tri-state instead of a boolean

Geometric tolerance verification returns a three-valued verdict, and the reasoning is in the type's own doc comment:

/// The verdict of a conformance check. A tri-state, never a bare bool, so an
/// unimplemented characteristic is reported honestly rather than as a pass.
///
/// The kernel does NOT yet verify this characteristic/feature combination.
/// Carries a machine-readable reason. Never substituted by a pass.
gdt/verify.rs:64Conformance::NotYetVerified

The measurement accessor returns an option, not a boolean — None when nothing was measured. An unimplemented check cannot silently read as conformant, because the type has nowhere to put that lie.

A refusal that names what it cannot do, and why

"Edges {} and {} share corner vertex {} with MIXED convexity (a convex blend
 edge and a concave blend edge meet here). …no single sphere/plane is tangent
 to both convexities. Mixed-convexity corners require an N-sided Gregory /
 GB-patch corner blend (Charrot-Gregory 1984; Vaitkus-Várady-Salvi GB-patches,
 CAGD 2018) — not yet implemented (Task #82 / F5)…"
lifecycle.rs:894NotImplemented

It names the entities, the geometric reason it is impossible with the current machinery, the literature that solves it, and the task tracking it. An agent can act on that; so can a person.

The commit that fixed a refusal rather than a feature

The message above used to be correct but misleading: a mixed-convexity corner fell through to a generic branch that called it a same-kind corner patch and recommended a workaround which does not apply. The operation failed either way. The commit changed nothing about what the kernel can do — only about what it says — and closed with the line that is the thesis of this entire page:

An honest refusal must also be an accurate one.
commit fcf9c2f3verbatim

And one refusal that was itself a bug

A blend refusal once advised applying each edge in a separate call. A later gate established that this is exactly the sequence that corrupts the solid. The advice had been recommending the corruption:

"Do NOT apply these edges in separate single-edge calls — sequential
 single-edge blends at a shared corner are unsupported (they corrupt the
 solid) and are refused."
lifecycle.rs:913verbatim

Two more worth naming: OpTimeout, which states that "the model is unchanged" because the operation ran on a discarded clone; and the pair EmptyResult and DisjointDifference — the same observable symptom split into two typed causes, "the answer is nothing" and "the cut would change nothing."

The distinction that matters Most systems treat error strings as plumbing — written once, never read, never tested. Here they are product surface: versioned, asserted against, and occasionally the entire subject of a commit.
"operation '{op_kind}' exceeded its
 {budget_secs}s time budget and was aborted;
 the model is unchanged"
error_catalog.rs:510OpTimeout
Coda Two admissions belong on this page. Case 04's documentation is stale — it describes a defect the code beneath it no longer has. Case 03's fix is landing as this sheet is written, which means its line citations describe history within days of publication. A casebook about a kernel that cannot lie is more credible for saying so than for quietly tidying up.