Retrospective: R010 (release preparation for 0.1.0rc1)#
Status: ready for the release candidate on the branch release-0.1.0 (from main at
8842acf, the merge of pull request #4 with M5). Nothing is published by this milestone: the
tags v0.1.0rc1 / v0.1.0 and the GitHub Release are pushed by the orchestrator afterwards (the
author’s decision of 2026-09-30, GOVERNANCE.md), and the PyPI deployment waits for the author’s
approval. R010 was done in two steps, each by one implementer, and a third step fixed what the
independent review found; each step has its section here.
Step 1: the benchmark-suite records and the release certificate (suites-cert)#
What was built#
Item |
Where |
|---|---|
The benchmark-suite records of PLAN 8.5 for 0.1’s algorithms |
|
The suite runner: |
|
The parity certificate of PLAN 8.3 and the release checks |
|
The golden mutation checks of PLAN 8.4 for sssp |
|
Tests (no builds, GPUs or originals needed; run by |
|
Documentation |
|
The release gate, the golden replays and the checks on the release code |
|
Deviations from the plan (each with the same intent)#
The sssp suite is
ipdps25_dynamosp_sosp.yaml, notipdps25_dynamosp.yaml. The DynaMOSP papers time the K = 3 per-objective updates plus the combined-graph step (mosp, 0.2); 0.1 ports the per-objective update (sssp), which the 0.1 gate compares per objective (PLAN 6.4.2). A suite named after the paper but timing only part of its pipeline would be misleading, so the 0.1 suite carries the_sospsuffix and says what it measures; the mosp-level suitesipdps25_dynamosp.yamlandtpds25_dynamosp.yamlcome withmosp.The runner is
parity/bench_suite.pyover the A/B harness, notdyng-bench run. PLAN 8.5 item 2 describes an end-to-end driver through the public API (tools/bench,benchmarks/run.py); the gates of PLAN 8.6 are read by the existing A/B harness through the compat tools, which is what a release must certify. The suite format is the one of PLAN 8.5’s example (datasets, batches with seeds, backends, runs, metrics mapped to profiler stages, baselines, tolerances), extended withreadings(which harness invocation, which clock lock, gated or recorded) and validated against the harness. A public-API driver can read the same files later.No
benchmarks/baselines/<repo>-<commit>.jsonfiles. The original’s medians are in every compacted record and in the suite summaries (original_ms,original_mib), next to the hardware and the commit; a separate copy would duplicate them.The temporal datasets of DynTruCy (CollegeMsg, email-Eu-core, time-window mode) are listed under
deferredin the suite and not run: the time-window and temporal modes arrive in 0.4.parity/mutate.pycovers the sssp mutation only. The cycle_count mutations of PLAN 8.4 are CTests since M2a (ctest -L mutation, host and CUDA);mutate.pyadds the one that needs the golden corpus (a skipped subtree invalidation, on each backend). The triad, label propagation and MOSP_ESCHER mutations come with their ports.
Results (benchmarks/results/0.1.0rc1/)#
The certificate parity.json (written by parity/certify.py write at b80ac38) states all
parts passed; the measured builds are from clean clones at d13d393 (the gates, the golden
replays, the sssp golden mutations) and 1049068 (the test-suite checks), both with the library,
compat tools and build system of main at 8842acf, which the certificate checks.
Part |
Result |
|---|---|
Golden replays |
|
|
132 / 132 gated regions within their gates (OpenMP 60, CUDA at boost clocks 60, CUDA memory 12); ratios 0.631-1.046; the default-clock readings (60 regions, 0.666-1.062) recorded |
|
78 / 78 (OpenMP 16, CUDA at boost 37, the COLLAB update at base 5, CUDA memory 20); ratios 0.229-1.005; the default-clock reading (42 regions, 0.222-1.003) recorded |
|
595 / 595 (26 skipped) and 520 / 520 (42 skipped) |
|
every step passed: CUDA tests (gpu 252, cpu 605), the CUDA goldens, memcheck, synccheck, racecheck, clang-tidy |
Mutation checks |
the cycle_count CTests 7 / 7; the sssp golden mutation fails the goldens on sequential, OpenMP and CUDA, the control passes |
What happened on the way#
A busy shared machine during the first pass. At times between 23:51 on 2026-09-30 and 01:00 CDT a workload outside the perf lock kept about 27 cores busy. The A/B harness of sssp rejected the rounds and, after 12 rejections, stopped two readings (CUDA
road_usa_gat locked clocks, default-clockroadNet-PA), as designed; the OpenMP cycle_count harness flags such runs but does not repeat them, so its reading completed with almost every run flagged, and the summary passed it.bench_suite.py summarizenow lists flagged runs per case undercontaminated(without failing, PLAN 8.6), and the flagged reading was taken again with the two stopped ones and the default-clock cycle_count reading the usage limit had interrupted (README of the results, “Readings taken again”). Note for later: the cycle_count OpenMP harness should repeat flagged runs like the others (a change toparity/cycle_count_perf.py, deliberately not made during a release).No re-measurement for the later commits. The commits after
d13d393change only harness scripts, documents and C++ tests, which the certificate verifies (git diffover the library paths is empty); a measurement is not repeated for them.Portability pre-check (the C++ test changes of
dd09893): the Clang 18 syntax pass over the dev build’s 161 translation units and the_FORTIFY_SOURCE=3cpu-only build are clean.
Step 2: the release changes, the distributions and the checks on the release code (bump-meta)#
What changed#
Item |
Where |
|---|---|
|
|
The CHANGELOG section |
|
|
|
|
|
|
the manifests, |
Status lines: “alpha: 0.1 release candidate” instead of pre-alpha |
|
The approvals log: the decisions of 2026-09-30 (the AI assistant pushes |
|
Who does what for 0.1.0 and later releases; how to build a tag’s distributions locally as |
|
|
|
Deviations and decisions (each with the same intent)#
The certificate accepts a metadata-only library difference with an equivalence record. Making the algorithms stable changes
cpp/src(the two manifests and the generated registry table) after step 1 measured the gates, the replays and the sssp golden mutations atd13d393; under step 1’s rule (the measured commit has the release’s library sources) the certificate would fail, and measuring the whole gate again would take several hours of the exclusive lock that M7 also needs, for a change no measured program executes. Instead,parity/certify.py equivalencebuildsd13d393and the release’s library over it in one clone (same paths, sameVERSION, presetsparityandparity-cuda) and compares the files: both compat tools are byte-identical andlibdyng.sodiffers only insidedyng::algorithms()(553 bytes of.text) plus the build id, unwind and symbol tables, with every section and symbol at the same address. The rule is narrow: only the files ofMETADATA_PATHS, only the library scope (the gates, the replays, the golden mutations), and only with a passed pair whose release side has the release’s library. The test-suite checks read the registry, so they were run again on the release code instead. The rule and the record are inparity.json(metadata_paths,equivalences).The decision date. The author’s decisions were given on 2026-09-30; the approvals log and the comments that cite them use that date, while the release date of the CHANGELOG and
CITATION.cffis 2026-10-01.The sdist carries the wheel’s licence expression. One
[project]table serves both, so the sdist (whose own files are all Apache-2.0) also names the bundled components’ licences; a broader expression than the sdist needs, never a narrower one (docs/developer/wheels.md).The pre-alpha wording was replaced in
CONTRIBUTING.md,SUPPORT.mdandSECURITY.mdtoo, not only in the README, so the repository says one thing.
Results (release code 07d46e2, a fresh clone of release-0.1.0; GPU 1)#
Check |
Result |
|---|---|
|
595 / 595 (26 skipped) and 520 / 520 (42 skipped), the same skips as at |
|
every step passed (CUDA tests gpu 252, cpu 605; the CUDA goldens; memcheck, synccheck, racecheck; clang-tidy) |
Mutation CTests |
7 / 7 ( |
|
all checks passed (including |
|
OK; 396 passed, 4 skipped (the optional torch, cupy and pandas are not installed) |
|
|
|
|
The wheel alone in fresh Python 3.12 and 3.13 venvs |
the whole suite 396 passed, 4 skipped; the cibuildwheel test subset 253 passed, 1 skipped ( |
Portability pre-check |
Clang 18 syntax pass over 174 translation units (with the Python bindings): 0 failures; the |
Certificate |
|
No tag was created and nothing was pushed or uploaded.
Notes for the orchestrator#
Superseded by the notes at the end of step 3 (the same points, plus what the review added).
Step 3: the review fixes (review-fix)#
The independent review of steps 1 and 2 found 15 problems, each confirmed by a second reviewer: the certificate could pass a partial suite, did not name the committed fixtures, claimed nothing about the inputs as measured, accepted checks without evidence or in too narrow a scope, and took the driver from the time it was written; and the release documents had gaps for the final release. All are fixed; none needed the gate to be measured again (deviations 1 and 2).
What changed#
Finding |
Fix |
|---|---|
A partial suite summary certified (high) |
|
The committed in-repo goldens not in the certificate (high) |
|
Inputs “not verified” (medium) |
the sssp harness hashes every input when a run starts ( |
Checks without evidence, scopes too narrow (medium) |
scopes |
The driver taken at write time (low) |
every harness record names the NVIDIA driver and the CUDA driver API version; the certificate takes the driver from the records, or, for records that predate the field, accepts the driver seen at write time only when it is shown unchanged since before the first measurement (deviation 1) |
The metadata-equivalence rule undocumented |
|
No certificate route for 0.1.0 |
|
O3 not tracked |
GOVERNANCE.md (O3: needed before 0.1.0 reaches PyPI), |
“License: Apache-2.0.” on the PyPI page |
|
Step 9 incomplete; no consistency check |
|
Roadmap and plan page |
updated (who tags, rc1 on TestPyPI, M5 merged, R010 in progress) |
|
it creates |
Zenodo timing |
|
The release date fixed before the tag |
|
|
|
The results README undercounted the second session |
five readings come from the second session (the cycle_count CUDA memory reading was first taken there) |
Two scope corrections found on the way: docs/references.bib is compiled into libdyng (for
dyng::citation()), so it is a library path; the C++ test suites build examples/cpp and the
README’s C++ quickstart, so examples and README.md are test paths. Neither changed since the
measured commits.
Deviations and decisions (each with the same intent)#
The 0.1.0rc1 records name no driver, and the gate was not measured again for it. The records of the first two steps predate the per-record field. Measuring the whole gate again (about five hours of the exclusive lock that M7 also needs) would only add the driver string. Instead
certify.pyshows that the driver seen when the certificate is written ran the measurements: the loaded kernel module is 590.48.01, the machine booted on 2026-08-10, the module file on disk (the only one a load since boot can have used) is 590.48.01 and was installed on 2026-08-05, andlibcuda.so.1->libcuda.so.590.48.01was installed on 2026-02-05, all before the first measurement (2026-10-01 02:28 UTC); the evidence is inparity.json(environment.driver.unchanged_since_first_measurement). From now on the records carry the driver and the certificate compares them.The sssp inputs of 0.1.0rc1 are verified after the fact. Their records carry the digests
preparewrote, not digests taken while measuring (and the memory records carry none). The summary hashes every input file again and requires each to equal the suite’s digest and to have been neither written nor replaced (modification and status-change times) since the execution started (the first command of the suite’s run log, 2026-09-30 21:28 CDT); the files were last changed between 2026-09-23 (the CSR files) and 2026-09-27 (the batches and initial trees). The cycle_count run records carry the digests their process took. New records are hashed when the run starts.The fixture tests’ results come from ctest’s per-test lines of the logs the checks already have (the
asanandtsanlogs at07d46e2;ci/gpu_local.shandci/check.sh --parityon the final code), not from a JUnit file: they are parsed when the check is recorded, and only the fixture tests are kept (the full logs are hashed).The
reposcope leaves outbenchmarks/results/, which is committed after the checks; everything else, documents included, must be the release’s, so the whole-tree checks ran after the last change outside the results.The release-date check is a warning in
release.ymland an error only before the tag (--release-date today, steps 7 and 10): once a tag is pushed, an error could not be fixed without deleting the tag.No cffconvert in CI. It is not in the development environment;
CITATION.cffwas validated with cffconvert 2.0 in step 2 and is unchanged, and--release-metadatachecks its version and date againstVERSIONand the CHANGELOG. Adding cffconvert tolint.ymlis left for a later infrastructure change.The M5 retrospective’s readiness list is not edited (it is the record of M5); O3 is tracked in GOVERNANCE.md,
release.mdstep 10 and the notes below.
Results#
Recorded in benchmarks/results/0.1.0rc1/README.md and parity.json, written by certify.py write on the final tree: the suites re-summarized from the same records (132 / 132 and 78 / 78
gated regions, unchanged; inputs verified; the driver shown unchanged), the committed fixtures,
and the checks with their scopes and evidence (asan, tsan and the mutation CTests of
07d46e2, whose test paths are unchanged; gpu_local, check-parity and distributions run
again on the final code from a clean clone; the sssp golden mutations of d13d393 through the
equivalence record). Tests: parity/tests and ci/tests (new cases for every fix). No C++ code
changed, so the portability pre-check has nothing new to compile.
Notes for the orchestrator#
Push
v0.1.0rc1only onmainafter the release pull request is merged (merge commit): the certificate names the release-branch commit, which stays reachable through the merge. Before pushing, runpython ci/wheel_check.py --release-metadata --release-date today: if the merge falls after 2026-10-01 (UTC), change the CHANGELOG date anddate-releasedin a small pull request first (release.mdstep 7).release.ymluploads the release candidate to TestPyPI only; step 8 of the checklist (the smoke install from TestPyPI on a CPU machine and on the GPU machine) follows.Before the author approves the
pypideployment ofv0.1.0, two author items must be settled: O3, the institution line and the years ofNOTICE(“software developed at the Missouri University of Science and Technology”, “Copyright 2023-2026 their authors”), which ships in every distribution (GOVERNANCE.md, open decisions); and the licence expression, recorded “pending objection before the final PyPI approval”: if the author objects, changepyproject.toml,LICENSE_EXPRESSIONinci/wheel_check.py,docs/developer/wheels.mdandpython/README.mdtogether beforev0.1.0.Zenodo: it archives only GitHub Releases published after it is switched on. If 0.1.0 should get a DOI, the author switches Zenodo on (checkpoint A4,
repository_settings.mdsection 14) before the GitHub Release of 0.1.0 (step 11); otherwise the first DOI comes with a later release, or 0.1.0 is uploaded to Zenodo by hand.The final release follows
release.mdstep 9 (“The final-release pull request”): the status and install texts,SECURITY.md, the CHANGELOG links, and the certificate underbenchmarks/results/0.1.0/(the rc’s carried over withcertify.py write --version 0.1.0after thepackagingandrepochecks, and the C++ test suites sinceREADME.mdchanges, are run again on the final tree).