From f52ee85a6248cf35e35675420af551ee4205eb77 Mon Sep 17 00:00:00 2001 From: "Harris, Austin" Date: Wed, 17 Jun 2026 13:23:47 -0400 Subject: [PATCH 1/3] Prepare v1.0 release closeout records --- docs/release-notes-v1.0.0.md | 155 ++++++++++++++++++++++++ docs/release-validation-v1.0.0.md | 134 ++++++++++++++++++++ docs/release.md | 7 ++ tests/check_release_docs_contract.cmake | 2 + 4 files changed, 298 insertions(+) create mode 100644 docs/release-notes-v1.0.0.md create mode 100644 docs/release-validation-v1.0.0.md diff --git a/docs/release-notes-v1.0.0.md b/docs/release-notes-v1.0.0.md new file mode 100644 index 0000000..b1a1815 --- /dev/null +++ b/docs/release-notes-v1.0.0.md @@ -0,0 +1,155 @@ +# fTimer v1.0.0 Release Notes Draft + +Status: release-prep draft for issue #354. This file is the prepared release +note source for the eventual `v1.0.0` GitHub release. It does not create a tag, +publish a GitHub release, or add release assets. + +## Audience And Scope + +fTimer 1.0.0 is for Fortran projects that need disciplined wall-clock timing +with structured summaries, human reports, CSV exports, and an explicit +correctness contract. The release-supported workflows are: + +- serial/local timing through `ftimer` or `ftimer_core`; +- strict pure-MPI timing and sparse pure-MPI union timing through the validated + `mpi_f08` communicator contract; +- OpenMP compatibility timing where existing `ftimer` / `ftimer_core` calls + bracket a parallel region from serial context; +- true OpenMP worker timing through the explicit `ftimer_openmp_t` object API; +- strict MPI+OpenMP rank/lane summaries, reports, and CSV output through + `ftimer_openmp_t`; and +- sparse union MPI+OpenMP rank/lane participation summaries, reports, and CSV + output through `ftimer_openmp_t`. + +See the claim boundary in [`docs/release-evidence.md`](release-evidence.md) +and the execution checklist in [`docs/release.md`](release.md). + +## Highlights + +- Serial timing remains the smallest adoption path: initialize, start/stop named + timers, retrieve `ftimer_summary_t`, and print or write reports. +- Pure-MPI timing uses `mpi_f08` `type(MPI_Comm)` handles captured at `init`. + Strict MPI summaries require matching descriptor trees; sparse union MPI + summaries represent rank-conditional participation explicitly. +- `FTIMER_USE_OPENMP=ON` keeps the existing APIs on the documented + master-thread-only compatibility carve-out. Worker-thread calls through those + existing APIs are silent no-ops and do not contribute timing data. +- `ftimer_openmp_t` is the supported opt-in worker-timing surface. It uses + serial-context lifecycle/catalog calls, pre-registered timer ids, explicit + timed level-1 OpenMP regions, and stopped-run local OpenMP summaries. +- MPI+OpenMP builds add strict and sparse union hybrid report families for + rank/lane data. Strict hybrid output rejects descriptor or eligible-lane + mismatches; sparse union hybrid output keeps missing rank/lane samples as + participation metadata rather than zero-filled timing samples. +- The source examples named by the release are + [`examples/basic_usage.F90`](../examples/basic_usage.F90), + [`examples/mpi_example.F90`](../examples/mpi_example.F90), + [`examples/openmp_example.F90`](../examples/openmp_example.F90), + [`examples/openmp_worker_example.F90`](../examples/openmp_worker_example.F90), + and [`examples/mpi_openmp_example.F90`](../examples/mpi_openmp_example.F90). + +## Compatibility And Public Surface + +- The stable source-level import surfaces are `ftimer`, `ftimer_core`, + `ftimer_openmp`, and `ftimer_types`. +- For the 1.x release line, CMake package version compatibility uses + `SameMajorVersion`: a `1.y.z` install may satisfy same-major requests at or + older than the installed package version, rejects future-major requests, and + rejects same-major requests newer than the installed package. +- Installed Fortran `.mod` files remain compiler-, wrapper-, runtime-, and + feature-mode-specific artifacts. A serial install is not promised to satisfy + an MPI, OpenMP, MPI+OpenMP, or different-compiler downstream build. +- CSV is the stable machine-readable export family. Local and strict MPI CSV + share the `format_version=2` schema line; sparse MPI union, local OpenMP, + strict MPI+OpenMP, and sparse MPI+OpenMP union use dedicated schemas that are + not append-compatible with each other. +- Fixed-width text reports are human-facing output. Use structured summary + objects or CSV for machine parsing. +- The callback hook remains a lightweight intra-run event hook, not a stable + profiler-backend integration contract with semantic timer identity. + +Detailed API and installed-package notes live in +[`docs/installed-api.md`](installed-api.md). CSV field details live in +[`docs/csv-schema.md`](csv-schema.md). + +## Packaging And Artifacts + +The v1.0.0 release artifact policy is source-only: + +- publish the annotated or signed `v1.0.0` tag; +- publish GitHub release notes from this draft after final validation; +- rely on GitHub-generated source archives, which include the root + [`LICENSE`](../LICENSE); and +- keep generated install-tree artifacts reproducible through the documented + CMake install path. + +Do not attach binary packages, generated install trees, compiler module +bundles, benchmark CSVs, generated reports, Spack recipes, or EasyBuild +easyconfigs to the GitHub release unless a separate release issue accepts that +artifact type and records its build, validation, and licensing basis. + +The installed CMake package path installs documentation under +`share/doc/fTimer/`, including `installed-api.md` and `LICENSE`. + +## Migration Notes + +- Existing serial and pure-MPI users do not need source changes for v1.0.0. +- Existing OpenMP compatibility users should keep timing calls outside + `!$omp parallel` blocks when they want one wall-clock interval for a parallel + region. +- Applications that currently call `ftimer_start`/`ftimer_stop` inside an + OpenMP parallel region expecting every worker to contribute should either + move those calls outside the parallel region or migrate those hot paths to + `ftimer_openmp_t`. +- Applications that need compile-out behavior should use an application-owned + timing facade. fTimer does not install a drop-in no-op `ftimer` module. + +## Known Limitations And Deferred Work + +- MPICH MPI+OpenMP hybrid support is caveated for v1.0.0: OpenMPI + MPI+OpenMP is routine CI-covered, while MPICH MPI+OpenMP remains focused + local-evidence-backed support from the release ledger, not permanent PR CI + coverage. Issue #353 owns that decision. +- Package-manager availability and package-recipe ownership remain post-v1.0 + questions tracked by issue #355. The Spack and EasyBuild material in + [`docs/package-manager-readiness.md`](package-manager-readiness.md) is + readiness guidance only, not maintained package-manager support. +- Fixed-team or no-explicit-region OpenMP worker ergonomics are deferred to + issue #294. +- Ubuntu 24.04 MPICH pFUnit runner migration remains post-release maintenance + tracked by issue #259. +- NVHPC serial smoke/install-consumer validation remains unclaimed and tracked + by issue #256. +- fTimer remains wall-clock only. It does not synchronize accelerator/device + queues, insert MPI barriers, provide hardware counters, emit traces, publish + dashboards, support FPM packaging, or claim profiler-backend integration. + +## Validation Summary + +The release-prep validation record is +[`docs/release-validation-v1.0.0.md`](release-validation-v1.0.0.md). It records +local commands, toolchain versions, skips, artifact checks, and the required CI +jobs for the release-prep PR. + +Before tagging, require the release-prep PR to pass every job in +[`.github/workflows/ci.yml`](../.github/workflows/ci.yml), including the +`CI` workflow jobs, `Codex Review Routing and Triggers`, and +`Codex Review Coverage`. + +## Benchmark Evidence Handling + +Benchmark CSVs are review evidence, not release assets and not pass/fail +thresholds. This release note intentionally makes no benchmark trend or +absolute-overhead claim. Any future release-note benchmark observation must +cite the corresponding CSV plus a sidecar/provenance record as described in +[`docs/release.md`](release.md). + +## Important Release-Readiness Links + +- Umbrella: #348 +- This closeout issue: #354 +- 1.x compatibility decision: #349 +- v1.0 package-version implementation: #350 and PR #356 +- public API and output-surface decision: #351 +- v1.0 claim/evidence refresh: #352 and PR #357 +- MPICH MPI+OpenMP evidence decision: #353 diff --git a/docs/release-validation-v1.0.0.md b/docs/release-validation-v1.0.0.md new file mode 100644 index 0000000..aa94798 --- /dev/null +++ b/docs/release-validation-v1.0.0.md @@ -0,0 +1,134 @@ +# fTimer v1.0.0 Validation And Artifact Record + +Status: release-prep record for issue #354. This record supports the +v1.0.0 release-notes draft in +[`docs/release-notes-v1.0.0.md`](release-notes-v1.0.0.md). It does not tag or +publish the release. + +## Claim Boundary + +Validation and release wording for v1.0.0 are bounded by +[`docs/release-evidence.md`](release-evidence.md). In particular: + +- #349, #350, #351, #352, and #353 are the release-blocking prerequisite + decisions or implementations for this closeout. +- #355, #294, #259, and #256 remain post-release or non-blocking follow-ups + unless a maintainer later changes their scope. +- MPICH MPI+OpenMP hybrid support remains local-evidence-backed and caveated + for v1.0.0, not permanent PR CI coverage. +- Package-manager material is readiness guidance only. +- Benchmark observations require CSV plus sidecar/provenance evidence before + they can become release-note trend claims. + +## Local Environment + +Local validation for this PR was run on: + +- OS: Darwin `mac149625` 25.5.0, arm64. +- CMake: 4.3.3. +- GNU Fortran: Homebrew GCC 15.3.0 at `/opt/homebrew/bin/gfortran`. +- MPI wrapper: `/opt/homebrew/bin/mpifort`, reporting GNU Fortran 15.3.0. +- MPI launcher: `/opt/homebrew/bin/mpiexec`, Open MPI 5.0.9. +- pFUnit: `/opt/homebrew/PFUNIT-4.16`, `PFUNIT_VERSION` 4.16.0, + `PFUNIT_MPI_FOUND` true. +- LLVM Flang: `/opt/homebrew/bin/flang`, Homebrew flang 22.1.7. + `flang-19` was not on `PATH` locally. + +## Local Validation Commands + +The release checklist in [`docs/release.md`](release.md) defines the command +set. This PR records exact local commands and CI coverage rather than +overclaiming unavailable local toolchains. + +| Area | Command | Local status | +| --- | --- | --- | +| Smoke/install path | `cmake -B build-smoke` | Passed with default `/opt/homebrew/bin/flang` LLVMFlang 22.1.7. | +| Smoke/install path | `cmake --build build-smoke` | Passed. | +| Smoke/install path | `cmake -E chdir build-smoke ctest --output-on-failure` | Passed, 25/25 tests. This included `ftimer_release_docs_contract`, `ftimer_installed_package_consumer`, installed docs checks, examples, and contract checks. | +| Serial pFUnit | `FC=gfortran cmake -B build -DFTIMER_BUILD_TESTS=ON -DPFUNIT_DIR=/opt/homebrew/PFUNIT-4.16` | Passed with `/opt/homebrew/bin/gfortran` 15.3.0. | +| Serial pFUnit | `cmake --build build` | Passed. | +| Serial pFUnit | `cmake -E chdir build ctest --output-on-failure` | Passed, 26/26 tests, including `ftimer_serial_tests`. | +| MPI pFUnit | `FC=mpifort cmake -B build-mpi -DFTIMER_USE_MPI=ON -DFTIMER_BUILD_TESTS=ON -DPFUNIT_DIR=/opt/homebrew/PFUNIT-4.16 -DMPIEXEC_EXECUTABLE=/opt/homebrew/bin/mpiexec` | Passed with `/opt/homebrew/bin/mpifort` and Open MPI 5.0.9. | +| MPI pFUnit | `cmake --build build-mpi` | Passed. | +| MPI pFUnit | `cmake -E chdir build-mpi ctest --output-on-failure -L mpi` | Did not complete locally: CTest-launched `ftimer_mpi_tests` and `ftimer_mpi_tests_4pe` failed before test execution with Open MPI reporting `All nodes which are allocated for this job are already filled.` The same CTest run passed `ftimer_mpi_example_smoke`. Direct generated pFUnit commands passed: `/opt/homebrew/bin/mpiexec -n 2 .../ftimer_mpi_tests --verbose` reported OK with 79 tests, and `/opt/homebrew/bin/mpiexec -n 4 .../ftimer_mpi_tests_4pe --verbose` reported OK with 22 tests. | +| MPI+OpenMP smoke | `FC=mpifort cmake -B build-mpi-openmp -DFTIMER_USE_MPI=ON -DFTIMER_USE_OPENMP=ON` | Passed with `/opt/homebrew/bin/mpifort` and Open MPI 5.0.9. | +| MPI+OpenMP smoke | `cmake --build build-mpi-openmp` | Passed. | +| MPI+OpenMP smoke | `cmake -E chdir build-mpi-openmp ctest --output-on-failure` | Passed, 35/35 tests, including MPI+OpenMP example and installed-consumer coverage. | +| OpenMP pFUnit | `FC=gfortran cmake -B build-openmp -DFTIMER_USE_OPENMP=ON -DFTIMER_BUILD_TESTS=ON -DPFUNIT_DIR=/opt/homebrew/PFUNIT-4.16` | Passed with `/opt/homebrew/bin/gfortran` 15.3.0. | +| OpenMP pFUnit | `cmake --build build-openmp` | Passed. | +| OpenMP pFUnit | `cmake -E chdir build-openmp ctest --output-on-failure` | Passed, 31/31 tests, including OpenMP guard tests and worker examples. | +| Benchmark harness | `cmake -S . -B build-bench -DFTIMER_BUILD_BENCH=ON -DCMAKE_BUILD_TYPE=Release` | Passed with default `/opt/homebrew/bin/flang` LLVMFlang 22.1.7. | +| Benchmark harness | `cmake --build build-bench --target ftimer_bench` | Passed. | +| Benchmark harness | `./build-bench/bench/ftimer_bench /tmp/ftimer_bench_results.csv` | Passed and wrote a 52-line CSV at `/tmp/ftimer_bench_results.csv`. Numeric rows are not used as release-note trend claims in this PR. | +| Diff hygiene | `git diff --check` | Passed after final doc updates. | + +## Unavailable Local Validation + +- The documented `flang-19` executable was not available on `PATH`; local + smoke and benchmark configures used Homebrew `/opt/homebrew/bin/flang` + 22.1.7 where CMake selected it by default. The corresponding CI job for the + documented LLVM Flang OpenMP path remains `build-openmp-flang`. +- MPICH local validation was not run from this worktree because the local + `mpifort` / `mpiexec` pair is Open MPI 5.0.9 and `mpifort.mpich` was not on + `PATH`. The release evidence for pure MPICH remains the CI + `build-mpi-mpich` and `test-mpi-mpich` jobs; the MPICH MPI+OpenMP hybrid + boundary remains the #353 local-evidence caveat. +- Direct Spack and EasyBuild execution was not run because package-manager + availability remains a post-v1.0 ownership question tracked by #355, and + neither `spack` nor `eb` was on `PATH` locally. +- NVHPC validation was not run and is not claimed; #256 remains the + post-release investigation issue. + +## Required CI Proof + +Before the release-prep PR can be considered merge-ready, the following CI +proof must be green on the PR head: + +- `build-serial` +- `build-serial-flang` +- `build-mpi` +- `build-mpi-mpich` +- `build-mpi-openmp` +- `test-serial` +- `test-mpi` +- `test-mpi-mpich` +- `build-openmp` +- `build-openmp-flang` +- `test-openmp` +- `build-contract-regressions` +- `build-bench` +- `build-openmp-bench` +- `build-mpi-openmp-bench` +- `lint` +- `Codex Review Routing and Triggers` +- `Codex Review Coverage` + +## Artifact Closeout + +- `CMakeLists.txt` declares `project(fTimer VERSION 1.0.0)`. +- `CMakeLists.txt` sets `FTIMER_PACKAGE_VERSION_COMPATIBILITY` to + `SameMajorVersion` for the 1.x package line. +- The normal release artifact policy remains source archive plus release notes + plus the root [`LICENSE`](../LICENSE). No binary package, generated install + tree, compiler module bundle, benchmark CSV, generated report, Spack recipe, + or EasyBuild easyconfig is part of the v1.0.0 GitHub release artifact set. +- The CMake install path installs documentation under `share/doc/fTimer/`, + including `installed-api.md` and `LICENSE`. The installed-consumer smoke path + and release evidence cover that artifact contract. + +## Benchmark Closeout + +The local benchmark command in this record is a release-readiness smoke and +review-evidence command. This PR does not commit generated benchmark CSV output +and the v1.0.0 release-notes draft makes no benchmark trend or absolute +overhead claim. Any later benchmark observation in release notes must include +the benchmark CSV and the sidecar/provenance fields required by +[`docs/release.md`](release.md). + +## Post-Release Triage Expectations + +After publication, label confirmed release regressions with `post-release`. +Use `release-blocker` only when an issue blocks the next release or patch. +Security-sensitive reports follow [`SECURITY.md`](../SECURITY.md), not public +issue triage. Keep release-note corrections factual and timestamped if they +materially change user guidance. diff --git a/docs/release.md b/docs/release.md index b47949a..160795f 100644 --- a/docs/release.md +++ b/docs/release.md @@ -283,6 +283,13 @@ the readiness spike, MPICH hybrid is local-evidence-backed rather than permanent CI-covered, and NVHPC remains unvalidated unless #256 or a later issue changes that evidence. +The prepared v1.0.0 release-note draft lives in +[`docs/release-notes-v1.0.0.md`](release-notes-v1.0.0.md), with the companion +validation and artifact record in +[`docs/release-validation-v1.0.0.md`](release-validation-v1.0.0.md). Keep both +files aligned with this checklist and +[`docs/release-evidence.md`](release-evidence.md) until the tag is published. + ## Tag And Publish After the release-prep PR has merged and `main` is current: diff --git a/tests/check_release_docs_contract.cmake b/tests/check_release_docs_contract.cmake index 41e05e3..215d648 100644 --- a/tests/check_release_docs_contract.cmake +++ b/tests/check_release_docs_contract.cmake @@ -15,6 +15,8 @@ set(required_paths docs/package-manager-readiness.md docs/release-evidence.md docs/release.md + docs/release-notes-v1.0.0.md + docs/release-validation-v1.0.0.md docs/semantics.md docs/troubleshooting.md CONTRIBUTING.md From 792b0ced77105b58a9ee8cc09417057ee30c0ce3 Mon Sep 17 00:00:00 2001 From: "Harris, Austin" Date: Wed, 17 Jun 2026 13:34:26 -0400 Subject: [PATCH 2/3] Check v1 release closeout doc claims --- tests/check_release_docs_contract.cmake | 125 ++++++++++++++++++++++++ 1 file changed, 125 insertions(+) diff --git a/tests/check_release_docs_contract.cmake b/tests/check_release_docs_contract.cmake index 215d648..1d307db 100644 --- a/tests/check_release_docs_contract.cmake +++ b/tests/check_release_docs_contract.cmake @@ -1124,6 +1124,131 @@ endif() file(READ "${REPO_ROOT}/docs/release-evidence.md" release_evidence_text) file(READ "${REPO_ROOT}/docs/installed-api.md" installed_api_text) +file(READ "${REPO_ROOT}/docs/release-notes-v1.0.0.md" release_notes_v1_text) +file(READ "${REPO_ROOT}/docs/release-validation-v1.0.0.md" release_validation_v1_text) +file(READ "${REPO_ROOT}/CMakeLists.txt" cmake_lists_text) +file(READ "${REPO_ROOT}/.github/workflows/ci.yml" ci_workflow_text) + +function(require_release_text_contains doc_name doc_text needle) + string(FIND "${doc_text}" "${needle}" release_text_needle_index) + if(release_text_needle_index EQUAL -1) + message(FATAL_ERROR + "${doc_name} must keep v1 release closeout term: ${needle}" + ) + endif() +endfunction() + +set(release_notes_v1_required_terms + "serial/local timing through `ftimer` or `ftimer_core`" + "strict pure-MPI timing and sparse pure-MPI union timing" + "OpenMP compatibility timing" + "true OpenMP worker timing through the explicit `ftimer_openmp_t` object API" + "strict MPI+OpenMP rank/lane summaries, reports, and CSV output" + "sparse union MPI+OpenMP rank/lane participation summaries" + "`SameMajorVersion`" + "CSV is the stable machine-readable export family." + "Fixed-width text reports are human-facing output." + "source-only" + "Do not attach binary packages" + "generated install trees" + "compiler module" + "benchmark CSVs" + "Spack recipes" + "EasyBuild" + "MPICH MPI+OpenMP hybrid support is caveated" + "permanent PR CI" + "Package-manager availability and package-recipe ownership remain post-v1.0" + "issue #355" + "issue #294" + "issue #259" + "NVHPC serial smoke/install-consumer validation remains unclaimed" + "issue #256" + "benchmark trend" + "CSV plus a sidecar/provenance record" + "Codex Review Routing and Triggers" + "Codex Review Coverage" +) + +foreach(release_notes_v1_required_term IN LISTS release_notes_v1_required_terms) + require_release_text_contains("docs/release-notes-v1.0.0.md" + "${release_notes_v1_text}" "${release_notes_v1_required_term}") +endforeach() + +if(NOT cmake_lists_text MATCHES "project\\(fTimer[^\)]*VERSION[ \t\r\n]+1\\.0\\.0") + message(FATAL_ERROR + "CMakeLists.txt must keep project(fTimer VERSION 1.0.0) for the v1.0 release closeout." + ) +endif() + +if(NOT cmake_lists_text MATCHES "set\\(FTIMER_PACKAGE_VERSION_COMPATIBILITY[ \t\r\n]+SameMajorVersion\\)") + message(FATAL_ERROR + "CMakeLists.txt must keep FTIMER_PACKAGE_VERSION_COMPATIBILITY SameMajorVersion for the 1.x release line." + ) +endif() + +set(release_validation_v1_required_terms + "project(fTimer VERSION 1.0.0)" + "FTIMER_PACKAGE_VERSION_COMPATIBILITY" + "`SameMajorVersion`" + "source archive plus release notes" + "[`LICENSE`](../LICENSE)" + "installed-api.md" + "No binary package" + "No binary package, generated install" + "benchmark CSV" + "Spack recipe" + "EasyBuild easyconfig" + "post-release" + "release-blocker" + "Security-sensitive reports follow [`SECURITY.md`](../SECURITY.md)" +) + +foreach(release_validation_v1_required_term IN LISTS release_validation_v1_required_terms) + require_release_text_contains("docs/release-validation-v1.0.0.md" + "${release_validation_v1_text}" "${release_validation_v1_required_term}") +endforeach() + +set(release_validation_required_ci_jobs + build-serial + build-serial-flang + build-mpi + build-mpi-mpich + build-mpi-openmp + test-serial + test-mpi + test-mpi-mpich + build-openmp + build-openmp-flang + test-openmp + build-contract-regressions + build-bench + build-openmp-bench + build-mpi-openmp-bench + lint +) + +foreach(release_validation_required_ci_job IN LISTS release_validation_required_ci_jobs) + require_release_text_contains("docs/release-validation-v1.0.0.md" + "${release_validation_v1_text}" "- `${release_validation_required_ci_job}`") + + string(FIND "${ci_workflow_text}" "\n ${release_validation_required_ci_job}:" + ci_job_index) + if(ci_job_index EQUAL -1) + message(FATAL_ERROR + "docs/release-validation-v1.0.0.md lists CI job '${release_validation_required_ci_job}', but .github/workflows/ci.yml does not define it." + ) + endif() +endforeach() + +set(release_validation_required_status_checks + "Codex Review Routing and Triggers" + "Codex Review Coverage" +) + +foreach(release_validation_required_status_check IN LISTS release_validation_required_status_checks) + require_release_text_contains("docs/release-validation-v1.0.0.md" + "${release_validation_v1_text}" "- `${release_validation_required_status_check}`") +endforeach() set(readme_v1_package_contract_terms "For the 1.x release line, CMake package compatibility uses same-major matching." From a479211f665a89810a0bfb15feea382299a60084 Mon Sep 17 00:00:00 2001 From: "Harris, Austin" Date: Wed, 17 Jun 2026 13:41:45 -0400 Subject: [PATCH 3/3] Tighten release closeout contract checks --- tests/check_release_docs_contract.cmake | 121 ++++++++++++++++++------ 1 file changed, 92 insertions(+), 29 deletions(-) diff --git a/tests/check_release_docs_contract.cmake b/tests/check_release_docs_contract.cmake index 1d307db..135e691 100644 --- a/tests/check_release_docs_contract.cmake +++ b/tests/check_release_docs_contract.cmake @@ -1127,7 +1127,12 @@ file(READ "${REPO_ROOT}/docs/installed-api.md" installed_api_text) file(READ "${REPO_ROOT}/docs/release-notes-v1.0.0.md" release_notes_v1_text) file(READ "${REPO_ROOT}/docs/release-validation-v1.0.0.md" release_validation_v1_text) file(READ "${REPO_ROOT}/CMakeLists.txt" cmake_lists_text) -file(READ "${REPO_ROOT}/.github/workflows/ci.yml" ci_workflow_text) +file(READ "${REPO_ROOT}/.github/workflows/codex-review.yml" codex_review_workflow_text) +file(READ "${REPO_ROOT}/.github/workflows/codex-review-coverage.yml" + codex_review_coverage_workflow_text) +file(STRINGS "${REPO_ROOT}/docs/release-validation-v1.0.0.md" + release_validation_v1_lines) +file(STRINGS "${REPO_ROOT}/.github/workflows/ci.yml" ci_workflow_lines) function(require_release_text_contains doc_name doc_text needle) string(FIND "${doc_text}" "${needle}" release_text_needle_index) @@ -1146,12 +1151,19 @@ set(release_notes_v1_required_terms "strict MPI+OpenMP rank/lane summaries, reports, and CSV output" "sparse union MPI+OpenMP rank/lane participation summaries" "`SameMajorVersion`" + "older than the installed package version" + "rejects future-major requests" + "rejects same-major requests newer than the installed package" "CSV is the stable machine-readable export family." "Fixed-width text reports are human-facing output." "source-only" "Do not attach binary packages" "generated install trees" "compiler module" + "compiler-, wrapper-, runtime-, and" + "feature-mode-specific artifacts" + "A serial install is not promised to satisfy" + "an MPI, OpenMP, MPI+OpenMP, or different-compiler downstream build" "benchmark CSVs" "Spack recipes" "EasyBuild" @@ -1208,46 +1220,97 @@ foreach(release_validation_v1_required_term IN LISTS release_validation_v1_requi "${release_validation_v1_text}" "${release_validation_v1_required_term}") endforeach() -set(release_validation_required_ci_jobs - build-serial - build-serial-flang - build-mpi - build-mpi-mpich - build-mpi-openmp - test-serial - test-mpi - test-mpi-mpich - build-openmp - build-openmp-flang - test-openmp - build-contract-regressions - build-bench - build-openmp-bench - build-mpi-openmp-bench - lint -) - -foreach(release_validation_required_ci_job IN LISTS release_validation_required_ci_jobs) +function(extract_workflow_name doc_name workflow_text out_var) + string(REGEX MATCH "(^|\n)name:[ \t]*([^\n\r]+)" + workflow_name_match "${workflow_text}") + if(NOT workflow_name_match) + message(FATAL_ERROR "${doc_name} must define a workflow name.") + endif() + + set("${out_var}" "${CMAKE_MATCH_2}" PARENT_SCOPE) +endfunction() + +extract_workflow_name(".github/workflows/codex-review.yml" + "${codex_review_workflow_text}" codex_review_workflow_name) +extract_workflow_name(".github/workflows/codex-review-coverage.yml" + "${codex_review_coverage_workflow_text}" codex_review_coverage_workflow_name) + +set(ci_workflow_job_ids) +set(in_ci_jobs FALSE) +foreach(ci_workflow_line IN LISTS ci_workflow_lines) + if(ci_workflow_line STREQUAL "jobs:") + set(in_ci_jobs TRUE) + continue() + endif() + + if(in_ci_jobs AND ci_workflow_line MATCHES "^ ([A-Za-z0-9_-]+):$") + list(APPEND ci_workflow_job_ids "${CMAKE_MATCH_1}") + endif() +endforeach() + +if(NOT ci_workflow_job_ids) + message(FATAL_ERROR ".github/workflows/ci.yml must define at least one CI job.") +endif() + +set(release_validation_required_ci_proof_entries) +set(in_release_validation_ci_proof FALSE) +foreach(release_validation_v1_line IN LISTS release_validation_v1_lines) + if(release_validation_v1_line STREQUAL "## Required CI Proof") + set(in_release_validation_ci_proof TRUE) + continue() + endif() + + if(in_release_validation_ci_proof AND release_validation_v1_line MATCHES "^## ") + set(in_release_validation_ci_proof FALSE) + endif() + + if(in_release_validation_ci_proof AND release_validation_v1_line MATCHES "^- `([^`]+)`") + list(APPEND release_validation_required_ci_proof_entries "${CMAKE_MATCH_1}") + endif() +endforeach() + +set(release_validation_required_status_checks + "${codex_review_workflow_name}" + "${codex_review_coverage_workflow_name}" +) + +foreach(release_validation_required_ci_job IN LISTS ci_workflow_job_ids) require_release_text_contains("docs/release-validation-v1.0.0.md" "${release_validation_v1_text}" "- `${release_validation_required_ci_job}`") - string(FIND "${ci_workflow_text}" "\n ${release_validation_required_ci_job}:" - ci_job_index) + list(FIND release_validation_required_ci_proof_entries + "${release_validation_required_ci_job}" ci_job_index) if(ci_job_index EQUAL -1) message(FATAL_ERROR - "docs/release-validation-v1.0.0.md lists CI job '${release_validation_required_ci_job}', but .github/workflows/ci.yml does not define it." + "docs/release-validation-v1.0.0.md Required CI Proof must list CI job '${release_validation_required_ci_job}' from .github/workflows/ci.yml." ) endif() endforeach() -set(release_validation_required_status_checks - "Codex Review Routing and Triggers" - "Codex Review Coverage" -) - foreach(release_validation_required_status_check IN LISTS release_validation_required_status_checks) require_release_text_contains("docs/release-validation-v1.0.0.md" "${release_validation_v1_text}" "- `${release_validation_required_status_check}`") + + list(FIND release_validation_required_ci_proof_entries + "${release_validation_required_status_check}" status_check_index) + if(status_check_index EQUAL -1) + message(FATAL_ERROR + "docs/release-validation-v1.0.0.md Required CI Proof must list Codex workflow status '${release_validation_required_status_check}'." + ) + endif() +endforeach() + +foreach(release_validation_required_ci_proof_entry IN LISTS release_validation_required_ci_proof_entries) + list(FIND ci_workflow_job_ids "${release_validation_required_ci_proof_entry}" + ci_job_index) + list(FIND release_validation_required_status_checks + "${release_validation_required_ci_proof_entry}" status_check_index) + + if(ci_job_index EQUAL -1 AND status_check_index EQUAL -1) + message(FATAL_ERROR + "docs/release-validation-v1.0.0.md Required CI Proof lists '${release_validation_required_ci_proof_entry}', but it is neither a .github/workflows/ci.yml job nor a Codex review workflow name." + ) + endif() endforeach() set(readme_v1_package_contract_terms