Closes Defects -> Known and still open item 12, both halves.
include/akgl/SDL_GameControllerDB.h is tracked on purpose: it is the offline
fallback that keeps the library buildable when upstream is unreachable. The
script that writes it had no set -e and never checked curl, so a failed fetch
wrote AKGL_SDL_GAMECONTROLLER_DB_LEN 0 and an empty array over the good copy
and exited 0. The safety net destroyed itself, and because CMake re-ran the
generator on every build, an offline build was enough to do it.
The script now runs under set -euo pipefail, fetches into a temporary
directory, and moves the result into place only after checking curl's exit
status (with --fail, so an HTTP error is a status rather than an error page in
the body), a plausible minimum mapping count, and that no mapping carries a
quote or backslash that would break the C string literal it becomes. Any of
those failing leaves the tracked header exactly as it was and exits non-zero.
Verified against all five failure modes -- unresolvable host, 404, truncated
response, empty-but-successful response (the original failure exactly), and a
response containing a quote. Each refuses, and the header's checksum is
unchanged after every one. AKGL_CONTROLLERDB_URL and
AKGL_CONTROLLERDB_MIN_LINES are environment-overridable, which is how.
The build no longer runs it at all. The add_custom_command declared a relative
OUTPUT, which CMake resolves against the binary directory while the script
writes to the source directory, so the declared output never appeared and every
build re-ran the command -- needing network access and leaving the tree dirty.
It is an explicit `controllerdb` target now, and the header is no longer listed
as a library source, which is all it was there for.
The empty-initializer problem goes with it: an empty array initializer is a
constraint violation in ISO C that compiles only as a GCC extension, and the
minimum-count check guarantees at least one entry.
Also here, because it rested on a premise that turned out to be false: the
character suite is no longer excluded from CI's coverage and memory-check jobs,
nor from the mutation harness by default. It was excluded on the grounds that
it failed deliberately. It did not -- it was reporting success while running
one of its four tests.
25/25 pass, memcheck clean, shellcheck clean.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
It was reporting and shrugging. A definite leak, a read past the end of an
allocation or a branch on uninitialised memory now fails the build on the
push that introduces it, which is the only point at which it is cheap to
fix.
The six findings the job had on its first run were fixed rather than
excused, so the gate closes on a clean tree instead of on a backlog.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The perf suites were already running in CI, because they are ordinary CTest
tests -- but only in the coverage job, which is a Debug build with gcov
instrumentation. That is the one place their numbers cannot mean anything,
and it was spending full-scale iteration counts to prove it. They now run
there at AKGL_BENCH_SCALE=0.02, for path coverage alone, which takes the
whole coverage run to four seconds.
The `performance` job is where the timings are taken: RelWithDebInfo, full
scale, `ctest -L perf`, which is the only configuration in which
tests/benchutil.h enforces a budget. It keeps the tables as an artifact
whether it passes or fails -- a red run says which measurement moved, and a
green one is the next baseline for PERFORMANCE.md. The step uses --verbose
rather than --output-on-failure, because --output-on-failure prints nothing
at all for a passing benchmark, and sets pipefail, without which the status
reaching the runner is tee's and a blown budget reads as a pass.
The `memory_check` job runs scripts/memcheck.sh over every suite under
valgrind and keeps the logs. It carries continue-on-error, and that is a
deliberate, temporary lie: the six findings in TODO.md "Memory checking" are
real and all of them are libakgl's, so gating on it today would only teach
everyone to ignore a red build. The flag comes off with the commit that
closes the last item, and item 34 -- the missing json_decref in all four
asset loaders -- is four lines.
Both new jobs were run locally against a clean copy of the tree with the
exact commands the workflow uses.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Instrument libakgl in opt-in coverage builds, use CTest fixtures to reset counters and emit Cobertura XML and detailed HTML reports, and upload those reports from Gitea CI. Document the local coverage workflow for contributors.
Co-authored-by: Codex (GPT-5) <noreply@openai.com>
Add file, structure, global, and function documentation across all libakgl-owned headers and sources, including parameter contracts and likely AKERR/AKGL_ERR exceptions. Add a strict Doxyfile and build the generated API documentation in Gitea CI with warnings treated as failures.
Co-authored-by: Codex (GPT-5) <noreply@openai.com>
Build libakgl with recursive vendored dependencies, run the passing CTest suite with JUnit reporting, and publish a bounded static-string mutation gate with a 50 percent score threshold.
Co-authored-by: Codex (GPT-5) <noreply@openai.com>