session-prompts.md: one self-contained, copy-paste prompt per pending session,
each naming the model (Sonnet/Haiku/Opus), the findings + audit doc, the
build/test commands, and the branch/push/PR + review-gate workflow. S6 carries
the G0 precondition. Linked from finding-orchestration.md.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Update finding-orchestration.md (master table I1/H1/N7 → ✅, S2 session marked
done with the original plan folded into a <details>), README headline cells +
next-batch pointer (now S3), and the test-coverage / numerical-stability audit
banners. S2 was implemented directly by Opus in the warm post-refactor session
(commit 90e966a); 301/301 tests green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Session 1 (2026-05-31) resolved 26 findings across Sonnet/Haiku/Opus; 298/298
CGAL tests green. Bring the audit docs in line with reality:
- README.md: G0 banner now records that the original authors were contacted by
email about porting/relicensing rights (awaiting reply); headline-status cells
updated per finding; new "Session 1 — implemented" record; link to the plan.
- Per-audit resolution banners (api-performance, numerical-stability,
input-validation, test-coverage, math-citation, thread-safety) + G0-blocked
banners (cgal-submission, dependency-license).
- NEW finding-orchestration.md: the meta-plan mapping every finding to a session,
an implementing model (Haiku/Sonnet/Opus by the "how much must be understood"
rule), and an Opus review gate after each implementation session. Records S1
(done) and lays out S2–S6 so the next session can be picked up cold.
Docs only — no code change.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The hyper-ideal vertex scale b is floored to keep the geometry valid. The
original clamp `b<0 → 0.01` mirrors the Java oracle but is only C⁰ (in fact
value-discontinuous at b=0): a Newton step crossing the feasibility boundary
hits a kink that can stall convergence (numerical-stability audit N3).
Rather than replace the Java-faithful behaviour (which would break the golden
parity tests), make the floor a selectable mode so BOTH the Java standpoint
and the clean mathematics are available:
- HyperIdealScaleClamp::HardJava (DEFAULT) — the original snap, bit-for-bit
faithful to HyperIdealFunctional.java → all parity tests unchanged.
- HyperIdealScaleClamp::SmoothBarrier — C¹ softplus floor
b ↦ floor + softplus_β(b−floor), β = HYPER_IDEAL_SCALE_SHARPNESS (=100);
≈ identity away from the floor, smooth across b=0. Opt-in.
clamp_hyper_ideal_scale centralises the logic (also folds in the N4 nachzügler:
compute_face_angles used a bare 0.01). The mode threads with a defaulted
trailing parameter through compute_face_angles, face_angles_from_local_dofs,
evaluate_hyper_ideal, the four hyper_ideal_hessian* variants and
newton_hyper_ideal — so every existing call site keeps HardJava behaviour.
Tests (+4): clamp-function C¹/floor/identity contract, mode-equivalence away
from the boundary, and end-to-end SmoothBarrier convergence to the same Java
golden vector (LawsonHyperIdeal). 296/296 CGAL tests pass.
Documented in doc/math/geometry-modes.md.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds a comprehensive 'External audit documents' section to the reviewer index:
- groups all 12 audits (correctness, API/perf/packaging, robustness)
- surfaces G0 (porting rights) as the cross-cutting release blocker
- records the decisions taken: coverage gate 80/70/90, API naming A1-A5
(A1-A3 implemented in PR #36, A4-A5 deferred pending G0/G1)
- points a new session at the low-risk quick-win findings
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Checks code/docs against the published mathematics (vs java-port-audit which
checks code vs Java):
- M1: Kolpakov-Mednykh volume formula used in code but missing from references.md
- M2: BPS circle-packing paper cited as '2010' in code vs '2015' in references.md
- M3: post-2023/preprint citations back unimplemented phases — re-verify + clarify
scope before submission
- M4: no canonical citation-key convention
- M5: large derivations numerically validated but prose unreviewed — expert sign-off
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Closes the dimensions the prior audits did not cover:
- numerical-stability: tolerance hierarchy (FD-step vs Newton tol), discontinuous
clamps, cancellation in cotangent/area, magic constants.
- input-validation: malformed JSON/XML deserialization, NaN/Inf vertex coords on
load, schema-drift handling.
- thread-safety: no mutable static state (good); undocumented same-mesh concurrency
contract; Eigen threading.
- dependency-license: existing THIRD-PARTY-LICENSES matrix is sound but predicated
on the MIT premise that G0 undermines; test meshes have no provenance/license.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Finding-U6 from doc/reviewer/usability-audit-2026-05-31.md.
The Finding-D fix (external-audit-2026-05-30) added a clean one-call
gauge-vertex overload:
assign_euclidean_vertex_dof_indices(mesh, maps, gauge_vertex)
But all user-facing code still showed the old verbose manual loop:
auto vit = mesh.vertices().begin();
maps.v_idx[*vit++] = -1;
int idx = 0;
for (; vit != mesh.vertices().end(); ++vit) maps.v_idx[*vit] = idx++;
Replaced in three places:
README.md 'Minimal usage' code block
example_euclidean.cpp Step 3
example_layout.cpp pin_first() helper
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
U4 (README.md:17) — status line: v0.9.0 → v0.10.0, test count 0 → 277
U5 (Discrete_conformal_map.h:6-16) — \file Doxygen block rewritten:
was: 'provides a single function … Spherical/hyperbolic scheduled for Phase 8b.2'
now: lists all three discrete_conformal_map_* functions already present,
plus pointers to the circle-packing companion headers
U7 (getting-started.md) — new 'Mode 4 — Low-memory build' section added
after Mode 3; shows CONFORMALLAB_LOW_MEMORY_BUILD=ON with -j1 and explains
the -O0 / no PCH / batch-1 tradeoffs for Raspberry Pi / ≤ 4 GB runners
U8 (README.md compile-time modes) — LOW_MEMORY_BUILD entry added to the
compile-time workflow code block with a one-line explanation and the
mandatory -j1 note
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Finding-U3 from doc/reviewer/usability-audit-2026-05-31.md.
Three concrete errors corrected:
1. check_gauss_bonnet() row (was: implies all map types work)
→ now: 'EuclideanMaps/SphericalMaps only' — HyperIdealMaps overload
is = delete (compile error since external-audit Finding-B fix)
2. enforce_gauss_bonnet() row (same issue)
→ same restriction note added
3. newton_hyper_ideal() preconditions (was: 'lambda0 initialised')
→ WRONG: HyperIdeal computes lengths from b_v, a_e via zeta functions
internally; lambda0 plays no role. Correct precondition:
'no lambda0 needed · no GB pre-check'
→ Added explanation: strictly convex energy (Springborn 2020 Thm 1.3)
→ Newton converges for any targets without a pre-check
Gauss-Bonnet prose section also updated:
- Examples now show EuclideanMaps/SphericalMaps explicitly
- HyperIdeal compile-error note added with the correct hyperbolic
identity Σ(2π-Θ_v) - Area = 2π·χ and why no pre-check is needed
- Open-mesh note added (GB identity does not hold for boundary meshes)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
U10: CLI has no parameter reference in README or getting-started.md.
Documents all 7 current flags with defaults in the audit file so
a future session can add the table to getting-started.md.
U11: Three useful CLI gaps documented as a roadmap item:
- --tol / --max-iter: Newton solver tuning, currently hardcoded
- -g cp_euclidean / -g inversive_distance: Phase-9a models not
reachable from CLI despite being fully implemented in the library
Each item has an effort estimate (~30 min / ~2 h) and concrete
acceptance criteria so a future session can pick it up cold.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Finding-U1 and Finding-U2 from doc/reviewer/usability-audit-2026-05-31.md.
The existing examples (example_euclidean, example_layout, example_hyper_ideal)
all used the "natural theta" pattern which makes x*=0 trivially the
equilibrium — u_v ≈ 0 everywhere, no deformation. A new user following
these examples saw solver output but not conformal geometry.
New: example_flatten.cpp
- PRIMARY USE CASE: conformally flatten a mesh to the plane
- Sets Θ_v = 2π for all interior vertices (flat target)
- Pins boundary vertices (no Gauss-Bonnet check for open meshes)
- Demonstrates non-trivial u_v (cathead.obj: range ≈ 2.96, 5 Newton iters)
- Documents the difference from "natural theta" explicitly
New: example_cgal_api.cpp
- Demonstrates CGAL::discrete_conformal_map_euclidean (Discrete_conformal_map.h)
- First runnable CGAL public API example; contrast with internal API
- Documents the "natural theta" default behaviour and explains why u_v=0
- Explains when to use CGAL API vs internal API
Both examples registered in code/examples/CMakeLists.txt and compile
cleanly with -DWITH_CGAL=ON.
Updated:
- example_euclidean.cpp: prominent "TESTING CONVENTION" warning
- example_layout.cpp: same warning on set_natural_theta helper
- doc/getting-started.md: example_flatten is now the recommended
"start here" example; note on natural-theta behaviour added
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
External documentation and usability review of v0.10.0.
9 findings covering documentation correctness, API usability,
and new-user experience.
Critical:
U1 — All examples show trivial identity map (natural theta),
not real conformal flattening — new users see no-op output
U2 — CGAL public API has zero runnable examples
Medium:
U3 — contracts.md incorrect: check_gauss_bonnet row missing
HyperIdeal restriction (deleted overload after Finding-B)
U4 — README still shows v0.9.0 (current: v0.10.0, 277 tests)
U5 — Discrete_conformal_map.h header comment describes Phase-8a
state; all 5 entry functions already implemented
U6 — New gauge-vertex overload (Finding-D) not reflected in
README or examples — old verbose loop still shown
Minor:
U7 — CONFORMALLAB_LOW_MEMORY_BUILD absent from getting-started.md
U8 — CONFORMALLAB_LOW_MEMORY_BUILD absent from README table
U9 — Layout2D.uv index semantics undocumented (v.idx() contract)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Finding-I from doc/reviewer/external-audit-2026-05-30.md.
Root cause: CGAL+Eigen at -O3 drives cc1plus peak RAM to ~700 MB per
Unity compilation unit (batch size 4) on ARM64. With the 1600 MB
container limit the 2nd or 3rd TU reliably triggered OOM-kill, so
test-cgal was gated off via `if: false` since 2026-05-26.
Fix: new CMake option CONFORMALLAB_LOW_MEMORY_BUILD=ON applies four
orthogonal memory-saving measures to conformallab_cgal_tests:
1. -O0 (no debug info): optimizer passes entirely skipped → cc1plus
peak drops from ~700 MB to ~150-200 MB per TU on ARM64.
Omitting -g avoids the additional object-file / linker RAM cost.
2. CONFORMALLAB_USE_PCH=OFF: saves the one-time ~200 MB PCH
compilation cost; each TU re-parses CGAL headers (fast at -O0).
3. UNITY_BUILD_BATCH_SIZE=1: one source file per cc1plus invocation,
removing the "4-file template-explosion" per-unit multiplier.
4. -Wl,--no-keep-memory (GNU ld): linker releases symbol tables after
each input file → ~15-25 % less linker RSS.
Verified locally with cmake -DCONFORMALLAB_LOW_MEMORY_BUILD=ON:
277/277 CGAL tests pass, 31 s runtime (vs 2 s at -O3 — expected;
tests run 15× slower without optimizer but all correct).
CI workflow changes (cpp-tests.yml):
- test-cgal re-enabled: `if: github.event_name == 'pull_request'`
- Configure step adds -DCONFORMALLAB_LOW_MEMORY_BUILD=ON
- Container memory: 1600m → 2000m (--memory-swap=3000m for 1 GB swap
headroom), using ~half of the Pi's 3-4 GB while leaving OS margin.
CLAUDE.md updated: new flag added to compile-time options table; CI
status row corrected from DISABLED to active.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
MINOR-1 (spherical_functional.hpp:426)
Wrong comment said "second derivative < 0 for a convex functional".
The spherical energy is *concave* (NSD Hessian); the monotone-f argument
applies to both convex and concave functionals equally. Comment rewritten
to explain the actual physics: increasing scale increases all angles and
thus reduces Σ G_v.
MINOR-2 (spherical_functional.hpp:494-495)
Forward finite difference O(ε) → central finite difference O(ε²):
old: dft = (sum_Gv(t + fd_eps) - ft) / fd_eps
new: dft = (sum_Gv(t + fd_eps) - sum_Gv(t - fd_eps)) / (2*fd_eps)
Same cost when the extra sum_Gv(t - fd_eps) replaces the cached ft.
MINOR-3 (euclidean_functional.hpp, spherical_functional.hpp,
inversive_distance_functional.hpp)
New header gauss_legendre.hpp centralises the 10-point Gauss-Legendre
nodes and weights (gl10_nodes() / gl10_weights()). The three energy
functions now use the shared accessors instead of duplicated local
static arrays.
MINOR-4 (euclidean_functional.hpp, spherical_functional.hpp,
hyper_ideal_functional.hpp, inversive_distance_functional.hpp)
halfedge_to_index() centralised in conformal_mesh.hpp. All four local
aliases (eucl_hidx, spher_hidx, hidx, id_detail::hidx) now delegate to
it as one-line wrappers; the aliases are kept for now to avoid a larger
call-site churn, clearly documented as thin wrappers.
MINOR-5 (clausen.hpp:33-38)
Added a comment above inits() explaining the intentional off-by-one
return value and how it interacts with csevl() — matching the Java
Clausen.inits() / csevl() contract.
277/277 CGAL + 26/26 pure-math tests pass, 0 failed.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Finding-E from doc/reviewer/external-audit-2026-05-30.md.
Scan also uncovered the same issue in inversive_distance_functional.hpp.
Three functions used absolute error `|analytic - fd| > tol` while the
rest of the library (euclidean_functional, spherical_functional,
euclidean_hessian, hyper_ideal_functional) all use relative error
`|analytic - fd| / max(1, |analytic|) > tol`.
Absolute error is too strict for large gradients (false failures) and
too lenient for small gradients.
Fixed:
cp_euclidean_functional.hpp gradient_check_cp_euclidean()
cp_euclidean_functional.hpp hessian_check_cp_euclidean()
inversive_distance_functional.hpp gradient_check_inversive_distance()
All three now use the relative criterion and accumulate all failures
before returning (ok=false instead of early return on first mismatch).
Default tol updated from 1e-6/1e-5 to 1e-4, matching the Java
FunctionalTest convention used by all other checks in the library.
Error message updated to print rel-err instead of raw diff.
266/266 CGAL tests pass, 0 failed.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Finding-D from doc/reviewer/external-audit-2026-05-30.md.
All three DOF-assignment functions iterated over every vertex
unconditionally, overwriting any v_idx set before the call. The
documentation said "pin before OR after" — the "before" option was
silently wrong (the pin would be overwritten). For the
inversive-distance variant the doc explicitly said the pre-call pin
would make the function "a no-op for that vertex", which was false.
Changes (three headers):
- euclidean_functional.hpp assign_euclidean_vertex_dof_indices()
- spherical_functional.hpp assign_vertex_dof_indices()
- inversive_distance_functional.hpp assign_inversive_distance_vertex_dof_indices()
For each:
1. Single-arg overload: doc corrected to "pin AFTER, not before;
pre-call pins are overwritten"
2. New two-arg overload accepting a Vertex_index gauge: pins the
requested vertex (v_idx=-1) in a single pass, preventing the
user error entirely
Three new GTests in test_euclidean_functional.cpp:
SingleArg_PinBeforeHasNoEffect — documents the old pitfall
TwoArg_GaugeIsPinnedOthersAreSequential — verifies the new overload
TwoArg_NewtonConvergesWithGaugeOverload — end-to-end correctness
266/266 CGAL tests pass, 0 failed.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Finding-C from doc/reviewer/external-audit-2026-05-30.md.
The box comment at the top and the function-level comment above
euclidean_cot_weights() both stated:
cot_k = (t_adj1·l123 − t_adj2·t_opp) / denom2 ← WRONG
The correct formula (verified numerically on a 3-4-5 right triangle,
expected cot1=4/3, cot2=3/4, cot3=0) is:
cot_k = (t_opp · l123 − t_a · t_b) / denom2
where t_opp is the t-value of the edge OPPOSITE vertex k, and t_a/t_b
are the t-values of the two edges ADJACENT to vertex k.
The implementation in euclidean_cot_weights() was already correct;
only the documentation was wrong.
Changes (documentation only, zero code changes):
- Box comment: rewritten with correct formula and explicit per-vertex
assignment (cot1: t_opp=t23, t_a=t12, t_b=t31; etc.)
- Box comment: added missing ½ factor to Hessian contribution lines
- Function-level comment: corrected to (t_opp·l123 − t_a·t_b)/(8·Area)
with a pointer to the box comment for the full assignment
- Inline return comment in euclidean_cot_weights(): now shows the
mapping (cot1: t_opp=t23, t_a=t12, t_b=t31) directly at the formula
263/263 CGAL tests pass, 0 failed.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Finding-B from doc/reviewer/external-audit-2026-05-30.md.
The Euclidean Gauss–Bonnet identity Σ(2π−Θ_v) = 2π·χ is ONLY valid for
flat/Euclidean and spherical metrics. For hyperbolic metrics (HyperIdeal)
the correct identity is Σ(2π−Θ_v) − Area(M) = 2π·χ. The previously
provided gauss_bonnet_sum(HyperIdealMaps) overload would silently pass the
wrong LHS to check_gauss_bonnet, which would always throw "deficit = ±Area"
for valid hyperbolic targets.
Fix:
- gauss_bonnet_sum(mesh, HyperIdealMaps) → = delete + explanation comment
- enforce_gauss_bonnet(mesh, HyperIdealMaps&) → = delete + explanation comment
- Header box comment rewritten with the correct hyperbolic Gauss–Bonnet
identity and a clear "HyperIdeal: NOT SUPPORTED" section
New test in test_phase6.cpp:
- HyperIdeal_EuclideanSumDiscrepancy_DocumentsWhyCheckIsDeleted
verifies numerically that the Euclidean sum = 0 but 2π·χ = 4π for a
regular tetrahedron, documenting the −4π discrepancy that motivated
the deletion
- Three compile-time static_asserts (SFINAE) confirm the overload is not
invocable with HyperIdealMaps but remains so with Euclidean/SphericalMaps
263/263 CGAL tests pass, 0 failed.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Follow-up to the Finding-A fix (face_energy guard). The throw is the
correct safe behaviour for now; the mathematically complete solution
requires formulas for semi-ideal and fully-ideal tetrahedra that are
absent from the Java reference.
Adds a structured research entry to research-track.md (Phase 9b+):
- primary references: Kolpakov-Mednykh arXiv:math/0603097, Milnor 1982,
Vinberg 1985
- acceptance criteria: two new volume functions + gradient-check tests +
limiting-behaviour continuity witness
- explicit note that the throw in face_energy() must not be removed
without implementing and testing the replacement formulas
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Finding-A from doc/reviewer/external-audit-2026-05-30.md.
Root cause: both the Java reference (HyperIdealFunctional.java:222-231)
and the C++ port silently applied the one-ideal-vertex volume formula
to the first ideal vertex found in a face, ignoring any additional ideal
vertices. For two or three ideal vertices this produces a wrong energy
value with no diagnostic.
Fix: add an ideal_count guard at the top of face_energy() that throws
std::logic_error for ideal_count >= 2. The one-ideal (Kolpakov-Mednykh)
and zero-ideal (Meyerhoff/Ushijima) paths are unchanged and correct.
Three new GTests cover the three guard cases:
MultiIdealGuard_TwoIdealVertices_Throws (two ideal → throw)
MultiIdealGuard_AllThreeIdealVertices_Throws (all ideal → throw)
MultiIdealGuard_ExactlyOneIdeal_DoesNotThrow (one ideal → no throw)
262/262 CGAL tests pass, 0 failed.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Full external code review of v0.10.0 against all math-critical headers
(direct source read, not automated scan). Documents 5 open bugs/API errors,
3 test gaps inherited from java-port-audit.md, 1 architectural CI risk,
and 5 minor findings. Each finding is self-contained with file+line
references, a concrete fix proposal, and acceptance criteria so a new
session can pick up any single finding without prior context.
Key findings:
- FINDING-A (critical): face_energy() wrong for mixed ideal/hyper-ideal configs
- FINDING-B (medium): Gauss–Bonnet API conceptually wrong for HyperIdeal
- FINDING-C (medium): cotangent formula in euclidean_hessian.hpp header is wrong
- FINDING-D (medium): DOF-assignment doc falsely claims "pin before" works
- FINDING-E (medium): cp_euclidean gradient_check uses absolute not relative error
- FINDING-F/G/H: three open test gaps from java-port-audit.md
- FINDING-I (arch): 246/272 CGAL tests not gated in CI
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Upgrades the cyclic Euclidean Hessian from block-FD to closed-form, satisfying
the novelty-statement §3.2 "analytic Hessians, not finite difference" claim for
the Euclidean path.
- euclidean_hessian.hpp: `euclidean_hessian_analytic` — closed-form cyclic
Hessian from the law-of-cosines angle derivatives
∂α_i/∂s_i = ℓ_i²/4A, ∂α_i/∂s_j = ½cot α_i − ℓ_j²/4A (Σ_j = 0),
chained to (u, λ_e) and sign-mapped to the gradient outputs (−α vertex,
+α_opp edge). Reuses euclidean_cot_weights. Block-FD kept as cross-check.
- newton_solver.hpp: newton_euclidean cyclic path now uses the analytic Hessian.
- tests: CyclicHessian_Analytic_MatchesBlockFD_Tetrahedron — analytic == block-FD
(1e-6), == gradient FD (1e-5), symmetric (1e-9). Existing cyclic convergence
oracle still GREEN with the analytic Hessian routed in.
Tier-2 (Wente) finding: wente_torus02.obj is a QUAD mesh (1240 quads) and the
Java golden comes from cyclic (quad-net) uniformization; the C++ period-matrix
pipeline is triangle-based, so a faithful bit-vs-Java τ comparison needs a
quad/cyclic pipeline (Phase 9f). Deferred and documented; golden τ = ½+i√3/2.
244/244 cgal tests pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Build-verified attempt to port the Java EuclideanCyclicConvergenceTest
(cathead, "circular hole edge" φ = π−0.1).
- ✅ GREEN `CyclicCircularEdge_PhiEntersGradient_CatHead`: solver-free
cross-validation that the circular-edge φ target enters the cyclic edge
gradient exactly (ΔG_e = −Δφ_e at 1e-12; no other component moves).
- ⏸️ DISABLED `CyclicCircularEdge_CatHead_JavaXVal`: the full Java convergence
assertion (α_opp+α_opp = π−0.1), kept with golden semantics. Auto-activates
once the edge-DOF Hessian lands.
Build-verification finding: `newton_euclidean` -> `euclidean_hessian` throws
"edge DOFs are not supported" — the cyclic full solve is blocked by a missing
edge-DOF Euclidean Hessian (gradient supports edge DOFs, analytic Hessian does
not). Spherical convergence (Tier-1 #2) is already covered by test_newton_solver.
Documented in doc/reviewer/java-ignore-crossvalidation.md.
All 13 EuclideanFunctional tests pass (1 disabled).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Classifies the 22 Java @Ignore'd test files by root cause (ARM64 PETSc
native lib vs logic/known-issue) and by cross-validation value for the
C++ port.
- Notes what PR #27 already locks (math cores + functional-eval oracles)
to avoid duplication.
- Priority ranking: HIGH (HyperIdeal Lawson convergence golden vector —
records the exact u*), MEDIUM (genus-1 Wente uniformization, branch-point
variant), LATER (genus-2/hyperelliptic/Mobius/quasi-isothermic/Schottky),
NON-ORACLE (Java gaps: testHessian, testDoLayout; ARM64-flaky known issues).
- Documents why the Lawson mesh needs a low-level half-edge generator
(4 vertices / 12 edges => multi-edges; CGAL add_face cannot build it).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Infrastructure table: add Matrix (→ Eigen inline, done) and P2 rows.
P2 marked "port inline with Phase 9c" — almost exclusively consumed by
FundamentalPolygon/CanonicalForm/SurfaceCurve (all Phase 9c), so building
p2_geometry.hpp as a standalone ahead of 9c would be dead weight.
- Phase 9c rows in the utility table: ⚠️ annotation listing the exact P2.*
methods needed (makeDirectIsometryFromFrames, projectP3ToP2,
imbedMatrixP2InP3) plus the P2Big/cpp_dec_float_50 high-precision
prerequisite for the group-relation product ∏gᵢ = Id.
Ensures a future Phase 9c session starts with full context and does not
discover the jReality/precision dependencies mid-port.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Ports the small but pervasive de.jreality.math.Pn surface that the Java
algorithmic core uses across every not-yet-ported geometric phase:
HyperbolicLayout, SphericalLayout, FundamentalPolygon (9c), KoebePolyhedron
(10c'), quasi-isothermic (10e), hyperelliptic theta, CircleDomain (11c).
Porting it once unblocks all downstream consumers instead of re-deriving
the metric ad hoc per phase.
pn_geometry.hpp — header-only, Eigen, ~120 LOC:
PnMetric { EUCLIDEAN=0, ELLIPTIC=+1, HYPERBOLIC=-1 } matching jReality.
pn_inner_product — bilinear form per signature.
pn_norm / pn_dehomogenize / pn_set_to_length / pn_normalize.
pn_distance_between — Euclidean (spatial), elliptic (acos), hyperbolic (acosh).
pn_linear_interpolation — affine (E) and slerp (S/H constant-speed geodesic).
HYPERBOLIC uses the timelike-positive ("upper-sheet") convention, identical to
the already-verified projective_math.hpp::hyperbolicDistance; pn_distance_between
is regression-anchored against it in the tests.
test_pn_geometry.cpp — 6 tests, all GREEN:
InnerProductSignatures, EuclideanDistance, EllipticDistanceIsAngle,
HyperbolicDistanceClosedFormAndAnchor (+ projective_math.hpp anchor),
NormAndScaling, LinearInterpolationGeodesic.
doc/roadmap/java-parity.md — new "Infrastructure / support layers" section:
de.jreality.math.Pn → pn_geometry.hpp (partial, 6 fns covering core usage)
de.jreality.math.Rn → Eigen (no separate port needed)
MatrixBuilder → not yet (only needed for hyperelliptic theta)
conformallab XML types → not planned (GUI persistence, not algorithmic)
246/246 cgal tests pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add bit-for-bit (1e-12) golden-value oracle tests pinning the C++ pure-math
and functional cores against the compiled upstream Java library (openjdk 17):
- HyperIdealGoldenJava: Clausen/Л/ImLi2, ζ13/14/15/ζ, both tetrahedron-volume
formulas (real de.varylab…Clausen / HyperIdealUtility).
- EuclideanGoldenJava / SphericalGoldenJava: angle formulas + β relations + Л
energy terms, plus FULL-MESH oracles driving the real EuclideanCyclicFunctional
/ SphericalFunctional on a shared tetrahedron — per-vertex gradient (Θ−Σα) and
ΔE = E(x)−E(0) (C++ Gauss-Legendre path integral vs Java closed form).
- SphericalGoldenJava.FullMeshEdgeDofGradient: edge-DOF gradient (vertex + edge
components, α_opp⁺+α_opp⁻−θ_e) vs raw conformalEnergyAndGradient — locks
Finding 3 at the solution level (audit items 4 & 5).
- PeriodMatrix.NormalizeModulus_GoldenJava: τ-reduction fold convention vs the
real DiscreteEllipticUtility.normalizeModulus (audit items 7 & 8).
Subtlety documented: the spherical oracles call Java's raw
conformalEnergyAndGradient, not evaluate() (which pre-runs a Brent gauge
maximization that C++ factors into the Newton solver's spherical_gauge_shift).
Also:
- P1-2 (layout.hpp): Euclidean holonomy now uses a per-cut-edge rigid-motion fit
g(z)=a·z+b, exposing residual_rotation = |arg(a)| as a diagnostic; non-
regressive (flat case a=1 reduces to the old midpoint formula).
- P1-3 (period_matrix.hpp): is_in_fundamental_domain fixed to the correct
half-open SL(2,ℤ) domain (−½ ≤ Re < ½). Updated the now-exposed
ComputePeriodMatrix_ReducedTau_InFD to assert the normalizeModulus domain
(closed +½ edge) instead.
Test counts (single source of truth = doc/api/tests.md): 272/272 pass, 0
skipped (26 non-CGAL + 246 CGAL).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The Java uniformization classes (FundamentalPolygonUtility, CanonicalFormUtility)
rely on the *Big arbitrary-precision geometry (MathContext(50)) because products
of hyperbolic isometry generators grow exponentially and double fails to verify
the group relation ∏gᵢ = Id. Record this planning-relevant prerequisite and
resolve the contradiction in java-parity.md, which previously listed *Big as
permanently out of scope.
- CLAUDE.md: † note on the Phase-9 not-yet-ported table
- java-parity.md: *Big exception (localized high-precision substrate for 9c/10)
- phases.md: precision prerequisite as 9c sub-task + effort estimate
- design-decisions.md: new "Scalar type: double, with one localized exception"
Core flattening (Newton/energy/Eigen solver) stays double; the substrate
(cpp_dec_float_50 / mpreal) is localized to the uniformization module only.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Cross-referenced all 232 Java classes against the roadmap. New plan
entries for genuinely-useful, previously-unplanned items:
- 9g.1 conformal quality measures (Isothermicity, ConformalEquivalence,
FlippedTriangles, LengthCrossRatio + ConvergenceUtility metrics)
- 9g.2 optional period-matrix convergence experiment (method only;
Java harness depends on Mathematica/JLink + jReality, not ported)
- DEC operator layer (heds/dec/) noted as a 10a prerequisite
- HomotopyUtility -> 10a (explicit generator cycles; not covered by
cut_graph.hpp, which yields only the 2g cut edges)
- SurfaceCurveUtility -> 9c; MercatorTextureProjection -> 9d.3 companion
Documented as deliberately out-of-scope: SpanningTreeUtility (subsumed
by cut_graph.hpp), convergence/* harness, datasource/* (jReality viewer
decoration), *Big arbitrary-precision geometry, jReality GUI, and the
MTJ/Tao/PETSc solver bindings.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Refresh CLAUDE.md for v0.10.0 (3 CI jobs incl. disabled test-cgal,
compile-time option matrix, reviewer/pages docs, agentic + token-hygiene
workflow patterns) and condense the historical Phase-8/audit logs to
pointers.
Add the documentation-pass process so the single-source-of-truth rules
stay enforced:
* scripts/quality/check-doc-freshness.sh — string-only drift gate
(version/date across CITATION/CHANGELOG/CLAUDE, doc-map count), <1 s,
registered in run-all.sh + quality README.
* doc/release-policy.md — "Documentation passes" subsection (triggers +
docs:sync rule); fix stale Phase-milestone mapping (v0.10.0 was
reviewer-ready, 9c→v0.11.0) and the test-cgal CI mention.
Add shared Claude config (un-ignore the two files only):
* .claude/settings.json — permission allowlist for safe repo commands.
* .claude/token-hygiene.md — Tier-3 cache-discipline user guide that
CLAUDE.md instructs Claude to remind the user about.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Two bugs in the reviewer hub HTML:
1. The earlier sed-rewrite that lifted the hub from
`preview/reviewer-snapshot-v6` into `branch/main` accidentally
produced `branch/branch/main` — sed pattern matched the
`preview/reviewer-snapshot-v6` slug but the surrounding URL
already had `/src/branch/` prefix. All 25 in-hub links to the
repo were broken with 404 on codeberg.org.
Fix: `s|/src/branch/branch/main/|/src/branch/main/|g`.
2. The version pill in the badge strip still read v0.9.0 (stale
from the original v0.9.0-era hub template). Updated to v0.10.0.
The fix is in this in-repo source-of-truth file so any future manual
republication of the pages branch picks up the corrected hub. The
just-pushed pages branch already has the fix applied; codeberg's
`tmoussa.codeberg.page` frontend cache (max-age=600 s) will refresh
over the next 10 minutes.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Three small cleanups surfaced by running the full gate sweep on the
merged main:
1. CGAL conventions (CGAL-2 \\file briefs)
doc-only headers `Conformal_map/doxygen_groups.h` and
`Conformal_map/doxygen_namespaces.h` were missing the `\\file`
brief required by the CGAL conventions check. Added both.
2. codespell — three new triggers
`code/tests/cgal/CMakeLists.txt` uses "honour", `doc/reviewer/hub.html`
uses `<thead>` (HTML tag, false-positive for "thread"), and
`doc/roadmap/research-track.md` uses "optimiser". All three are
British-English / HTML usage; added to `.codespellrc` ignore list.
3. Doxygen warning in `doc/architecture/compile-time.md:250`
A trailing backtick-quoted CMake flag at end-of-file confused
Doxygen's markdown parser into starting a never-closing verbatim
block. Rewrote the line to put the prose first and the backtick
in the middle, not at end-of-file.
All gates green again on the merged main:
✅ 259/259 tests pass
✅ test-count consistency
✅ markdown links 166/166 resolve
✅ CGAL conventions 0/8 violations
✅ license-headers 68/68 carry MIT SPDX
✅ codespell 0 typos
✅ shellcheck 0 findings (18 scripts)
✅ Doxygen 100% coverage, 0 warnings
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>