The Pi runner (3-4 GB RAM, swap heavily loaded) OOMs when /ci-all
triggers test-cgal + quality-gates + doc-build + links simultaneously:
four Docker containers start at once after test-fast completes, each
consuming 150-400 MB, exhausting available RAM.
Fix: /ci-all removed from all three workflow files. Each keyword
now triggers exactly one job — no parallel container competition.
Safe workflow: one keyword per commit.
Typical sequence:
git commit -m 'fix: ... /test-cgal' → CGAL tests (~5 min)
git commit -m 'chore: /quality-gates' → style checks (~30 s)
CLAUDE.md: CI table updated with Pi-runner warning note.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
issue_comment triggers had two problems: Gitea did not reliably fire
them, and the refs/pull/N/head checkout was fragile. Commit-message
keywords are simpler and guaranteed to work on any push event.
Trigger keywords (add anywhere in the commit message):
/test-cgal → CGAL test suite (277 tests, LOW_MEMORY_BUILD)
/quality-gates → license/codespell/shellcheck/cgal-conventions
/docs → Doxygen build + warning summary
/links → Markdown internal link check
test-fast still runs on every push (no keyword needed).
All `issue_comment` event handlers and `refs/pull/N/head` checkouts
removed from all three workflow files. review/** added to push branch
filters so this PR branch triggers normally.
CLAUDE.md CI table updated.
/test-cgal /quality-gates
Every CI job except test-fast and mirror-to-codeberg now runs only
when explicitly requested via a PR comment, instead of on every push
or PR sync. This keeps the Pi runner idle during WIP commits and lets
the author decide when to pay each job's cost.
Trigger commands:
/test-cgal → CGAL test suite (277 tests, ~5 min build + 31 s run)
/quality-gates → license/codespell/shellcheck/cgal-conventions (~30 s)
/docs → Doxygen build + warning summary (~2 min)
/links → Markdown internal link check (~10 s)
All comment-triggered jobs check:
event is issue_comment
AND comment is on a PR (issue.pull_request != null)
AND comment body contains the trigger word
AND checkout uses refs/pull/N/head (not the default branch)
Jobs that stay automatic:
test-fast — runs on every push (26 pure-math tests, < 5 s)
mirror-to-codeberg — unchanged
Jobs that keep additional triggers:
markdown-links — weekly cron (Mon 05:00 UTC) + workflow_dispatch
doc-build — workflow_dispatch (for manual runs outside a PR)
quality-gates drops `needs: test-fast` — it now runs independently
when comment-triggered (caller decides whether test-fast passed first).
CLAUDE.md CI pipeline table updated with all five jobs and their new
trigger descriptions.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Instead of triggering on every pull_request push, test-cgal now fires
only when a PR comment contains "/test-cgal". This prevents the Pi
runner (3-4 GB RAM, swap constantly loaded) from queuing CGAL builds
faster than it can drain them on every WIP commit.
Workflow changes:
- Add `issue_comment: types: [created]` to the top-level `on:` block
- test-cgal `if:` condition:
event is issue_comment
AND comment is on a PR (issue.pull_request != null)
AND comment body contains "/test-cgal"
- Checkout uses `refs/pull/N/head` so the PR branch is checked out
correctly (issue_comment sets GITHUB_REF to the default branch, not
the PR branch)
Usage: write "/test-cgal" as a PR comment to trigger the 277-test
CGAL suite. The build uses CONFORMALLAB_LOW_MEMORY_BUILD=ON (-O0,
no PCH, unity batch 1) and runs in a 2000 MB container.
CLAUDE.md: CI table + status paragraph updated accordingly.
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>
The CGAL test build is too heavy for the eulernest runner — most recent
runs OOM during CGAL+Eigen template expansion at -j1/1600 MB rather than
exposing real regressions. Gate the job off with `if: false` and a
DISABLED-2026-05-26 comment block, matching the pattern already used for
doxygen-pages.yml and perf-compile-time.yml. test-fast and quality-gates
keep running on every push/PR; workflow_dispatch reruns of test-cgal
still work from the Gitea UI.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Two reviewer-facing additions consolidated into one commit:
(1) New `quality-gates` job in .gitea/workflows/cpp-tests.yml
──────────────────────────────────────────────────────────
Runs in parallel with test-cgal after test-fast. Installs
`codespell` + `shellcheck` (apt) into the existing ci-cpp container,
then executes four scripts strictly (exit 1 on any finding):
* license-headers.sh — 66/66 files carry SPDX MIT
* cgal-conventions.py — 0 violations across 6 CGAL public headers
* codespell.sh — 0 typos across docs + source + scripts
* shellcheck.sh — 0 findings across 16 shell scripts
Each ran at 0 findings locally before promotion. Total wall-time
on the eulernest runner: ~30 s.
(2) New code/deps/THIRD-PARTY-LICENSES.md
──────────────────────────────────────
Enumerates every vendored dep under code/deps/, plus auto-fetched
GoogleTest, plus system-required Boost, with:
* upstream project + version + SPDX identifier
* compatibility note for MIT distribution
* downstream-packager license matrix (header-only consumer vs
CLI binary) clarifying the LGPL §3 vs §4 distinction
Required for any future Linux-distribution packaging and for the
CGAL submission's compliance check.
Also fixes a `code/.gitignore` gap: the `deps/*` wildcard was
catching the new file; added `!deps/THIRD-PARTY-LICENSES.md` to
the exclusion list so it's actually tracked.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
CI gates (active on every PR via .gitea/workflows/)
───────────────────────────────────────────────────
1. test-count consistency
cpp-tests.yml gains a step after test-cgal that runs
`scripts/check-test-counts.sh` against the just-built ./build dir
(reuse via new BUILD_DIR env var, ~5 s overhead). Drift between
`doc/api/tests.md` and ctest reality now fails the PR.
2. End-to-end smoke
`scripts/try_it.sh` (the documented user quick-start) is now part of
the CGAL job, so README quick-start regressions fail the PR rather
than silently breaking when users land.
3. Internal markdown link checker
New `.gitea/workflows/markdown-links.yml` + `scripts/check-markdown
-links.py`. PRs that touch any *.md file run the check; main pushes
trigger it too; a weekly cron catches external link rot. Pure
Python, no third-party action. Validated against the current tree:
122 internal links across 37 *.md files, 0 broken.
Local quality scripts (`scripts/quality/`, not in CI)
─────────────────────────────────────────────────────
* `license-headers.sh` — `SPDX-License-Identifier: MIT` audit over
code/{include,src,tests}/. Currently
reports 60/66 files missing it — that's
a follow-up; the script captures the
structural gap.
* `sanitizers.sh` — ASan + UBSan over the fast test suite.
* `coverage.sh` — gcov/lcov line + branch coverage of
code/include/, HTML report under
build-coverage/lcov-html/.
* `clang-tidy.sh` — runs the curated `.clang-tidy` policy over
every public header.
* `multi-compiler.sh` — sequential build + test against every
detected g++/clang++ (auto-discovery or
explicit list).
* `cgal-version-matrix.sh`— sequential build + CGAL test suite against
every CGAL tree under `~/cgal/<ver>/` (or
via `CGAL_ROOTS=...` env var).
* `reproducible-build.sh`— two `Release -j1` builds, fail if any test
executable byte-differs.
* `run-all.sh` — driver: `--fast` for the ~5-min subset,
no arg for the ~25–40 min full sweep;
captures per-gate logs to
build-quality-logs/.
+ `.clang-tidy` — curated, deliberately-small policy (only
checks that fire on OUR code, never on
transitive CGAL/Eigen/Boost headers).
+ `scripts/quality/README.md` — explains the structure, lists each
gate's wall-time + prereqs, and codifies
the promotion path: a gate moves into CI
only when it's green on the dev machine
AND has a recovery-instructions paragraph
in `doc/release-policy.md`.
Doc updates
───────────
`doc/architecture/locked-vs-flexible.md` (reviewer-facing) gains 4
"closed" rows in the limitations table — the 3 CI gates above and the
local quality-script suite.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Two CI improvements:
1. **test-cgal OOM fix**
* memory limit 1400m → 1600m (cc1plus needs ~700 MB for CGAL + Eigen)
* memory-swap 1400m → 1600m (was less than memory, Docker rejected
the config; now disables swap entirely
so OOM fails fast)
* build parallelism -j2 → -j1 (single worker leaves headroom)
These three changes together address the test-cgal failures observed
since the test_scalability_smoke.cpp was added. Locally the full
suite (183 tests including the brezel.obj genus-2 mesh) runs in
~1 s with peak ~700 MB; the ARM64 CI runner now has the same
headroom.
2. **API-docs job (new, soft-fail)**
* .gitea/workflows/doc-build.yaml — separate workflow, distinct name
"API Docs"
* Runs only on pull requests; `continue-on-error: true` ensures
warnings never block the merge
* Installs doxygen, runs `doxygen Doxyfile`, uploads the generated
HTML as a 14-day artifact for reviewer inspection
* Dockerfile.ci-cpp also pre-installs doxygen so future iterations
can drop the in-job install step
When Doxygen coverage matures (Phase 8c — User_manual.md), this job
can be promoted to a hard requirement and the HTML deployed to
Pages.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Unified the codebase language to English throughout. German text appeared
in code comments, test file headers, CI step names, and several markdown
documents. All natural-language text is now English; proper nouns
(Institut für Mathematik, Technische Universität Berlin) are unchanged.
Files changed:
- .gitea/workflows/cpp-tests.yml — CI step names and job comments
- code/include/mesh_utils.hpp — inline comment
- code/tests/cgal/CMakeLists.txt — section comment block
- code/tests/cgal/test_geometry_utils.cpp — full file header + all test comments
- doc/math/references.md — geometry-central section
- doc/math/validation.md — Section 9 (geometry-central cross-validation)
- doc/roadmap/phases.md — Optional geometry-central track (GC-1/2/3)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Reduces Pi load: test-cgal now triggers only when a PR is opened/updated,
not on every push to dev or main. test-fast continues to run on all branches.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
-j$(nproc) during CGAL+Eigen template compilation consumed ~1.5-2 GB
peak RAM on the Raspberry Pi CI runner, starving the Gitea web server.
Changes:
- CGAL build: -j$(nproc) → -j2 (halves peak memory, ~700 MB per process)
- Both builds: nice -n 19 (lowest CPU priority, web server keeps preemption)
- test-cgal container: hard memory cap --memory=1400m --memory-swap=1400m
so the container is OOM-killed rather than taking down the whole system
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
test-fast ist der schnelle, abhängigkeitsfreie Job: nur Eigen + GTest.
WITH_CGAL_TESTS=ON in test-fast triggert unnötigerweise find_package(Boost)
und konfiguriert das CGAL-Test-Verzeichnis.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- test-fast konfiguriert jetzt mit -DWITH_CGAL_TESTS=ON (Boost im Image)
- Kommentar aktualisiert (Boost kein Runtime-Install mehr nötig)
- Konsistenz zwischen test-fast und test-cgal hergestellt
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Root cause: -DWITH_CGAL=ON implied -DWITH_VIEWER=ON, which pulled in
GLFW, which requires wayland-scanner — not present in the headless CI
container (ubuntu:22.04 ARM64).
Fix: new CMake option -DWITH_CGAL_TESTS=ON builds conformallab_cgal_tests
without touching the viewer, GLFW, libigl, or any display dependency.
Only Boost headers are required (already in the Docker image).
Changes
───────
code/CMakeLists.txt
- Add WITH_CGAL_TESTS option (OFF by default)
- find_package(Boost REQUIRED) now shared between WITH_CGAL and WITH_CGAL_TESTS
- WITH_CGAL still implies WITH_VIEWER (for local full builds)
- Remove duplicate find_package(Boost) inside the WITH_CGAL block
code/tests/CMakeLists.txt
- cgal/ subdirectory added for WITH_CGAL OR WITH_CGAL_TESTS
.gitea/workflows/cpp-tests.yml
- test-cgal job: -DWITH_CGAL=ON → -DWITH_CGAL_TESTS=ON
README.md
- Build modes table: three rows (default / CGAL_TESTS / CGAL full)
- Quick-start: separate headless and full-local sections
- Prerequisite table updated
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
test-fast (alle Branches, < 1 s):
Unverändert — reine Mathe-Tests ohne CGAL/Boost.
test-cgal (main / dev / Pull Requests):
Läuft nach erfolgreichem test-fast (needs: test-fast).
Baut conformallab_cgal_tests mit -DWITH_CGAL=ON und führt
alle 158 CGAL-Tests (Phase 3–7) aus.
Übergangs-Schritt: apt-get libboost-dev zur Laufzeit, bis das
Docker-Image neu gebaut wird (Dockerfile bereits aktualisiert).
Dockerfile.ci-cpp:
libboost-dev ergänzt — für den nächsten manuellen Image-Rebuild.
Danach entfällt der apt-get-Schritt im Workflow automatisch.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The ci-cpp image was likely built for linux/amd64; the eulernest runner
is linux/arm64 (Raspberry Pi), so the container exited immediately
without running any steps (task 102 log: 10 lines, no step output).
Fix: run directly on the host runner and install cmake/g++ via apt-get
(same approach as the previously working workflow).
Also pin --platform=linux/arm64 in Dockerfile.ci-cpp so the next
image build produces the correct architecture. Once the image is pushed,
re-add the container: block to the workflow.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Runs conformallab_tests (GTest) on every push to main/dev/claude/**
using ubuntu-latest + cmake + g++. Only the test binary is built,
not the full app (no CGAL/Boost compilation needed).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>