Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/pages/mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ nav:
- Verification & Validation:
- V&V and Maturity: verification/evidence-and-maturity.md
- 0.2.10 Verification Summary: verification/0_2_10/README.md
- 0.2.11 Candidate Verification: verification/0_2_11/README.md
- 0.2.11 Verification Summary: verification/0_2_11/README.md
- Published 0.2.8 Verification: verification/0_2_8/README.md
- Benchmarks: benchmarks/index.md
- Historical Evidence:
Expand All @@ -67,7 +67,7 @@ nav:
- QF Solver vs scikit-fem: comparisons/qf-vs-scikit-fem.md
- QF Solver vs SfePy: comparisons/qf-vs-sfepy.md
- Project:
- What's New 0.2.11 (candidate): whats-new/0.2.11.md
- What's New 0.2.11: whats-new/0.2.11.md
- What's New 0.2.10: whats-new/0.2.10.md
- What's New 0.2.8: whats-new/0.2.8.md
- Roadmap: reference/feuille_de_route.md
Expand Down
14 changes: 13 additions & 1 deletion .github/workflows/publish-pypi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,26 @@ jobs:
contract = json.load(open(sys.argv[1], encoding="utf-8"))
if contract.get("status") != "OWNER_AUTHORIZED_SELECTED_PACKAGE_RELEASE":
raise SystemExit("The release contract is not Owner-authorized.")
if contract.get("publication_scope") != "SELECTED_DISTRIBUTION":
raise SystemExit("Only an explicit selected-distribution contract may use this workflow.")
if contract.get("package_version") != sys.argv[2][1:]:
raise SystemExit("The release contract version differs from the requested tag.")
if contract.get("release_tag") != sys.argv[2] or contract.get("source_sha") != sys.argv[3]:
raise SystemExit("The requested tag differs from the exact audited package source.")
if contract.get("g03_status") != "FAIL_PRESERVED" or contract.get("whole_repository_archive_cleared") is not False:
raise SystemExit("G03 must remain failed and the complete repository archive uncleared.")
if contract.get("wp14_status") != "HOLD_NOT_PROMOTED":
raise SystemExit("This release workflow does not authorize a WP14 status change.")
authorization = contract.get("authorization", {})
if authorization.get("whole_repository_archive_publication_allowed") is not False:
raise SystemExit("Selected distribution authorization must not permit a whole-repository archive.")
if authorization.get("selected_package_publication_allowed") is not True:
raise SystemExit("The selected distribution is not explicitly authorized.")
PY
python scripts/check_publication_metadata.py --root tagged-source --tag "$RELEASE_TAG"
python scripts/check_publication_metadata.py \
--root tagged-source \
--tag "$RELEASE_TAG" \
--phase PRE_PUBLICATION

quality:
name: Tagged release quality gate
Expand Down
8 changes: 3 additions & 5 deletions CITATION.cff
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
cff-version: 1.2.0
message: "If you use QF Solver, please cite the published software release."
message: "For the evolving project, use concept DOI 10.5281/zenodo.22697897. For exact-version reproducibility, use a published version DOI when assigned. This metadata identifies version 0.2.11 without asserting a release date or version DOI."
type: software
title: "QF Solver"
version: "0.2.10"
date-released: 2026-10-03
doi: "10.5281/zenodo.23106744"
version: "0.2.11"
license: "Apache-2.0"
authors:
- family-names: "Farinazzo"
given-names: "Quentin"
repository-code: "https://github.com/emptiesvoid-cloud/QF_solver"
url: "https://emptiesvoid-cloud.github.io/QF_solver/"

abstract: "Open-source white-box finite-element solver for verifiable structural mechanics and dynamics."
abstract: "Open-source Python finite-element solver for structural mechanics and dynamics, designed for inspectable formulations, engineering-method development, and reproducible numerical verification."

61 changes: 49 additions & 12 deletions PUBLIC_RELEASE_POLICY.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ do not rely on deleting a file in a later commit.

## Release Gate

Before promoting a full repository source archive or GitHub Release, run:
Before promoting a **whole-repository source archive** as a cleared distribution, run:

```powershell
python .\scripts\audit_public_release.py --output .\public_release_audit.json
Expand All @@ -73,11 +73,36 @@ is also excluded: only selected, reviewed V&V packages may be copied into a
future public release deliberately. These rules are safeguards, not substitutes
for review.

A source tag used solely to identify a separately audited PyPI candidate does
not pass this whole-repository gate by implication. GitHub may still offer an
automatic source archive for the tag; it must not be described or uploaded as
a cleared distribution while this gate fails. The separate PyPI decision and
its frozen selected-content checks are specified below.
### Selected distribution versus whole-repository archive

`SELECTED_DISTRIBUTION_CLEARANCE` and
`WHOLE_REPOSITORY_ARCHIVE_CLEARANCE` are separate decisions. A prospective,
Owner-authorized selected-release contract may authorize only its exact wheel,
sdist and checksum manifest when the selected-source/documentation audit,
package checks, artifact hashes and required release gates pass. This bounded
decision does not change a historical whole-repository G03 failure and does
not clear or authorize a complete repository archive.

A GitHub Release page may carry those exact selected assets when a separate
Owner authorization and the selected-release contract permit it. This is a
channel-specific authorization, independent of the PyPI decision. GitHub's
automatically generated `Source code (zip)` and `Source code (tar.gz)` assets
are platform-generated repository archives, not selected distribution assets.
When G03 is not cleared, they must not be called audited, qualified or cleared,
and they must not be uploaded to Zenodo as release artifacts. Authorization
for one publication channel does not implicitly authorize another channel.

A Zenodo version record for a selected distribution may contain only the exact
files named in its selected-release contract. It must not import or include a
full repository snapshot, GitHub-generated source archive or unselected
qualification archive unless whole-repository archive clearance is separately
granted.

A source tag used solely to identify a separately audited selected candidate
does not pass this whole-repository gate by implication. GitHub may still offer
an automatic source archive for the tag; it must not be described or uploaded
as a cleared distribution while this gate fails. Selected binary distribution
checks are independent and do not alter the whole-repository gate.

`audit_release_archive.py` uses worktree attributes by default to verify the
next prospective archive. Immediately before tagging, run it again with
Expand Down Expand Up @@ -188,9 +213,21 @@ alone is not.

The selected package must be built from the contract's exact tagged Git blobs,
not from the rest of the engineering checkout. Publish only those audited
wheel/sdist bytes. A PyPI-only decision never clears a failing whole-repository
source/archive/history audit and never authorizes a GitHub Release, an upload
of the repository archive to Zenodo, or a WP14 status change. Do not move an
existing tag to make corrected metadata appear retroactively in its source.
If the immutable tag's public metadata is inconsistent, prepare a new version
and tag after the corrections and a new frozen audit.
wheel/sdist bytes. A selected PyPI decision never clears a failing
whole-repository source/archive/history audit, authorizes an unselected
repository archive for Zenodo, or changes WP14. A GitHub Release requires its
own explicit Owner permission in the exact selected-release contract. Do not
move an existing tag to make corrected metadata appear retroactively in its
source. If immutable tagged metadata is inconsistent, stop and follow a
prospective, explicitly authorized correction sequence.

### Publication metadata phases

Before Zenodo publication, a frozen candidate may identify its version and
project concept DOI while leaving `date-released` absent and its version DOI
absent.
The prepublication metadata gate requires this state and rejects a reserved or
invented version DOI. After publication, a separate postpublication check
requires the factual release date, the resolving version DOI, matching public
citation metadata, and verified selected-asset hashes. A missing version DOI
is valid only in `PRE_PUBLICATION`; it fails the `POST_PUBLICATION` gate.
Loading
Loading