API review checklist#
Every pull request that adds, changes or removes public API goes through this checklist, and so
does every public header at the 0.1 API freeze (milestone M3) and before 1.0. “Public” means
cpp/include/dyng/** outside detail (and, from 0.1, the Python names reachable from dyng
without a leading underscore, the CLI flags and the file formats). Copy the list into the pull
request, tick what holds, and explain every item you leave unticked.
The rules come from the naming decision (ADR 0004: Naming conventions), the algorithm contract (ADR 0006: Algorithm contract) and the stability policy below. A reviewer may accept a deviation, but it is then recorded: in the pull request for a small one, in an ADR for a significant one.
Process#
[ ] The pull request carries the
api-changelabel and, for anything beyond a small addition, links a discussed API change issue.[ ]
CHANGELOG.mdhas an entry underUnreleased(Added,Changed,DeprecatedorRemoved); a breaking change has a migration note.[ ] A significant change (a new concept, a changed contract, a new dependency in a public header) has an ADR in
docs/adr/.[ ] The user documentation is updated in the same pull request: the algorithm page, the C++ reference group page (Writing documentation), examples and tutorials that use the API.
Names#
[ ] snake_case for types, functions and variables; no
_tsuffix on types;_tonly on template parameters (vertex_t); member type aliases in STL style (vertex_type);enum classwith snake_case values;DYNG_+ UPPER_SNAKE for the few unavoidable macros (ADR 0004; clang-tidy checks most of it).[ ] A new function uses a verb from the fixed vocabulary, or the pull request says why none fits:
compute(static solve),update(batch + result),apply(structural mutation only),from_*/to_*(construction and conversion),read_*/write_*(I/O),generate_*(seeded generators),check_*(validation that throws),copy,synchronize,warm_up.[ ] Accessors are nouns without
get_(unless the name clashes with a type), setters start withset_, predicates withis_/has_, counts withnum_.[ ] An algorithm’s name says what it computes (
sssp,cycle_count), never the paper acronym; the paper appears in@paperand the docs.
The algorithm contract (for algorithm headers)#
[ ] The header has the uniform skeleton:
options,result,stats,compute()andupdate()in a flatdyng::<algo>namespace.[ ]
optionsis an aggregate with defaults; inputs fixed atcomputeare arguments or read-only afterwards; tunables change throughresult::set_options.[ ]
resultis an opaque, move-only owning class (pimpl) with accessors,graph_version(),space()andclone(res).[ ]
statsderives fromupdate_stats; every counter’s comment says deterministic (assertable in tests) or schedule-dependent (log only). Timing is not a return value; it goes through the profiler.[ ]
compute(res, container, inputs, options) -> resultnever mutates the container;update(res, container&, batch, result&) -> statsapplies the batch and updates the result, and throwsstale_result_errorwhen the result does not match the container’s version.[ ] The oracle kind (
computeorreference) and the determinism (bitwise,exact_value,tolerance) are declared; required graph properties are checked bycompute()with aninvalid_argument_errorthat names the property and the fix.[ ]
sequentialis implemented; a missing backend throwsnot_supported_errornaming the available ones.
Library rules#
[ ] Public headers are host-compilable: no CUDA or CCCL header, no device-only type (the header self-containment test builds them with a plain host compiler).
[ ] No printing, no
exit()/abort(), no new global state; errors are exceptions derived fromdyng::error, preconditions useDYNG_EXPECTS.[ ] Memory, streams and profiling go through the
resourceshandle; functions that take it state whether they are@syncor@async.
Documentation (Doxygen)#
[ ] Every new public entity has a one-line
@brief,@tparamand@param[in|out|in,out]for every parameter,@return,@throwsfor each exception type, and@ingroup;compute()andupdate()also state@backends,@determinismand, for published algorithms,@paperwith a key fromdocs/references.bib.ci/docs.shchecks this.
Compatibility (stability policy)#
[ ] Struct fields and enum values are only appended, with defaults; new overloads do not make existing calls ambiguous.
[ ] A changed default value is treated as a breaking change, unless it is a documented bug fix.
[ ] Before 1.0 a stable-API break is allowed in a minor release, with a CHANGELOG “Changed” or “Removed” entry and a migration note. From 1.0, breaking changes wait for a major release, and removals are deprecated first (
[[deprecated("use X; removed in 2.0")]]and a PythonDeprecationWarning) for at least one minor release and six months.[ ]
dyng::experimentaland algorithms at maturityexperimentalmay change in any minor release, but the change is still in the CHANGELOG.
Exception guarantees and host-compilability#
[ ] Every function that changes a container or a result states its exception guarantee with
@guarantee(strong: nothing changed if it throws; basic: what state is left, e.g. a poisoned result), andci/doxygen_coverage.pyrequires it oncompute(),update(),graph::apply(),dyng::update()anddyng::update_each().[ ] Host allocation failures leave the library as
out_of_memory_error, also from header-inline code (catchstd::bad_allocandstd::length_errorand calldetail::throw_host_allocation_failure).[ ] The header compiles alone with the host compiler and pulls in no CUDA, CUB, Thrust or libcu++ header (
cpp/tests/api, the header self-containment targets).[ ] Anything the Python layer (M5) cannot bind directly (a variadic template, an
std::initializer_listoverload, a view that an update invalidates) has a bindable equivalent or is noted in ADR 0023’s list of binding notes.
Updating the API baseline#
The public declarations are frozen in a committed listing,
cpp/tests/api/api_snapshot/public_api.txt, generated from the Doxygen XML by
ci/api_snapshot.py (ADR 0023). ci/docs.sh compares the headers with it after Doxygen, so the
docs job of CI and the local gate (ci/check.sh, step docs) fail on any change of a public
signature, default value, enumerator, field or entity that the baseline does not contain. The
listing ignores comments and line numbers, so documentation edits never need it. Headers are
marked frozen (the reviewed 0.1 core API, the hypergraph container’s headers hypergraph/*
from M8b, ADR 0047: The hypergraph API review and freeze (0.3), and the header of every
algorithm whose manifest says
maturity stable: sssp and cycle_count since 0.1, mosp since 0.2,
ADR 0035: The mosp API review and freeze (0.2)) or tracked (io/*, generators/*,
testing/* and the algorithms at another maturity, such as the tutorial algorithms: checked the
same way, not frozen). The label of an algorithm’s header follows its manifest
(ci/api_snapshot.py), so making an algorithm stable freezes its header.
To change the API on purpose:
Go through this checklist for the change; a significant change also gets an ADR.
Add the CHANGELOG entry (
Added,Changed,DeprecatedorRemoved; a migration note for a break) and give the pull request theapi-changelabel.Regenerate the baseline and commit it with the change, so the reviewers see the API diff next to the code:
ci/docs.sh --update-api # Doxygen XML, then rewrite cpp/tests/api/api_snapshot/public_api.txt git diff cpp/tests/api/api_snapshot/public_api.txt
(
ci/docs.sh --doxygen-onlychecks the baseline and fails while the API differs, so it cannot be chained with&&toci/api_snapshot.py --update.)
A pull request whose baseline diff has no api-change label and no CHANGELOG entry is not
merged. api-check.yml enforces it for the frozen API: ci/api_check.sh compares the frozen
sections of the committed baseline with the base branch’s (ci/api_snapshot.py --against) and
the Python API with griffe, and fails on a breaking change of either (a removed or changed
declaration of a frozen header, a frozen header removed or no longer frozen; for Python a
removed name or parameter, a changed default) unless the pull request has the api-change label
and CHANGELOG.md changed. Lines only added to a frozen section and every change of a tracked
section are reported, not failed; the reviewers read them in the baseline diff
(ADR 0035: The mosp API review and freeze (0.2), amendment A2).