Skip to content

Raise the F06 mesh caps in code and cases - #150

Merged
axisrow merged 2 commits into
masterfrom
ao/work-the-upstream/feat-raise-mesh-caps
Oct 21, 2026
Merged

axisrow merged 2 commits into
masterfrom
ao/work-the-upstream/feat-raise-mesh-caps

Conversation

@axisrow

@axisrow axisrow commented Oct 21, 2026

Copy link
Copy Markdown
Collaborator

What this changes

F06 section 6 raised the hard mesh caps (decision on #141) so a plate with 64 holes of 1024 sides
fits, but the code still carried the old numbers, so the kernel, the engine blob validator and the
layer-engine budgets refused what the contract now admits. This raises every derived bound to the
contract values and updates the F06 case table:

  • Kernel shell/blob caps (crates/kernel/src/trimesh.rs): 262,144 vertices, 524,288 triangles,
    65,535 face-table entries (the u16 face index), 13,631,520-byte blob.
  • Extrusion build caps (crates/kernel/src/profile/extrude.rs): the same values plus 786,432
    topological edges and 1,114,111 features.
  • G05 profile admission (crates/kernel/src/profile/mod.rs): total profile points 131,072 (half
    the vertex cap; per-contour 1,024 points and 256 cavities unchanged).
  • Triangulation work budget (crates/kernel/src/profile/triangulate.rs): 150,000,000 →
    40,000,000,000 exact orientation evaluations. Ear clipping scans the remaining contour per
    candidate, so a cap-size profile costs on the order of n²/2 evaluations; at the old budget a
    profile the new caps admit passed admission and then died with a typed WorkBudget failure.
  • Operation production bounds (crates/kernel/src/ops/mod.rs): result triangles 8192 → 524,288;
    cap loops 64 → 257 (256 G05 cavities plus the outer loop), so a 64-hole plate can actually be
    cut or sectioned.
  • Engine blob validator constants (crates/engine/src/limits.rs): the new caps.
  • Layer-engine model profile (crates/layer-engine/src/lib.rs, plus a dated amendment in
    docs/design/layer-budgets-model-profile.md): array_items 32,768 → 1,572,864 — one derived
    mesh at the caps is 524,288 triangles = 1,572,864 indices per array; without this a legal
    cap-size body could not be derived into a USD layer.
  • F06 cases (tests/fixtures/contracts/f06-geometry-contract-cases-v0.1.json): F06-POS-27 and
    F06-NEG-11 to F06-NEG-14 carry the new cap numbers, plus the two derivations that quote the
    blob byte cap.
  • G07 bench: adds the cap body (64 round holes of 1020 edges) build/analyze timing and scales the
    near-cap structural-gate slab to the new caps.

The kernel certification capacity is deliberately untouched (GEO_KERNEL_CAPACITY): G06 analysis
of a cap-size body still stops with a typed Uncertain at the default budgets, and the bench
reports that instead of hiding it.

Fixes #147

Body-certification time at the new limits

Release build, macOS (Darwin 27), aarch64, cargo run --release -p beamcraft-kernel --example g07_bench (the harness prints min/median/max over repeated calls). Extrusion time covers
admission, triangulation, build and every self-check: an Extrusion exists only after its volume
certificate passed, so this is the cost of certifying the body, not only of building it.

Case master (before) this branch (after)
Plate, 1 round hole of 1020 edges — 2,048 vertices, exactly the old vertex cap 12.6 ms build, sealed 6.5 ms build, sealed
Plate, 64 round holes of 1020 edges — 130,568 vertices, 261,388 triangles, 6.79 MB blob refused at admission, GEO_ABOVE_LIMIT (TotalPoints) 8.2 s build, sealed (min of 3, median 8.2 s)
Plate, 128 round holes of 1020 edges — 261,128 vertices, 522,764 triangles, 13.59 MB blob, just inside every cap refused at admission 35.3 s build, sealed
G06 analyze of the sealed 64-hole body not reachable (body refused) 1.2 s (min) → Uncertain(PredicateBudget) at the default budgets
G06 analyze of the old-cap 1020-edge body 0.6–1.0 s → Uncertain(PredicateBudget) 0.6–1.3 s → Uncertain(PredicateBudget)
Structural gate alone: parse of the near-cap slab blob (260,642 vertices, 13.55 MB) 4,050-vertex slab 2.6 ms per parse (n=200)

The 1,020-edge body runs identical code on both sides; the 6.5–12.6 ms spread is machine load
between runs, not a changed path. The new cost is the expected superlinear ear clipping at
cap-size contours; it stays bounded by the work budget, which still refuses pathological contours
with a typed failure instead of hanging.

How you verified it

  • cargo fmt --all -- --check
  • cargo clippy --workspace --all-targets -- -D warnings
  • cargo test --workspace — every suite passes except six beamcraft-host output::tests
    cases on this macOS machine; they fail identically on unmodified upstream/master (verified by
    stashing this change and rerunning), match the known macOS symlink/std::env::temp_dir
    environment issue, and touch no code this PR changes.

New behaviour needs a test: the cap-boundary tests were rewritten for the new numbers
(one_above_the_face_cap_is_a_topology_limit and the at-cap refusal in
triangle_cap_is_enforced_before_any_triangulation, both refused after admission and before any
triangulation), the G05 total-points test now sits one contour above the 131,072 cap, the shell
validator's at-cap blob test follows the constants, and the engine validator's at-cap test scales
with them.

Never-crash

Every model file, IFC/DSTV import and keystroke is untrusted input (AGENTS.md §4).

  • No new unwrap/expect/panic!/todo! outside tests
  • No indexing or slicing with input-derived positions; allocations sized by input are capped
  • No unsafe

Provenance

Read AGENTS.md §1 and §2 before adding any asset.

  • Nothing taken from Tekla Structures or any Trimble product (assets, code, documentation, tables)
  • No GPL/AGPL code copied in
  • Every new asset has an entry in ATTRIBUTION.md (no new assets)

Anything a reviewer should look at first

  • The triangulation work budget (150 M → 40 G) is the judgement call: it must admit the
    square-of-contour cost of ear clipping at the new caps while keeping the documented
    bounded-refusal property. Measured above: 8.4 s and 35.3 s for the two cap-size bodies; a
    pathological contour still ends in a typed WorkBudget failure, never a hang.
  • MAX_TOTAL_MESH_BYTES (64 MiB snapshot retention) and the F05/host wire budgets are unchanged,
    as the contract allows: a delivery limit smaller than a body needs refuses delivery with
    GEO_BUFFER_LIMIT and never fragments a blob.
  • The face cap acceptance at exactly 65,535 faces is covered blob-level by the F06-POS-27
    validator cases; a full at-cap kernel build would be a minutes-long 65k-point extrusion in a
    debug test, so the kernel test pins the refusal side (one above the cap) and the success side
    stays covered by the below-cap and blob-level cases.

🤖 Generated with Claude Code

F06 section 6 raised the hard mesh caps (decision on #141) so a plate with
64 holes of 1024 sides fits, but the code and the F06 case table still
carried the old numbers and refused what the contract now admits. Bring
every derived bound up to the contract values: 262,144 vertices, 524,288
triangles, 65,535 faces (the u16 face index), 786,432 topological edges,
1,114,111 features and a 13,631,520-byte blob. The G05 profile total grows
to 131,072 points (half the vertex cap) and the triangulation work budget
grows with the square of the contours it now has to clip, so a cap-size
profile is still a bounded, typed refusal instead of an admission that
later dead-ends. The operation production bounds follow (524,288 result
triangles, 257 cap loops: 256 G05 cavities plus the outer loop), the
engine blob validator and kernel shell validator enforce the new caps,
the layer-engine array budget holds one derived mesh at the caps, and the
F06 cases at and above the caps (F06-POS-27, F06-NEG-11 to F06-NEG-14)
carry the new numbers.

The kernel certification capacity is deliberately untouched
(GEO_KERNEL_CAPACITY): G06 analysis of a cap-size body still stops with a
typed Uncertain at the default budgets, and the G07 bench now builds,
certifies and times such a body.

Fixes #147
@axisrow
axisrow marked this pull request as ready for review October 21, 2026 02:50
The 2026-10-21 amendment left two sentences of the layer-budgets design
note describing the boundary tests with the pre-raise numbers, so the
document contradicted the code it documents; state the current bounds.
Also reflow a comment wrap in the G09 budget test.

@axisrow axisrow left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR #150 review: Raise the F06 mesh caps in code and cases (head f27a090)

Verdict: approved. The fix commit f27a090 resolves both findings of the earlier round, and no new issues.

Fix commit verified

  • docs/design/layer-budgets-model-profile.md now states the live bounds: the model-profile boundary test holds arrays of 1,572,864 and rejects 1,572,865 entries — that is exactly what the parametric read.rs test charges through Budgets::MODEL.array_items, and entries is the precise unit there; the Evidence section now says the authored input bound is 524,289 points since the amendment, matching MODEL.array_items / 3 + 1 in authored.rs:1051. The document no longer contradicts the code.
  • The G09 comment wrap is fixed.

Carried over from the full review of f24b026 (unchanged by the fix)

  • The cap set is identical everywhere it lives — engine limits, the kernel shell validator (trimesh.rs), profile extrusion (extrude.rs): 262,144 vertices, 524,288 triangles, 65,535 faces, 786,432 edges = 3/2 of the triangle cap, 1,114,111 features = V+E+F, blob 32 + 24V + pad8(12T) + pad8(2T) = 13,631,520 — all matching the contract table (f06-geometry-contract-v0.1.md section 6) and the F06-POS-27 derivation.
  • check_limits runs before triangulation (extrude.rs:288-289); the new G05 cap tests are arithmetically exact (2+4+63x1024+1018 = 65,536 faces, one above; T = 4n+4h-4 = 524,800 at the 131,072-point cap), admission caps are inclusive, and the new ring() cavities follow the clockwise cavity convention.
  • g07_bench slab(360,360) = 260,642 / 521,280 / 13,553,360 sits inside the caps; the cap body builds 261,388 triangles; WORK_BUDGET 4e10 bounds the ~8.6e9 worst-case ear-clipping per cap.
  • OpLimits 524,288 triangles and 257 loops = MAX_CAVITIES + outer; layer-engine array_items 1,572,864 = 3x524,288 with FIRST_SLICE untouched; F05 buffer_bytes MAXIMA (16,777,216) still admits a cap blob; fixture cases F06-POS-27 and F06-NEG-11..14 match the implementation exactly.

Nothing requiring changes remains.

@axisrow
axisrow merged commit 06a67f2 into master Oct 21, 2026
4 checks passed
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.

Raise the F06 mesh caps in code and cases

1 participant