Skip to content

Cover the fourth test leg, and watch the SymPy snapshot for drift (#746 items 35, 73) - #1038

Merged
Rafael-SOWNet merged 2 commits into
masterfrom
ci/coverage-and-scheduled-parity
Aug 23, 2026
Merged

Rafael-SOWNet merged 2 commits into
masterfrom
ci/coverage-and-scheduled-parity

Conversation

@Rafael-SOWNet

@Rafael-SOWNet Rafael-SOWNet commented Aug 23, 2026 •

Copy link
Copy Markdown
Member

Two CI gaps from #746, independent of each other.

Item 35 — coverage for the C++ leg

The roadmap says "three of the four legs report coverage; CPPTest.yml has no coverage step and no codecov flag". Measured against the workflow files, that is exactly right:

leg workflow mechanism flag
C# CSharpTest.yml /p:CollectCoverage=true and --collect:"XPlat Code Coverage" csharp
F# FSharpTest.yml --collect:"XPlat Code Coverage" fsharp
Interactive InteractiveTest.yml --collect:"XPlat Code Coverage" interactive
C++ CPPTest.yml — —

The other three legs' measurement cannot be made here, and the reason decides what to do instead. AngouriMath.CPP.Exporting sets PublishAot; publishing it with -p:NativeLib=Shared -p:SelfContained=true leaves AngouriMath.CPP.Importing/out-x64 holding one shared object and a symbol file — no AngouriMath.dll, no AngouriMath.CPP.Exporting.dll — and the tests are a native binary run by ctest, not a test host. So there is no dotnet test for the collector to attach to and no managed assembly in the artefact for it to instrument. Copying a step from CSharpTest.yml would upload an empty report under a flag claiming this leg was covered.

That is a statement about that route, not a proof that no route exists, and the doc says so in those words.

What is genuinely uncovered and genuinely coverable is the C++ itself. Sources/Wrappers/AngouriMath.CPP.Importing is the handle cache, the error-code translation and the exception boundary every C++ caller passes through, and no managed test can see a defect in it. The Linux job in the matrix now configures cmake with --coverage -O0 -g, runs the same 24 tests, and reports with gcovr filtered to the wrapper.

Measured in CI, on the Linux job of this PR's own run (24 of 24 tests passing):

lines: 62.1% (90 out of 145)
functions: 63.8% (30 out of 47)
branches: 27.8% (50 out of 180)

with ErrorCode.cpp, ErrorCode.h and AmgouriMathException.h the least covered -- the error path is where these tests do not go.

A defect this found in the existing legs

The first push went green while uploading the opposite of that report. codecov/codecov-action@v5 does not take file; given it, the action logs "Unexpected input(s) 'file'", ignores the path and searches the workspace instead. That search found 96 coverage files -- the whole of googletest and of /usr/include/c++/13 -- so the cpp flag would have carried everything the filter exists to exclude.

Corrected to files, plus disable_search: true and plugins: noop, and re-measured on the next push: Found 1 coverage files to report, coverage-cpp.xml.

CSharpTest.yml has the same file: input and therefore the same consequence -- the csharp flag has never been made from the coverage.opencover.xml it names. That is a one-word fix and it is in this PR; its search is left alone, not having been measured.

The filter matters: unfiltered, the report is 6,773 lines of mostly vendored googletest, and it includes RunTests.cpp at 100% because that is the thing being run. And the step fails on an empty report (grep -q 'lines-valid="[1-9]') rather than letting gcovr's well-formed nothing go green under a cpp flag.

New Sources/AngouriMath/Docs/Contributing/Coverage.md says what each of the four flags covers, so cpp is not read as the kernel. It is not linked from AGENTS.md's Where things are written down table — that file is owned by another change in flight; the row is owed.

Roadmap wording. Item 35's Remaining line should stop implying a fourth leg of the same kind. Suggested: "Four legs run tests and all four now report coverage, but not of the same thing: csharp, fsharp and interactive are managed coverage through dotnet test, and cpp is gcov over the C++ wrapper, because the C++ leg carries no managed assembly into CI. Managed coverage through the Native AOT export path is not collected by any route tried."

Item 73 — the SymPy comparison goes stale on its own

The comparison is 80 probes over 23 areas, taken by hand against SymPy 1.14.0, published in Docs/Usage/Comparison.md (#1030). A snapshot cannot tell you it has gone out of date.

New SymPyParity.yml, weekly plus workflow_dispatch: install the newest SymPy (unpinned on purpose — pinning would make it agree with the baseline for ever), re-run the 80 probes, and compare with .github/sympy-parity/sympy-baseline.json. It fails when the version or any answer has moved, prints a was/is now table into the job summary, and uploads today's answers so re-taking the snapshot is a file copy plus a re-run of the harness. Same shape as the corpus gate: a committed baseline that fails when a verdict moves, rather than a number in a log that expires.

A version bump with no answer moving still fails, deliberately: the published page names the version it measured, and a version it does not name is a version it did not measure. That is roughly two or three failures a year.

What it deliberately does not do.

  • It does not compare the two libraries. Only the SymPy half runs here; the half that asks this library the same 80 questions is in the analysis workspace, not in this repository, so no verdict about either library is restated.
  • It does not touch Maxima or SageMath, which the roadmap item names alongside SymPy. Nothing here has ever measured them, and installing them without a baseline would show a green tick for a comparison nobody made.
  • It does not adjudicate any disagreement.

The probe set is vendored to .github/sympy-parity/probes.json (the SymPy column only) beside the workflow, since it is CI data rather than a test project. The committed baseline was regenerated locally and reproduces the published harness snapshot on all 80 rows; two consecutive runs at 1.14.0 differ on 0 of 80, and the one floating-point row is 15 digits out of mpmath.

What ran, and what cannot run yet

Observed on this PR, not inferred from the YAML:

run result
C++ Test — all three operating systems pass; on Linux, Preparing tests, instrumented for coverage, Coverage of the C++ wrapper and Send to codecov each green, 100% tests passed, 0 tests failed out of 24
SymPy parity watch — Parity pass, twice; sympy 1.14.0 installed on Python 3.14.7, 80 probes run, 0 answers moved, exit 0

The parity job passing on a GitHub runner is also the determinism evidence: 80 answers taken on a different machine, a different Python and a different CPU match the committed baseline exactly.

CPPTest.yml has no path filter, so it fires on any PR. SymPyParity.yml's schedule trigger cannot fire until the workflow is on the default branch — a GitHub rule, not a defect — so what can be observed before merge is the workflow_dispatch and the path-filtered pull_request trigger, and the latter is what ran here. Its path filters carry no leading ./, which is the defect that silenced Benchmark.yml for ninety-eight PRs and CPPBuild.yml for its whole existence (#775). It is the repository's first schedule trigger.

What is not claimed: that codecov ingested the cpp report. The upload step reports success and the CLI names the one file it sent, but codecov's public API returns no commits and no flags for this repository at all — including the three that already exist — so there is nothing to read back from that side.

Rafael-SOWNet and others added 2 commits August 23, 2026 17:15
…ems 35, 73)

Item 35: three of the four test legs report coverage and the C++ one reports none.
It cannot report the same measurement -- the library reaches those tests as a Native
AOT shared object, the published artefact holds no managed assembly, and ctest runs a
native binary rather than a host the VSTest collector can attach to. What it does have
is the C++ wrapper in AngouriMath.CPP.Importing, which nothing measured: the Linux job
now builds it with --coverage and uploads a gcovr Cobertura report under the `cpp`
flag, filtered to the wrapper so that neither googletest nor the test file inflates it.
The step fails on an empty report rather than uploading one. Docs/Contributing/Coverage.md
says what each flag covers and why this one is not the kernel.

Item 73: the SymPy comparison is a hand-taken snapshot against one version and cannot
tell you it has gone stale. A weekly job re-runs the 80 SymPy probes against whatever
pip installs that day and fails when the version or any answer has moved from the
committed baseline, uploading the new answers so re-taking the snapshot is a copy. Only
the SymPy half runs here; the half that asks this library the same questions is not in
this repository, and Maxima and SageMath are not touched, because nothing measures them.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Bjumi5K7fg8yx6UK1mZTQd
v5 of codecov-action takes `files`, not `file`. Given `file` it warns about an
unexpected input, ignores the path and searches the workspace instead: on the C++
leg that search found 96 reports, the whole of googletest and of /usr/include/c++/13
among them, so the flag carried everything the gcovr filter exists to exclude.
`disable_search` and `plugins: noop` hold it to the report gcovr wrote.

CSharpTest.yml has the same input and the same consequence, so it is corrected here
too; its search is left alone, not having been measured.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Bjumi5K7fg8yx6UK1mZTQd
@Rafael-SOWNet
Rafael-SOWNet merged commit c6777f7 into master Aug 23, 2026
32 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.

1 participant