Retrospective: M5 (the Python package, the CLI and the 0.1 documentation)#
Status: complete (2026-09-30) on the branch m5-python (from main at a826ed0, the merge
of pull request #3 with M3), pending the orchestrator’s pull request into main. Nothing was
published: no tag, no upload to TestPyPI or PyPI, no GitHub Release. M5 was done in three steps,
each by one implementer, followed by a review round that fixed the confirmed findings of the
independent reviewers (section “Review round”); this page was written in step 3 from the steps’
records (ADRs 0011 and 0025, docs/developer/python_gaps.md, docs/developer/wheels.md),
updated in the review round, and ends with the readiness list of release 0.1.0.
What was built#
Step |
Commits |
What |
|---|---|---|
1. bindings |
|
|
2. wheels-cli |
|
the |
3. docs-finish |
|
the Python API reference (sphinx-autoapi), getting started in Python, the README quickstarts run by pytest and CTest, |
Acceptance criteria#
# |
Criterion |
Evidence |
Status |
|---|---|---|---|
1 |
Root |
step 1 ( |
met |
2 |
The Python API of PLAN 5.4 for 0.1 |
step 1 (ADR 0011; what is not bound is listed in |
met, with the gaps of |
3 |
pytest: API, DLPack/NumPy, exceptions, stale results, Hypothesis, Python-level parity; green in the dev env and in a clean venv with only the wheel |
steps 1 and 2; step 3 adds the snippet and example tests; the review round the growth, copy, pickle, thread and scalar tests (section “Verification”) |
met |
4 |
manylinux_2_28 abi3 wheel with libgomp and the sdist, locally and in |
step 2 ( |
met locally; the hosted workflows have not run yet (readiness item 4) |
5 |
The |
step 2 (ADR 0025: a console script of the Python package instead of the C++ |
met |
6 |
Documentation for 0.1; README snippets executed; docs with -W; the repository state recorded |
this step (below) |
met |
7 |
A fresh clone passes |
section “Verification” |
met |
Review round#
Independent reviewers (lenses: Python API, packaging, CLI and docs, regression) reported 36
findings that a skeptic confirmed at 1035309; three were the same (the empty “Verification”
section). Every one is fixed on the branch; none was deferred.
# |
Finding (severity) |
Resolution |
Commit |
|---|---|---|---|
1 |
Zero-copy exports ( |
the result state lives in a |
|
2 |
|
the generation counter is in the native holder; |
|
3 |
|
no cache: the arrays are converted at every use; tests refill the arrays between two applies for int32/int64 ids and weights |
|
4 |
|
implemented in C++ ( |
|
5 |
pickling / copying: obscure errors, a used batch unpicklable (medium) |
ADR 0011 item 13 |
|
6 |
|
the native module is chosen on first use (ADR 0011 item 14); a fake plugin entry point tests both paths |
|
7 |
scalars coerced with |
|
|
8 |
|
both under |
|
9 |
legacy DLPack exports writable (low) |
unversioned exports are copies; |
|
10 |
buffer-protocol int64 inputs select int32 ids (low) |
the buffer format is the declared dtype |
|
11 |
no mypy in CI; 90 errors (low) |
|
|
12 |
wrong ADR cross-references (low) |
ADR 0011 items 3 and 5 |
|
13 |
option defaults not tested against C++ (low) |
a parametrized test per dataclass |
|
14 |
the wheel ships nanobind, robin-map and the GCC runtime without their licences (high) |
|
|
15 |
|
|
|
16 |
the “Verification” section was a placeholder (medium; three reviewers) |
filled in below |
this page |
17 |
the published sdist is not what the wheel is built from (low) |
|
|
18 |
deprecated |
|
|
19 |
the sdist ships the CC-BY-SA-4.0 Code of Conduct and repository files (low) |
excluded; |
|
20 |
extras differ from PLAN 7.7 without a record (low) |
ADR 0011 item 15 |
|
21 |
the local wheel bundles an unpinned GCC 16 libgomp (low) |
|
|
22 |
tag checks compare the raw |
|
|
23 |
|
a usage error as in the original; fixture |
|
24 |
the “add an algorithm” guide’s step 7 (medium) |
rewritten for the M5 layout |
|
25 |
a getting-started link to a non-existent CLI example (low) |
reworded |
|
26 |
the CUDA message points to a missing section (low) |
“use CUDA from C++”, the install page’s Python section |
|
27 |
CLI errors in Python/C++ terms, doubled |
hints with |
|
28 |
|
“every weight column”; the flag only on update |
|
29 |
the cycle-enum flag table misses renamed flags and values (low) |
rows added; the missing stderr line is noted |
|
30 |
the mapping tables do not name the CLI (low) |
added |
|
31 |
MOSP-OpenMP history: |
corrected |
|
32 |
|
a throwaway venv when the environment’s editable |
|
33 |
|
the target |
|
34 |
the bindings are never compiled by Clang (low) |
a Clang 18 entry in |
|
The CHANGELOG has the “Fixed (M5 review)” and “Changed (M5 review)” entries; the Python reference
(docs/api/python/index.md) states the new array, copy and thread rules (31e1563).
Step 3: documentation and close-out#
Done#
Python API reference (PLAN 9.2): sphinx-autoapi 3.8.1 reads
python/dyngand the committed stubs statically (no compiled module, so the docs job, Read the Docs and CPU-only machines need no build). The reference is the public API as users import it: thedyngpackage page with every name ofdyng.__all__, and one page each fordyng.sssp,dyng.cycle_count,dyng.io,dyng.generatorsanddyng.testing. The implementation modules whose names the package re-exports (dyng.graph,dyng.array, …) get no page of their own, and amissing-referencehook resolves the signatures’dyng.graph.Graphto the documenteddyng.Graph. The docstrings needed two fixes for the reference: the#:field comments of the dataclasses (which autoapi does not read) became “Attributes” sections, and nine property docstrings that started with “text: …” (which napoleon reads as a type) were reworded.docs/api/python/index.mdexplains the package-wide rules (resources, dtype dispatch, arrays, stale results, the exception table, threads, profiling).Getting started: the index page shows both ten-line quickstarts (included from the README, so they are the tested ones);
install.mdhas the Python section; “A first update in Python” (examples/python/first_update.py, the twin of the C++ page, and adyng.update()snippet with sssp and cycle_count on one graph).README quickstarts executed (PLAN 9.6): marked code blocks (
<!-- snippet: name -->, an optional output block) in the READMEs and the pages.python/tests/test_doc_snippets.pyruns every Python snippet (6 today: the two READMEs, the first update, both algorithm pages) and compares its output; the CTestexample.readme_quickstartextracts the C++ quickstart at configure time, compiles it with the examples’ warnings and compares its output;ci/doc_snippets.py --check(inci/docs.sh, tested byci/tests/test_doc_snippets.py) keeps the quickstarts present and within ten lines.examples/python(first_update.py,sssp_update.py,cycle_count_update.py, the twins of the C++ examples), tested against the originals’ outputs bypython/tests/test_examples.py.Algorithm pages: a runnable Python snippet with its output and the command lines on the originals’ formats in the API sections of
ssspandcycle_count; the “Python binding arrives in M5” notes are gone. The update-model page shows the profiler stages from Python.How-to “Port research code” (PLAN 6.3), written from what the sssp and cycle_count ports did, with the harness’s real commands.
History pages for MOSP-OpenMP, MOSP-CUDA and CycleEnumeration-GPU (PLAN 9.2): provenance, the pinned commit and the paper’s snapshot, the ported files, the fixes of the original before the port, what differs and what stays behind.
api-check.yml(a PLAN 11.2 M5 workflow, left open by step 2) withci/api_check.sh: griffe 2.3.0 against the base branch; a breaking change needs theapi-changelabel and a CHANGELOG entry (PLAN 5.9). Theapistep ofci/check.shruns it locally.Release process (
docs/developer/release.md, PLAN 10.3), referenced bywheels.mdand by an error message ofrelease.ymlsince step 2.Repository state of 2026-09-30 (
pending_author_facts.md): the approvals-log row inGOVERNANCE.mdand steps 7 and 9 ofrepository_settings.md(DCO required, 18 checks, the signing key; the pyyaml pin of the harness job).The roadmap’s “Where we are”, the landing page and the README say where 0.1.0 stands; the CHANGELOG has the draft summary of 0.1.0 at the top of
Unreleased.
Deviations from the plan (pragmatic choices, same intent)#
Plan |
What was done |
Why |
|---|---|---|
PLAN 9.2: sphinx-autoapi “over the nanobind stubs (.pyi)” |
autoapi over the typed layer |
the public API is the typed layer (ADR 0011); the stubs describe only the private |
PLAN 9.6: the README quickstarts are run “by a CI step ( |
the Python snippets run in pytest ( |
the docs job configures but builds nothing (Doxygen, Sphinx), and running the snippets needs the compiled library; the jobs that build it run them, so they still cannot drift |
PLAN 9.6: “10 lines of C++” |
ten lines in the body of |
a complete, compilable program; |
PLAN 9.2 tutorials “Dynamic SSSP in Python in 10 minutes” and “Cycle counting on a changing graph” (0.1) |
moved to 0.1.x; “A first update in Python” and the algorithm pages’ Python sections cover the steps |
not in the M5 criteria; recorded in |
PLAN 10.3 step 7: “GitHub Release from the CHANGELOG section” by |
a manual step of the author ( |
a job with |
PLAN 5.9: |
against the pull request’s base branch |
the only tag, v0.0.1, is the name reservation without an API; against the base branch every pull request is checked from now on. From 0.1.0 a release branch can compare with the tag ( |
PLAN 5.7: |
the 0.1 reader rejects them with an |
|
PLAN 8.7’s tooling table: mypy through pre-commit |
|
the check needs NumPy and the installed typed layer, which pre-commit’s isolated environments do not have (review round) |
PLAN 6.3 step 10: maturity |
|
step 10 also asks for the benchmark-suite record ( |
Notes#
autoapi_keep_filesis off: the generated pages exist only during the build (and are git-ignored). Thesource-readhook gives them the Python default domain, because the site’s primary domain is C++.The pure docstring changes of the typed layer changed no signature:
ci/api_check.shagainst1a11913(the end of step 2) reports no breaking change.
Verification#
A fresh clone of the branch at 524e96a (all review fixes; the later commits change only this page
and docs/api/python/index.md, whose site build ci/docs.sh passed on the final commit), made
with git clone /home/sskg8/Projects/dyng and git checkout m5-python in
$DYNG_SCRATCH/review/m5-fix-verify, on 2026-09-30, by the script
$DYNG_SCRATCH/runs/m5-fix-verify/run.sh (logs next to it). Heavy steps under the shared lock,
niced; GPU tests on GPU 1.
Check |
Command |
Result |
|---|---|---|
CPU gate with parity |
|
all checks passed (26 min): clang-format; cpu-only 592/592 and dev 605/605 CTests; clang-tidy; reuse; provenance (141 files); harness; python (the clone used the throwaway venv |
GPU gate |
|
all steps passed (31 min): gpu 252/252, cpu 605/605 in the CUDA build, sssp goldens on cuda 495/495, cycle_count goldens 48/48 replays (24 cases on cuda and cuda:resident), memcheck, synccheck, racecheck (0 errors), clang-tidy |
Distributions |
|
sdist 0.79 MB and wheel 1.50 MB ( |
Clang 18 pre-check |
|
174 translation units (library, tests, compat tools and the bindings), 0 failures |
Fortified GCC |
|
built, 0 warnings |
Performance: the review round changed no code of a timed region. git diff 1035309..HEAD -- cpp/
adds the .dgt reader and writer (cpp/src/io/batch_text.cpp), their tests and the API baseline,
and nothing else; the reviewers’ A/B at 1035309 against an a826ed0 parity build (sssp
roadNet-PA 0.996-1.008, cycle_count 0.978-1.003) therefore still describes the library. The
Python-side copy-on-write copies a result only while an exported view is alive; the CLI and the
examples keep none across an update.
Release 0.1.0 readiness#
The checklist of PLAN 10.3 (Release process) for 0.1.0, with the state on the branch
m5-python. “Author” items are publishing or account-level steps, which are not delegated.
# |
Item |
State |
Who |
|---|---|---|---|
1 |
Full parity on the GPU machine |
done from a fresh clone at |
done here; repeat on the release commit |
2 |
Performance gates and the parity certificates |
the gates are recorded in |
to do on the release commit (maintainer or AI assistant, on request) |
3 |
Sanitizers and mutation checks |
|
re-run on the release commit |
4 |
Distributions build and install |
|
orchestrator: first hosted run on the M5 pull request (needs item 14) |
5 |
|
the CHANGELOG draft summary exists |
release pull requests (maintainer), after the author’s go |
6 |
|
not yet (still the pre-release record) |
the same pull request |
7 |
Tag |
not done: nothing is published in M5 |
author (tag); then maintainer (smoke install) |
8 |
Tag |
not done |
author (tag, approve the deployment) |
9 |
GitHub Release from the CHANGELOG section |
not done |
author |
10 |
Zenodo DOI, Read the Docs |
not connected (checkpoint A4, M6) |
author, later (A4) |
11 |
Announce; curate the good-first-issue backlog |
not done |
maintainer, after the release |
12 |
Maturity |
both |
decision before the release commit (author) |
13 |
Required checks: |
to add after they have run on the M5 pull request ( |
author (account-level) |
14 |
|
to add before |
author (account-level) |
15 |
Licence metadata of the wheel: it bundles nanobind (BSD-3-Clause), robin-map (MIT) and the GCC runtime (GPL-3.0-or-later WITH GCC-exception-3.1), whose texts |
open: licensing is not delegated (GOVERNANCE.md) |
author (decide; record in the approvals log) |