# Repository Guidelines ## Project Structure & Module Organization `libakstdlib` is a C shared library that wraps libc calls and data structures in `libakerror` error contexts. Public API declarations live in `include/akstdlib.h`, which is also where the Doxygen documentation lives -- the header is the contract, the sources carry the reasoning. The implementation is split by domain: | File | Covers | |---|---| | `src/stdlib.c` | memory, formatted output, string-to-number, realpath, djb2, and the list/tree traversal entry points | | `src/string.c` | the `string.h` surface | | `src/stream.c` | `stdio.h` beyond open/read/write/close | | `src/collections.c` | list and tree operations, hash map, string buffer, FNV-1a | | `src/aksl_internal.h` | shared internals; not installed, not public | Tests are one-file CTest executables under `tests/test_.c`, with shared helpers in `tests/aksl_capture.h`. `tests/negative/` holds sources that must *fail* to compile, and `tests/consumer/` is a standalone project built against the *installed* package rather than the build tree -- see the testing section below. CMake package templates are in `cmake/` and `akstdlib.pc.in`. The vendored dependency is `deps/libakerror`; update it as a submodule rather than editing generated files under `build/`, `build-asan/` or `build-coverage/`. ## Build, Test, and Development Commands Initialize dependencies before a fresh build: ```sh git submodule update --init --recursive cmake -S . -B build cmake --build build ``` Run the normal suite with `ctest --test-dir build --output-on-failure`. Use the instrumented build for memory and undefined-behavior checks: ```sh cmake -S . -B build-asan -DAKSL_SANITIZE=ON cmake --build build-asan ctest --test-dir build-asan --output-on-failure ``` For coverage, configure a third tree; the report is part of that suite (the `coverage_reset` / `coverage_report` CTest entries) and also lands in `build-coverage/coverage-summary.txt`: ```sh cmake -S . -B build-coverage -DAKSL_COVERAGE=ON cmake --build build-coverage --target coverage ``` Run `cmake --build build --target mutation` only when you need the slower mutation harness, and `cmake --build build --target docs` to regenerate the API documentation -- that one fails if any public function, parameter or return value is undocumented, so it is a check as well as a generator. `.githooks/pre-push` runs the default build, the sanitizer build and the documentation check before a push; enable it with `git config core.hooksPath .githooks`. `rebuild.sh` installs to `/home/andrew/local` and removes the local build directory, so treat it as a local convenience script. ## Coding Style & Naming Conventions Use C with 4-space indentation; existing files sometimes use tabs for continued statements, so match the surrounding block. Public symbols use the `aksl_` prefix, structs use `aksl_`, and tests use `test_.c` plus static `test_` functions. Preserve the `akerr_ErrorContext AKERR_NOIGNORE *` return convention and the `PREPARE_ERROR` / `FAIL_*` / `SUCCEED_RETURN` pattern. Four conventions hold across the whole library, and a new wrapper that breaks one of them is wrong even if it compiles and passes: - **A NULL out-param is a caller error**, not "don't care". - **Finding nothing is success** -- searching functions write NULL or zero and return NULL. - **Truncation is a failure.** Take the destination's size, raise AKERR_OUTOFBOUNDS, and write nothing rather than a prefix. - **Clear `errno` before the wrapped call** and read it back through `AKSL_ERRNO_OR`, so no error can carry status 0 -- which every downstream `DETECT` reads as success. Every new public function needs a Doxygen block on its **declaration** with `@brief`, a `@param` per parameter, a `@throws` per status it can raise, and `@return`. The `docs` target fails otherwise. The build is `-Wall -Wextra` and CI adds `-Werror`. `-Wpedantic` is deliberately off: libakerror's `FAIL_*` macros trip "ISO C99 requires at least one argument for the ..." on their own expansion, not on anything at the call site. ## Testing Guidelines Add a new test by creating `tests/test_mything.c` and adding `mything` to the right list in `CMakeLists.txt`. `AKSL_TESTS` must exit zero. `AKSL_WILL_FAIL_TESTS` are deliberate abort/contract tests. `AKSL_KNOWN_FAILING_TESTS` assert defects that have an open issue; when one starts unexpectedly passing, move it into `AKSL_TESTS` with the fix and close the issue. Both of the latter are currently empty -- all six confirmed defects are fixed -- but the mechanism stays for the next one. `tests/negative/` holds sources that must **fail** to compile. Each is an `EXCLUDE_FROM_ALL` target built with `-Werror` and registered as a `WILL_FAIL` CTest entry, so the test passes only when the compile fails. They cover the two guarantees the compiler enforces and nothing else does: `AKERR_NOIGNORE` and the format attributes. Drop either in a refactor and every ordinary test still passes. `tests/consumer/` is configured standalone against `CMAKE_PREFIX_PATH`, not as part of this build, because being part of this build is what would let it pass without testing anything. It covers the paths only an install has: the version file, `find_dependency(akerror)` resolving, and the exported `akstdlib::akstdlib` target. CI runs it after `cmake --install`. Coverage is 99.5% of lines and 100% of functions across all four sources; CI gates at 90 (line) / 40 (branch), so new code needs tests in the same commit. Run `cmake --build build-coverage --target coverage` and check the uncovered-line listing before proposing a change. Tests for behaviour an open issue records as defective belong in `AKSL_KNOWN_FAILING_TESTS` asserting the *correct* contract — do not pin current-but-wrong behaviour in `AKSL_TESTS`, since that turns the eventual fix into a test failure. ## Commit & Pull Request Guidelines Recent commits use short imperative summaries, for example `Add memory wrapper tests` and `Make error-status assertions authoritative`. Keep commits focused and include tests with behavior changes. Pull requests should describe the changed API or behavior, list the CTest/sanitizer/mutation commands run, and link the issue it closes. ## Agent-Specific Instructions **Outstanding work goes in the issue tracker, not in a file.** Open an issue at — `tea issues create --repo andrew/libakstdlib` — naming the file and line, the functional consequence, and what closing it would touch. Label it by kind and blast radius and leave `status::grooming` on it until its scope and approach are settled. **Do not add outstanding items to `TODO.md`**: that file is the record of where the library stands, what is deliberately not wrapped, and which uncovered lines are uncoverable rather than untested. A description of work still to do goes stale the moment somebody does it, which is why the two are separated. **A defect in a dependency is filed against that dependency.** `libakerror` has a tracker on the same forge, and three defects that cost this library a workaround each sat in this repository's own notes for months without anybody upstream being able to see them. Comment the workaround at its site with the words "filed upstream" and delete it when the fix lands. Do not modify generated build trees, profiling artifacts, or untracked scratch files unless explicitly asked. Prefer small, test-backed changes and update `README.md` when changing documented workflows.