docs+tooling: doc-freshness gate, documentation-pass policy, token-hygiene
All checks were successful
C++ Tests / test-fast (pull_request) Successful in 2m2s
API Docs / doc-build (pull_request) Successful in 1m8s
Markdown link check / check (pull_request) Successful in 52s
C++ Tests / test-cgal (pull_request) Has been skipped
C++ Tests / quality-gates (pull_request) Successful in 1m59s
All checks were successful
C++ Tests / test-fast (pull_request) Successful in 2m2s
API Docs / doc-build (pull_request) Successful in 1m8s
Markdown link check / check (pull_request) Successful in 52s
C++ Tests / test-cgal (pull_request) Has been skipped
C++ Tests / quality-gates (pull_request) Successful in 1m59s
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>
This commit is contained in:
151
CLAUDE.md
151
CLAUDE.md
@@ -45,6 +45,20 @@ cmake --build build -j$(nproc)
|
||||
|
||||
`-DWITH_CGAL=ON` automatically enables `-DWITH_VIEWER=ON`, which pulls in GLFW and requires `wayland-scanner`. Never use this in headless CI.
|
||||
|
||||
### Compile-time options (v0.10.0 matrix)
|
||||
|
||||
The CGAL test build defaults to **PCH + Unity Build ON** (CGAL test wall-time 78 s → 55 s, CPU time 676 s → 167 s on Apple M1). Opt-in/opt-out flags — full measurements + macOS-vs-Linux notes in `doc/architecture/compile-time.md`:
|
||||
|
||||
| Flag | Default | Effect |
|
||||
|---|---|---|
|
||||
| `-DBUILD_TESTING=OFF` | ON | Skip the entire test subtree (headers-only consumers). |
|
||||
| `-DCONFORMALLAB_USE_PCH=OFF` | ON | Disable precompiled headers for `conformallab_cgal_tests`. |
|
||||
| `-DCMAKE_UNITY_BUILD=OFF` | ON | Disable Unity (jumbo) build. |
|
||||
| `-DCONFORMALLAB_DEV_BUILD=ON` | OFF | Dev iteration: PCH on, Unity forced off (cheaper incremental rebuilds). |
|
||||
| `-DCONFORMALLAB_FAST_TEST_BUILD=ON` | OFF | `-O0 -g` for tests (faster compile, slower run). |
|
||||
| `-DCONFORMALLAB_USE_CCACHE=ON` | OFF | Route compiles through ccache. |
|
||||
| `-DCONFORMALLAB_HEADERS_CHECK=ON` | OFF | Standalone header self-containment check target. |
|
||||
|
||||
### Running a single test
|
||||
|
||||
```bash
|
||||
@@ -243,87 +257,50 @@ my_map[v] = 3.14;
|
||||
|
||||
## CI pipeline
|
||||
|
||||
Two jobs in `.gitea/workflows/cpp-tests.yml`:
|
||||
Three jobs in `.gitea/workflows/cpp-tests.yml`:
|
||||
|
||||
| Job | CMake flags | Deps | Triggers on |
|
||||
|---|---|---|---|
|
||||
| `test-fast` | *(none)* | Eigen + GTest only | all branches |
|
||||
| `test-cgal` | `-DWITH_CGAL_TESTS=ON` | + Boost | pull requests only |
|
||||
| Job | CMake flags | Deps | Triggers on | Status |
|
||||
|---|---|---|---|---|
|
||||
| `test-fast` | *(none)* | Eigen + GTest only | all branches | **active** |
|
||||
| `test-cgal` | `-DWITH_CGAL_TESTS=ON` | + Boost | pull requests only | **DISABLED 2026-05-26** (`if: false`) |
|
||||
| `quality-gates` | *(none)* | + codespell, shellcheck | all branches (`needs: test-fast`) | **active** |
|
||||
|
||||
Runner: `eulernest` — self-hosted Raspberry Pi, ARM64, Ubuntu 22.04. Docker image: `git.eulernest.eu/conformallab/ci-cpp:latest`. `test-cgal` needs `test-fast` to pass first (`needs: test-fast`).
|
||||
Runner: `eulernest` — self-hosted Raspberry Pi, ARM64, Ubuntu 22.04. Docker image: `git.eulernest.eu/conformallab/ci-cpp:latest`. `test-cgal` and `quality-gates` both need `test-fast` to pass first (`needs: test-fast`).
|
||||
|
||||
Expected results: full test suite passing, 0 skipped, 0 failed. The canonical counts live in `doc/api/tests.md` — do not hardcode them anywhere else (see [`doc/release-policy.md`](doc/release-policy.md)).
|
||||
`quality-gates` runs four required structural gates: `license-headers.sh`, `cgal-conventions.py`, `codespell.sh`, `shellcheck.sh --strict`. Seven more gates (clang-format, cmake-format, cppcheck, sanitizers, clang-tidy, multi-compiler, reproducible-build) are local-only — see `scripts/quality/README.md`.
|
||||
|
||||
**`test-cgal` is gated off** (`if: false`, see the DISABLED-2026-05-26 comment block in the workflow): the `-j1` CGAL build is too memory-heavy for the 1.6 GB runner and OOMs intermittently without exposing real regressions. Consequence: the two structural sub-gates that lived inside it — `scripts/check-test-counts.sh` and `scripts/try_it.sh` — are currently **un-gated**; run them locally before tagging a release. Re-enable by restoring `if: github.event_name == 'pull_request'`.
|
||||
|
||||
Two other workflows are also restricted to `workflow_dispatch:` only (auto-trigger disabled 2026-05-26 while the codeberg pages-branch push is being stabilised):
|
||||
- `.gitea/workflows/doxygen-pages.yml` — publishes Doxygen HTML + reviewer hub to the codeberg `pages` branch.
|
||||
- `.gitea/workflows/perf-compile-time.yml` — Linux ARM64 compile-time benchmark.
|
||||
|
||||
Expected results: `test-fast` + `quality-gates` green on every push, 0 skipped, 0 failed. The canonical counts live in `doc/api/tests.md` — do not hardcode them anywhere else (see [`doc/release-policy.md`](doc/release-policy.md)).
|
||||
|
||||
## Release state
|
||||
|
||||
Current release: **v0.9.0** (tag on `main`, released 2026-05-22).
|
||||
Phases 1–9a complete, Phase 8b-Lite CGAL API surface complete (all 5 DCE models reachable via `<CGAL/Discrete_*.h>`), Phase 9b block-FD HyperIdeal Hessian shipped (~96× speed-up). Next planned milestones: Phase 9c (4g-polygon, genus g > 1) and Phase 9b-analytic (Schläfli identity). See `doc/release-policy.md` for the version-tag policy and `doc/roadmap/phases.md` for the phase plan.
|
||||
Current release: **v0.10.0** (tag on `main`, released 2026-05-26 — the "reviewer-ready" release).
|
||||
Phases 1–9a complete, Phase 8b-Lite CGAL API surface complete (all 5 DCE models reachable via `<CGAL/Discrete_*.h>`), Phase 9b block-FD HyperIdeal Hessian shipped (~96× speed-up). v0.10.0 added: 100 % Doxygen public-API coverage (396/396 symbols, 0 warnings), a 14-gate structural quality suite (4 required in CI), the reviewer materials package (`doc/reviewer/`), `output_uv_map` for 4 of 5 DCE entries, six new roadmap phases + three RESEARCH phases, and a six-mode compile-time workflow matrix. Numbers at release: **259/259 tests pass, 0 skipped** (23 non-CGAL + 236 CGAL). Next planned milestones: Phase 9c (4g-polygon, genus g > 1) and Phase 9b-analytic (Schläfli identity). See `doc/release-policy.md` for the version-tag policy, `CHANGELOG.md` for full release notes, and `doc/roadmap/phases.md` for the phase plan.
|
||||
|
||||
## Phase 8 strategic decisions (2026-05-19)
|
||||
## Phase 8 CGAL-package decisions (frozen 2026-05-19)
|
||||
|
||||
The CGAL-package architecture was frozen on 2026-05-19. Full design:
|
||||
[`doc/api/cgal-package.md`](doc/api/cgal-package.md). Key decisions:
|
||||
Locked architecture choices — full design in [`doc/api/cgal-package.md`](doc/api/cgal-package.md), locked-vs-flexible split in `doc/architecture/locked-vs-flexible.md`:
|
||||
**MIT license** (no LGPL switch) · **Named Parameters** (`CGAL::parameters::...`) · default kernel **`Simple_cartesian<double>`** · **dual-layer wrapper** (`code/include/*.hpp` = implementation, `include/CGAL/*.h` = thin wrapper, no duplication) · target design is generic **`FaceGraph + HalfedgeGraph`** but ships Surface_mesh-only · upstream CGAL submission is pre-submission-ready, not bound (12+ month horizon). Phase 8 extensions (8a.2 generic FaceGraph, 8c manuals, 8d CGAL-format tests, 8e YAML pipeline) are deferred to on-demand.
|
||||
|
||||
| Decision | Choice |
|
||||
|---|---|
|
||||
| Submission to upstream CGAL | **Pre-submission-ready, not bound.** 12+ months horizon. |
|
||||
| License | **MIT preserved** (no LGPL switch). |
|
||||
| Mesh-type flexibility | **Generic `FaceGraph + HalfedgeGraph`** in target design; MVP starts Surface_mesh-only. |
|
||||
| Parameter style | **Named Parameters** (`CGAL::parameters::...`). |
|
||||
| Default kernel | **`Simple_cartesian<double>`** (status quo). |
|
||||
| Backward compatibility | **Dual-layer wrapper** — `code/include/*.hpp` stays as implementation, `include/CGAL/*.h` is thin wrapper. No algorithm duplication. |
|
||||
| Implementation strategy | **Hybrid MVP** — minimum Phase 8 (traits + one wrapper) first, then Phase 9 in full, then Phase 8 extensions only on concrete demand. |
|
||||
| Phase-8 MVP acceptance test | **Phase 9a (Inversive-Distance)** as the first new client of the new traits API. |
|
||||
## Port-vs-research maintenance rule
|
||||
|
||||
### Implementation sequence (committed)
|
||||
|
||||
```
|
||||
1. Phase 7.5 Doxygen + cleanup done ✅
|
||||
2. Phase 8 MVP — traits + one euclidean wrapper 3–5 days
|
||||
3. Phase 9a — Inversive-Distance against new traits 3–5 days
|
||||
4. Phase 9b — analytic HyperIdeal Hessian 1 week
|
||||
5. Phase 9c — 4g-polygon for genus g > 1 1 week
|
||||
→ port really complete, v0.9.0 release
|
||||
```
|
||||
|
||||
Phase 8 extensions (8a.2 generic FaceGraph, 8c full Doxygen manuals, 8d
|
||||
CGAL-format tests, 8e YAML pipeline) are deferred to on-demand status —
|
||||
no speculative architecture for an uncertain submission.
|
||||
|
||||
Root-level files added at v0.7.0:
|
||||
- `CITATION.cff` — machine-readable citation (Sechelmann 2016, Springborn 2020, Bobenko–Springborn 2004)
|
||||
- `CONTRIBUTING.md` — short root-level pointer to `doc/contributing.md`
|
||||
- `scripts/try_it.sh` — one-script quickstart: build → 209 tests → example run
|
||||
- CMake install target: `cmake --install build --prefix /usr/local` → headers land in `include/conformallab/`
|
||||
|
||||
## Port-vs-research maintenance rule (2026-05-21 audit)
|
||||
|
||||
Before claiming something "ports X from Java", **verify empirically**:
|
||||
Before claiming something "ports X from Java", **verify empirically** — if zero matches, it is **new research** (→ `doc/roadmap/research-track.md` with citations, **not** `doc/roadmap/java-parity.md`):
|
||||
|
||||
```bash
|
||||
find /Users/tarikmoussa/Desktop/conformallab -iname "*X*"
|
||||
grep -r "ClassName" /Users/tarikmoussa/Desktop/conformallab/src
|
||||
```
|
||||
|
||||
If zero matches, the work is **new research** — add it to
|
||||
`doc/roadmap/research-track.md` with primary literature citations,
|
||||
**not** to `doc/roadmap/java-parity.md`.
|
||||
|
||||
The 2026-05-21 audit found four pre-existing mis-labels:
|
||||
|
||||
| Item | Wrong claim | Reality |
|
||||
|---|---|---|
|
||||
| `InversiveDistanceFunctional` | "Java port (Luo 2004)" | No such Java class exists |
|
||||
| HyperIdeal Hessian (FD) | "Phase 4a" | Research — Java has `hasHessian()==false` |
|
||||
| HyperIdeal Hessian (analytic) | "Phase 9b port" | Research — derivation via Schläfli 1858 |
|
||||
| Tutorial framing | "ports `InversiveDistanceFunctional.java`" | Implementation from Luo 2004 + Glickenstein 2011 |
|
||||
|
||||
All four are corrected as of this commit. Future contributors must
|
||||
follow the empirical verification rule above before any new claim.
|
||||
The 2026-05-21 audit corrected four mis-labels (now fixed): `InversiveDistanceFunctional`, both HyperIdeal Hessians (FD + analytic), and the inversive-distance tutorial were all wrongly tagged "Java port" — they are research (no Java parent; Java declares `hasHessian()==false`). Details in `research-track.md`.
|
||||
|
||||
## Documentation map
|
||||
|
||||
24 documents across 6 categories. Read the relevant one before reasoning from scratch
|
||||
38 documents across 7 categories. Read the relevant one before reasoning from scratch
|
||||
— do not hallucinate content that is already written down.
|
||||
|
||||
### Mathematics & theory
|
||||
@@ -348,6 +325,9 @@ follow the empirical verification rule above before any new claim.
|
||||
| Key architectural decisions and their rationale | `doc/architecture/design-decisions.md` |
|
||||
| Detailed comparison with geometry-central (CMU): overlap, adoption, scientific value | `doc/architecture/geometry-central-comparison.md` |
|
||||
| Phase 9a validation report (CP-Euclidean port + Luo-inversive-distance literature check) | `doc/architecture/phase-9a-validation.md` |
|
||||
| Compile-time measurements + six-mode workflow matrix (macOS-vs-Linux honesty notes) | `doc/architecture/compile-time.md` |
|
||||
| Required vs optional dependencies + standalone-verification recipe | `doc/architecture/dependencies.md` |
|
||||
| Which 12 architecture decisions are locked vs still flexible | `doc/architecture/locked-vs-flexible.md` |
|
||||
|
||||
### API & extension
|
||||
|
||||
@@ -383,6 +363,18 @@ follow the empirical verification rule above before any new claim.
|
||||
| Language policy, test standards, release flow | `doc/contributing.md` |
|
||||
| Versioning rules + release process + single-source-of-truth list | `doc/release-policy.md` |
|
||||
|
||||
### Reviewer materials (v0.10.0)
|
||||
|
||||
| Question | Document |
|
||||
|---|---|
|
||||
| One-page reviewer briefing | `doc/reviewer/briefing.md` |
|
||||
| Seven scoped reviewer questions (Q1–Q7) | `doc/reviewer/questions.md` |
|
||||
| Internal meeting agenda | `doc/reviewer/agenda.md` |
|
||||
| Reviewer landing index | `doc/reviewer/README.md` |
|
||||
| Hand-curated reviewer landing page (HTML, source-of-truth for codeberg pages) | `doc/reviewer/hub.html` |
|
||||
|
||||
The published hub lives at https://tmoussa.codeberg.page/ConformalLabpp/ (Doxygen index at `/doxygen.html`). See the "Codeberg pages" quirk below for how it is republished.
|
||||
|
||||
### geometry-central context
|
||||
|
||||
**geometry-central** (Keenan Crane, CMU) implements the same discrete conformal
|
||||
@@ -393,9 +385,42 @@ The shared mathematical core (Springborn 2020) means cross-validation is meaning
|
||||
Full analysis: `doc/architecture/geometry-central-comparison.md`.
|
||||
Optional adoption roadmap (GC-1/2/3): `doc/roadmap/phases.md` (Optional section).
|
||||
|
||||
## Agentic workflow patterns
|
||||
|
||||
Recommended loops when working in this repo. Prefer the cheapest gate that catches the class of error you just touched.
|
||||
|
||||
- **Add/port an algorithm**: new `.hpp` in `code/include/` → test in `code/tests/cgal/` (must include a gradient-check, see Test design patterns) → register in `code/tests/cgal/CMakeLists.txt` → build `conformallab_cgal_tests` → `ctest -R "^cgal\."`. Before claiming "ports X", run the empirical port-vs-research check above.
|
||||
- **Inner dev loop** (fast iteration): `-DCONFORMALLAB_DEV_BUILD=ON` (PCH on, Unity off) for cheap incremental rebuilds; run a single suite via `--gtest_filter`. Switch back to the default (Unity on) for a final full build.
|
||||
- **Before any commit**: run the four required gates locally — they mirror CI exactly and are seconds-cheap: `bash scripts/quality/license-headers.sh`, `python3 scripts/quality/cgal-conventions.py`, `bash scripts/quality/codespell.sh`, `bash scripts/quality/shellcheck.sh --strict`.
|
||||
- **Before tagging a release**: also run the two now-un-gated structural gates (test-cgal is disabled in CI): `BUILD_DIR=build bash scripts/check-test-counts.sh` and `bash scripts/try_it.sh`. Update `CHANGELOG.md`, `CITATION.cff`, and the `doc/api/tests.md` counts (single source of truth).
|
||||
- **Touching public-API headers**: rebuild Doxygen (`cmake --build build --target doc`) and re-check coverage (`bash scripts/doxygen-coverage.sh --threshold 100`); regenerate `doc/api/headers.md` via `python3 scripts/gen-headers-md.py` (or `bash scripts/regen-docs.sh`).
|
||||
- **Landing to `main`** (origin is protected): branch → push to `origin` → open PR via `gh`/Gitea API → merge via API → also push `codeberg/main` directly → keep both remotes in sync.
|
||||
- **Republishing the reviewer hub**: see the Codeberg `pages` quirk below — manual force-push of an orphan branch; verify the live URL with a cache-bust query.
|
||||
- **Delegation**: this repo's heavy builds are slow on the ARM64 runner — when a task is genuinely parallelisable and independent, consider a background agent; otherwise handle inline. Always verify an agent's actual diff, not just its summary.
|
||||
- **settings.json**: `.claude/settings.json` (committed) pre-allows the safe read/build/test/quality commands so they don't prompt, and denies destructive git on `main`. Extend the allowlist as new safe commands recur rather than re-approving each time.
|
||||
|
||||
### Token hygiene — session-cut (Tier 1, highest impact)
|
||||
|
||||
Every turn re-sends the whole conversation, so context accumulation is the largest avoidable cost.
|
||||
|
||||
- **One session per task.** After a task is done, start a fresh session (`/clear`) instead of pivoting to an unrelated task in the same thread — the old task's context is dead weight in every later turn.
|
||||
- **Compact proactively at clean breakpoints.** Run `/compact <what matters>` when a task finishes and before the next starts, rather than waiting for auto-compaction at the limit (which you don't control).
|
||||
- **Delegate read-heavy sweeps to a subagent.** An `Explore`/`Plan` subagent reads large amounts in *its* context and returns a short summary — the bulk never enters the main context. Use it for "where is X used / what depends on Y"; for a *known* path, `Read` directly (a subagent starts cold and only pays off on a large search space).
|
||||
|
||||
### Token hygiene — command discipline (Tier 2)
|
||||
|
||||
- **Scope + filter together.** Path-scope searches (`grep -rn "newton_" code/include/`, not repo-wide). Filter test output (`ctest -R "cgal.NewtonSolver" --output-on-failure`, or `--gtest_filter` for one suite) instead of dumping all 259 results.
|
||||
- **Never read raw logs into context.** Redirect to a file, then `grep`/`tail` it. With `run_in_background`, read the output file selectively rather than pulling it whole.
|
||||
- **Don't re-read a file you just edited.** `Edit` errors on stale state — the harness tracks it; a `Read`-back after a successful edit is wasted context.
|
||||
- **Reference by line number** (`newton_solver.hpp:147`) instead of re-pasting code blocks.
|
||||
|
||||
Cache discipline (Tier 3) is a user-facing guide — see [`.claude/token-hygiene.md`](.claude/token-hygiene.md). **Remind the user of the relevant Tier-3 rule when you observe the matching anti-pattern** (mid-session CLAUDE.md edits, chained sub-5-minute waits, long multi-topic sessions).
|
||||
|
||||
## Known quirks
|
||||
|
||||
- **No GTEST_SKIP stubs remain** (since v0.9.0): the three stale HDS-port stub files were removed because the CGAL test suite covers the same functionality with real tests. The pure-math `conformallab_tests` target now only contains active tests.
|
||||
- **Boost is header-only**: CGAL 6.x uses only Boost headers (`Boost.Config`, `Boost.Graph`). No compiled Boost libraries are needed. `find_package(Boost REQUIRED)` only locates the include path.
|
||||
- **`main` branch is protected** on `origin` (Gitea). Push to `dev`, then merge via pull request. Codeberg `main` can be pushed to directly.
|
||||
- **Both remotes must stay in sync**: `origin` = `git.eulernest.eu` (CI runs here), `codeberg` = `codeberg.org/TMoussa/ConformalLabpp` (public mirror). Push to both after every significant change.
|
||||
- **Both remotes must stay in sync**: `origin` = `git.eulernest.eu` (CI runs here), `codeberg` = `codeberg.org/TMoussa/ConformalLabpp` (public mirror, SSH). Push to both after every significant change.
|
||||
- **Codeberg `pages` branch is an orphan publish target** that serves the reviewer hub + Doxygen HTML at https://tmoussa.codeberg.page/ConformalLabpp/. Its source-of-truth is `doc/reviewer/hub.html` (installed as `index.html`) + a local Doxygen build (`cmake --build build --target doc`, demoted to `/doxygen.html`). Because the auto-publish workflow (`doxygen-pages.yml`) is on `workflow_dispatch:` only, the branch is **not** refreshed on normal pushes and has been accidentally lost during force-push/merge cleanups. To republish manually: build Doxygen, copy `doc/doxygen/html/.` into a scratch dir, `mv index.html doxygen.html`, copy `hub.html` → `index.html`, then `git init -b pages && git commit && git push -f codeberg pages:pages`. Codeberg pages caches for ~10 min (`Cache-Control: max-age=600`) — verify with a cache-busting `?cb=$(date +%s)` query. Protect the branch in codeberg settings to prevent deletion (leave force-push allowed so CI/manual republish still works).
|
||||
- **Both `main` branches are independent for the pages cycle**: `origin/main` is protected (PR-only); `codeberg/main` can be pushed directly.
|
||||
|
||||
Reference in New Issue
Block a user