Skip to content

wire: face classification hooks (query.face_p1) in runner objects - #614

Merged
bherbruck merged 4 commits into
tangency-labs:mainfrom
tdamsma:claude/face-p1-hooks
Oct 23, 2026
Merged

bherbruck merged 4 commits into
tangency-labs:mainfrom
tdamsma:claude/face-p1-hooks

Conversation

@tdamsma

@tdamsma tdamsma commented Oct 23, 2026

Copy link
Copy Markdown
Contributor

Machine-generated (Claude Fable 5.1 coordinator, Claude Opus 5.5 agent) on behalf of @tdamsma.

Found

  • The query.face_p1 deferrals came from four DISPATCH GAP stubs. There was no runner-side producer:
    • intersect::curve_class::p7 (ClassifyFaceInterval: EdgeCurveOnClassify and Point3DClassify)
    • intersect::topology_solver::p1 (SmTLSPointFace::SolveIt: Point3DClassify)
    • topology::brep::p9 (inner-loop transfer: Point3DClassify)
    • topology::face::p3 (FaceIntersect touching points). Left alone: it is a FaceIntersect bridge.
  • Every remaining query.face_p1 deferral goes through query::face::p2::curve_on_classify. That code wraps the caller's objects in WithMadeTrimCurves, which does not forward topology_entity, so the face handle cannot be resolved. p2.rs is Codex-owned and not edited here. The forwarding already exists on codex/primitive-p2-production (4526f4aa0).
  • Once that forwarding is in, newly reachable code shows disagreements outside query.face_p1. Details are in plan/findings.md:
    • heal.face_props has 8 failures and intersect.curve_class_p4 has 2. Rust classifies a seam crossing at an edge end as EDGE (t=1.0); C++ classifies it as VERTEX.
    • topology.brep_p3 hit an empty BrepCache. This is fixed here.

Done

  • p7: face_edge_curve_on_classify / face_point_3d_classify resolve the face (and edge) through ClassGeometry::topology_entity.
    • They call query::face::p1 on a copy of that B-rep, because the upstream const members may add UV trim curves. The C++ argument list is kept.
    • The classification is mapped back with topology_handle_in. An edge from another B-rep gives "not inside", as upstream.
    • An unresolved handle keeps the query.face_p1 deferral.
  • topology_solver p1: the Point3DClassify retry pair (tol, then 100*tol, boundary intersections on) runs on a copy of the B-rep that TopologyObjects::face_entity returns.
  • brep p9: point_3d_classify takes the caller's &mut Brep (guess UV, outer loop only).
  • brep p3: brep_curve_solve builds its cache with make_brep_cache (CacheMakeOrValidate), so the solve has trees.
  • plan: dated notes for query.brep, topology.brep_p8 and sweep.api_surfaces. A findings entry covers the blockers and the latent disagreements.

Result (Mac Studio runs; Linux CI is the gate). Before = main reports (CI 39939270570); after = this branch.

  • query.brep: before partial 1172/1089 pass, 83 deferred (query.face_p1 29) -> PARTIAL query.brep cases=1172 passed=1115 failed=0 deferred=57 max_rel_err=0e0 with_values=1115 no_values=0 vacuous=0 blocked_by=curve.curve_p2(9),topology.edgeuse_p3(2),topology.face_p2(46)
  • topology.brep_p8: before partial 339/336 pass, 3 deferred (query.face_p1 2) -> PARTIAL topology.brep_p8 cases=339 passed=338 failed=0 deferred=1 max_rel_err=0e0 with_values=338 no_values=0 vacuous=0 blocked_by=curve.curve_p2(1)
  • sweep.api_surfaces: before 882/862 pass, 20 deferred (query.face_p1 1) -> PARTIAL sweep.api_surfaces cases=882 passed=862 failed=0 deferred=20 max_rel_err=0e0 with_values=862 no_values=0 vacuous=0 blocked_by=boolean.topology_intersector_p2(17),surface.trim_srf_cache(3) (the deferral moves on)
  • Unchanged (blocked by WithMadeTrimCurves):
    • PARTIAL intersect.curve_class_p4 cases=3201 passed=2918 failed=0 deferred=283 max_rel_err=0e0 with_values=2918 no_values=0 vacuous=0 blocked_by=query.face_p1(97),topology.face_p4(186)
    • PARTIAL topology.brep_p3 cases=897 passed=812 failed=0 deferred=85 max_rel_err=0e0 with_values=812 no_values=0 vacuous=0 blocked_by=query.face_p1(38),topology.face_p3(47)
    • PARTIAL heal.face_props cases=1528 passed=1431 failed=0 deferred=97 max_rel_err=0e0 with_values=1422 no_values=9 vacuous=0 blocked_by=query.face_p1(27),topology.edge(1),topology.face_p4(69)
    • PARTIAL topology.face_p2 cases=2692 passed=2532 failed=0 deferred=160 max_rel_err=0e0 with_values=2179 no_values=353 vacuous=0 blocked_by=query.face_p1(19),query.face_p2(30),topology.edge(106),topology.face_p4(3),topology.vertex(2)
    • PARTIAL query.face_p2 cases=1344 passed=1326 failed=0 deferred=18 max_rel_err=0e0 with_values=1299 no_values=27 vacuous=0 blocked_by=query.face_p1(4),topology.edge(14)
    • PARTIAL topology.brep_p1 cases=2627 passed=2461 failed=0 deferred=150 max_rel_err=0e0 with_values=2416 no_values=45 vacuous=0 rejected=16 blocked_by=nurbs.b_spline_surface_n_lib_p2(8),query.face_p1(1),topology.edge(14),topology.face_p2(109),topology.face_p3(18)
    • PARTIAL query.face_p4 cases=500 passed=395 failed=0 deferred=105 max_rel_err=0e0 with_values=368 no_values=27 vacuous=0 blocked_by=query.face_p1(1),topology.edge(104)
  • Touched-source units:
    • PASS query.face_p1 cases=2266 passed=2266 failed=0 deferred=0 max_rel_err=0e0 with_values=2266 no_values=0 vacuous=0
    • PARTIAL intersect.topology_solver_p1 cases=3532 passed=3434 failed=0 deferred=98 max_rel_err=0e0 with_values=3434 no_values=0 vacuous=0 blocked_by=topology.edge(98)
    • PARTIAL intersect.topology_solver_p2 cases=2429 passed=2396 failed=0 deferred=33 max_rel_err=0e0 with_values=2396 no_values=0 vacuous=0 blocked_by=geom.tol(2),query.face_p2(8),surface.surface_p2(12),topology.edge(3),topology.face_p2(8)
    • PARTIAL topology.brep_p9 cases=684 passed=683 failed=0 deferred=1 max_rel_err=0e0 with_values=683 no_values=0 vacuous=0 blocked_by=topology.face_p2(1)
    • PARTIAL intersect.curve_class_p7 cases=1516 passed=1515 failed=0 deferred=1 max_rel_err=0e0 with_values=1515 no_values=0 vacuous=0 blocked_by=topology.vertex(1)
  • Checks (Mac, after merging origin/main): fmt, clippy (with and without difftest/cpp), cargo test --workspace and the wasm32 check all pass.
  • Skipped:
    • blend.fillet_solver_p5 (3 query.face_p1 deferrals) was not verified. It FAILs 100/100 on the Mac at main too (cpp_exception on both sides), so Linux CI decides.
    • No unit reaches green.

🤖 Generated with Claude Code

https://claude.ai/code/session_01RvuXmr7S5RoUXxVohC1giE

tdamsma and others added 4 commits October 23, 2026 13:38
…ehind resolved face handles

ClassifyFaceInterval (curve_class p7) and SmTLSPointFace::SolveIt (topology_solver
p1) call query::face::p1 on a copy of the B-rep their adapters resolve the face
handle to; topology::brep::p9's loop transfer classifies on its own &mut Brep.
LoopObjectCurves (face props) and UvLineObjects (sm_FaceClassifyUVLine) now
resolve their topology handles through ClassGeometry::topology_entity.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RvuXmr7S5RoUXxVohC1giE
…adapter hooks

The ray votes of OrientTrimmedSurfaces solved against an empty BrepCache (no
vertex, curve or surface trees: SM_ERR_NULL_POINTER where upstream's
CacheMakeOrValidate builds them); make_brep_cache builds them.

The LoopObjectCurves / UvLineObjects topology hooks are left for a follow-up:
together with the topology hook forwarding of query::face::p2's
WithMadeTrimCurves they expose disagreements outside query.face_p1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RvuXmr7S5RoUXxVohC1giE
@tdamsma
tdamsma marked this pull request as ready for review October 23, 2026 12:23
@bherbruck
bherbruck added this pull request to the merge queue Oct 23, 2026
Merged via the queue into tangency-labs:main with commit 10a9297 Oct 23, 2026
7 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.

2 participants