# TODO Working notes for `libakerror`. Outstanding items only. ## 1. The test suite has no sanitizer run Mutation testing caught an out-of-bounds probe in the status-name hash table that the suite could not: the failure mode was a write into adjacent BSS, which does not crash, so every test still passed. Sharpening one test closed that instance, but ASan would have caught the whole class directly and independently of how sharp the assertions are. Add a `-fsanitize=address,undefined` build to `.gitea/workflows/ci.yaml`, or a CMake option alongside `AKERR_COVERAGE`. This is the highest-value item here: it covers the whole library, not just the registry, and the library's fixed pools and manual buffer arithmetic are exactly what it is good at. ## 2. `HANDLE`-level status aliasing is still undetectable Two components can compile the same integer into a `case` label without ever reserving a range or registering a name, and nothing sees it. Ownership enforcement covers *naming*, which is the part the library mediates; the `case` label never reaches it. Closing this needs the `if`/`else if` handler ladder — rewriting `PROCESS`/`HANDLE`/`HANDLE_GROUP`/`HANDLE_DEFAULT`/`FINISH` so status matching is not restricted to integer constant expressions. That would also allow matching on ranges or predicates, and would let a handler resolve a code through its owner. It touches the most load-bearing code in the library and every consumer's error handling at once, so it wants its own change. Note it would *not* by itself fix the "don't use `CATCH` or `FAIL_*_BREAK` inside a loop" hazard: that comes from exiting via `break`, not from `switch`. ## 3. No registry introspection There is no way to ask who owns a status, or to enumerate reservations. The "coordinate ranges at the dependency-stack level" advice in UPGRADING.md therefore has no tooling behind it. A read-only accessor plus a dump through `akerr_log_method` would let a startup self-check or a CI job print the whole map for a linked stack. Cheap, additive, and the natural next step for multi-component adoption. ## 4. No way to release a reservation A plugin host that `dlopen`s many distinct plugins over a process lifetime accumulates ranges until the table fills. Reloading the *same* plugin is fine — an identical repeat by the same owner is idempotent. ## 5. The registry is not thread safe Global mutable state, no locking, and `akerr_status_name_count++` is not atomic. Currently documented as an initialization-time-only API rather than enforced. If components start initializing on separate threads this needs either a lock or a documented once-per-process init barrier. ## 6. Deprecate the two-argument name-registration path `akerr_name_for_status(status, name)` cannot identify its caller, so it can only check that *some* reservation covers the status, not that the caller owns it. It exists for migration. Once consumers have moved to `akerr_register_status_name()`, make the set path a no-op or remove it and leave `akerr_name_for_status()` as pure lookup. ## 7. The library's own startup failure path is untested `__akerr_name_library_status()` and the band reservation in `akerr_init()` log and then terminate when the library cannot name its own codes. Nothing exercises that: it needs a build whose `AKERR_STATUS_NAME_SLOTS` is too small to hold the library's own entries, and that macro is `PRIVATE` to the library target, so a test executable cannot set it. Mutation testing reports those lines as surviving mutants for this reason. Closing it means a second library target built with a tiny table plus a `WILL_FAIL` test linked against it — worth doing when the CMake gains a sanitizer variant (item 1), since that adds the same machinery. ## Unrelated pre-existing issues - The `AKERR_USE_STDLIB=OFF` build does not compile at all: `bool`, `PATH_MAX` and `NULL` are used unconditionally but only included under the stdlib branch. The README's dependency list states what a replacement must provide, but the header still needs its includes untangled for that configuration to work. - `CMakeLists.txt` sets `main_lib_dest` from `MY_LIBRARY_VERSION`, which is never defined and never read. Dead line.