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
59 changes: 40 additions & 19 deletions .github/workflows/pypi-publish.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
name: Publish to PyPI (trusted publisher)

# Release policy: CI runs on v* tags first. Publish only after the tag CI is green.
# Dispatch from main and provide the immutable annotated release tag, for example:
# gh workflow run pypi-publish.yml --ref main -f release_tag=v0.25.2
# Drop-in 035 release policy:
# 1. Merge the owner-authorization unit to main and require exact-main CI.
# 2. Create and push the immutable annotated v0.26.0 tag.
# 3. Require tag CI to pass.
# 4. Dispatch this workflow from main with the exact tag:
# gh workflow run pypi-publish.yml --ref main -f release_tag=v0.26.0
# 5. Verify the public wheel, sdist, embedded companion asset, and clean reader
# route before committing the post-publication receipt.
on:
workflow_dispatch:
inputs:
release_tag:
description: "Annotated release tag to build and publish (for example, v0.25.2)"
description: "Annotated release tag to build and publish (exactly v0.26.0 for Drop-in 035)"
required: true
type: string

Expand All @@ -16,7 +21,7 @@ jobs:
environment: pypi
runs-on: ubuntu-latest
permissions:
id-token: write # needed for trusted publishing
id-token: write # required for trusted publishing
contents: read

steps:
Expand All @@ -29,19 +34,17 @@ jobs:

# actions/checkout can materialize a commit-shaped local tag ref when a
# workflow is dispatched against a tag. Re-fetch the named ref explicitly
# so the release gate sees the original annotated tag object from origin.
# so every release gate sees the original annotated tag object.
- name: Restore and verify exact annotated release tag
shell: bash
env:
RELEASE_TAG: ${{ inputs.release_tag }}
run: |
case "$RELEASE_TAG" in
v[0-9]*) ;;
*)
echo "Release tag must start with v followed by a version: $RELEASE_TAG"
exit 1
;;
esac
set -euo pipefail
if [ "$RELEASE_TAG" != "v0.26.0" ]; then
echo "Drop-in 035 authorizes exactly v0.26.0, not $RELEASE_TAG"
exit 1
fi

git fetch --force origin "refs/tags/${RELEASE_TAG}:refs/tags/${RELEASE_TAG}"

Expand All @@ -67,16 +70,34 @@ jobs:
with:
python-version: "3.10"

- name: Verify annotated release tag matches package version
run: python tools/check_release_tag.py
- name: Verify release tag, technical proof, and owner authorization
run: |
set -euo pipefail
python tools/check_release_tag.py
python tools/check_psych_design_release_proof.py --phase complete
python tools/check_psych_design_public_release.py --phase authorization

- name: Install build backend
- name: Install deterministic build backend
run: |
set -euo pipefail
python -m pip install --upgrade pip
python -m pip install build
python -m pip install "build>=1.2,<2" setuptools==80.9.0 wheel==0.45.1

- name: Build distributions
run: python -m build
- name: Build governed companion asset and distributions
shell: bash
run: |
set -euo pipefail
export SOURCE_DATE_EPOCH="$(git show -s --format=%ct HEAD)"
rm -rf build dist *.egg-info src/*.egg-info
python tools/build_psych_design_companion_asset.py
python -m build --no-isolation

- name: Verify exact public distribution identities before upload
run: |
set -euo pipefail
python tools/check_psych_design_public_release.py \
--phase distributions \
--dist-dir dist

- name: Publish to PyPI via trusted publisher
uses: pypa/gh-action-pypi-publish@release/v1
Expand Down
16 changes: 16 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ help:
@echo " psych-design-release-contract-verify - verify the advanced-book companion audit and command contract"
@echo " psych-design-release-proof-check - verify the Drop-in 034 candidate freeze and proof contract"
@echo " psych-design-release-proof-compare - compare committed Ubuntu and WSL proof receipts"
@echo " psych-design-public-release-check - verify Drop-in 035 owner authorization and source scope"
@echo " psych-design-public-release-distributions-check - verify built v0.26.0 wheel and sdist"
@echo " psych-design-public-release-public-check - verify the committed public PyPI receipt"
@echo " local-r-verify - run all governed R parity checks locally (never in GitHub Actions)"
@echo " release-verify - require an annotated v<version> tag matching pyproject.toml"
@echo " lint - ruff check"
Expand Down Expand Up @@ -555,6 +558,19 @@ psych-design-release-proof-compare:
--readiness $(PSYCH_DESIGN_RELEASE_EVIDENCE)/PSYCH_DESIGN_RELEASE_READINESS.json
$(PYTHON) tools/check_psych_design_release_proof.py --phase complete

# --- Psychological Statistics by Design owner-authorized public release ---
.PHONY: psych-design-public-release-check
psych-design-public-release-check:
$(PYTHON) tools/check_psych_design_public_release.py --phase authorization

.PHONY: psych-design-public-release-distributions-check
psych-design-public-release-distributions-check:
$(PYTHON) tools/check_psych_design_public_release.py --phase distributions --dist-dir dist

.PHONY: psych-design-public-release-public-check
psych-design-public-release-public-check:
$(PYTHON) tools/check_psych_design_public_release.py --phase public

# --- Quality gates ---
.PHONY: lint
lint:
Expand Down
31 changes: 18 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,31 +38,36 @@ python scripts/psych_ch10_problem_set.py
pytest -q
```

## Psychological Statistics by Design companion — v0.26.0 release candidate
## Psychological Statistics by Design companion — PyStatsV1 v0.26.0

The source tree now contains a **non-public release candidate** for
*Psychological Statistics by Design — Executable Companion v0.1*. It unifies
ten synthetic Student Well-Being and Learning studies behind one registry, ten
visible Python entry scripts, independent R implementations, verification
receipts, figure specifications, reviewer packets, and synthetic-safe adaptation
templates. PyStatsV1 remains the versioned bridge and launcher; it does not
choose a method, validate an instrument, authorize data, or establish causality.
PyStatsV1 v0.26.0 distributes *Psychological Statistics by Design — Executable
Companion v0.1*. It unifies ten synthetic Student Well-Being and Learning
studies behind one registry, ten visible Python entry scripts, independent R
implementations, verification receipts, figure specifications, reviewer
packets, and synthetic-safe adaptation templates. PyStatsV1 remains the
versioned bridge and launcher; it does not choose a method, validate an
instrument, authorize data, or establish causality.

The candidate interface is implemented for local and CI proof:
The verified public reader route is:

```bash
python -m pip install -e '.[psych-design]'
python tools/build_psych_design_companion_asset.py
python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install "pystatsv1[psych-design]==0.26.0"
pystatsv1 psych-design info
pystatsv1 psych-design init
cd psychological_statistics_by_design_companion_v0_1
pystatsv1 psych-design verify --dest .
python -m pip install -r requirements-psych-design-companion.txt
pystatsv1 psych-design doctor --dest .
make first-result # complete SWL-S02 Python/R V2 chain; requires Rscript
pystatsv1 psych-design verify --dest .
```

This is **not yet a PyPI or portal reader route**. Public release, portal
deployment, book binding, and real-data use remain unauthorized. The current
The governed reader proofs cover native Ubuntu and Windows 11 WSL2 with Ubuntu.
The companion remains synthetic-only. Portal deployment, book binding, and
real-data use remain separately governed and unauthorized by this release. The
public foundations companion continues to use the separately pinned Book 1
route below.

Expand Down
82 changes: 82 additions & 0 deletions docs/PYSTATSV1_DROPIN_035_OWNER_AUTHORIZED_V0260_PUBLIC_RELEASE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# PyStatsV1 Drop-in 035 — Owner-authorized v0.26.0 public release

## Purpose

Drop-in 035 converts the technically proven Psychological Statistics by Design
companion candidate into the exact public PyStatsV1 `0.26.0` distribution. The
unit authorizes only PyPI publication through the repository's existing trusted
publisher, then records and verifies the public wheel and source distribution.

## Approved baseline

- Approved parent main: `400a3d688fb3c341fd393aca715de6d941b7f1e6`
- Release-proof tag: `psych-design-companion-v0-1-release-proof`
- Frozen scientific candidate: `58d92f85b865cb657bf49c731fefc381970c8bda`
- Candidate tag: `psych-design-companion-v0-1-candidate`
- Package release: `pystatsv1==0.26.0`
- Companion release: `v0.1`
- Final annotated tag: `v0.26.0`

The complete Drop-in 034 Ubuntu/WSL proof, all 2,982 governed cross-platform
checks, the deterministic asset identity, and the closed non-PyPI gates remain
unchanged.

## Authorization boundary

The repository owner explicitly authorizes:

1. the exact annotated `v0.26.0` tag;
2. tag CI;
3. manual dispatch of `.github/workflows/pypi-publish.yml`;
4. trusted-publisher upload to PyPI;
5. public wheel and sdist verification; and
6. a post-publication evidence receipt.

The authorization does **not** authorize portal deployment, book binding,
real-data support, scientific changes, package-runtime changes, companion-asset
changes, or edits to the Drop-in 034 proof contract.

## Release gates

Before publication, the source checker requires:

- the complete Drop-in 034 technical-readiness receipt;
- the release-proof tag at the approved parent commit;
- the exact governed companion asset hash;
- the Drop-in 035 owner-authorization receipt;
- an exact allowlisted diff from the approved parent;
- the manual trusted-publisher workflow;
- an annotated tag matching `pyproject.toml`; and
- all portal, book, and real-data gates closed.

The trusted-publisher workflow rebuilds the governed asset, builds the wheel and
sdist with the pinned build backend, verifies both distributions, and publishes
only after all source and authorization checks pass.

## Public verification

After PyPI reports `0.26.0`, the local verifier:

- downloads the wheel and sdist from PyPI;
- verifies their PyPI-reported SHA-256 hashes;
- verifies package name and version metadata;
- verifies the exact embedded companion asset in both artifacts;
- creates a fresh Python 3.10 virtual environment;
- installs `pystatsv1[psych-design]==0.26.0` from the public PyPI index;
- runs `info`, `init`, `verify`, and `doctor`;
- runs the complete SWL-S02 `make first-result` Python/R verification chain;
- verifies the regenerated first-result files; and
- writes `PSYCH_DESIGN_PUBLIC_RELEASE.json` without persisting an absolute
reader workspace path.

## Final state

A successful unit records:

- public wheel filename, size, and SHA-256;
- public sdist filename, size, and SHA-256;
- exact embedded companion asset identity;
- release commit and annotated tag;
- exact tag-CI and trusted-publisher workflow run IDs;
- successful fresh-public-install command evidence; and
- `pypi_release_authorized: true` with portal, book, and real-data gates false.
24 changes: 14 additions & 10 deletions docs/source/release_notes.rst
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
Release notes
=============

v0.26.0 release candidate — Psychological Statistics by Design companion v0.1
---------------------------------------------------------------------------------
v0.26.0 — Psychological Statistics by Design companion v0.1
------------------------------------------------------------------

PyStatsV1 v0.26.0 is prepared as a non-public release candidate for the
synthetic-only *Psychological Statistics by Design* executable companion.
Publication to PyPI, portal deployment, and book binding remain separate,
explicitly unauthorized actions.
PyStatsV1 v0.26.0 publishes the synthetic-only *Psychological Statistics by
Design* executable companion after clean native-Ubuntu and Windows 11 WSL2
installed-wheel proofs, exact cross-platform scientific comparison, annotated
tag CI, trusted-publisher delivery, and public-artifact verification. Portal
deployment, book binding, and real-data support remain separate, explicitly
unauthorized actions.

Highlights
~~~~~~~~~~

* Adds ``pystatsv1 psych-design info``, ``init``, ``verify``,
``list-studies``, and ``doctor`` behind the release-candidate source tree.
``list-studies``, and ``doctor`` for the governed companion.
* Packages all ten SWL studies in one deterministic companion with a central
``STUDY_INDEX.json``, ten visible Python entry scripts, independent base-R
paths, V2/V3/V4 comparison policies, figures, APA source maps, matched
Expand All @@ -28,9 +30,11 @@ Highlights
source bundle.
* Includes synthetic-safe adaptation templates and states that adaptation is a
new research project rather than replacement of a CSV.
* Retains all public-release, PyPI, portal, book-binding, and real-data
authorization gates as false pending clean Ubuntu and WSL installed-wheel
proofs.
* Authorizes only the PyPI v0.26.0 publication path after the complete release
proof; portal binding, book binding, and real-data authorization remain false.
* Records the public wheel and source-distribution hashes after trusted
publishing and verifies a fresh exact-version install through the SWL-S02
first-result route.

v0.25.2 — Book 1 Companion v0.2.1 identity correction
----------------------------------------------------------------
Expand Down
83 changes: 83 additions & 0 deletions release_proofs/psych_design_v0_1/PYPI_RELEASE_AUTHORIZATION.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
{
"allowed_release_commit_paths": [
".github/workflows/pypi-publish.yml",
"Makefile",
"README.md",
"docs/PYSTATSV1_DROPIN_035_OWNER_AUTHORIZED_V0260_PUBLIC_RELEASE.md",
"docs/source/release_notes.rst",
"release_proofs/psych_design_v0_1/PYPI_RELEASE_AUTHORIZATION.json",
"release_proofs/psych_design_v0_1/evidence/PSYCH_DESIGN_PUBLIC_RELEASE.json",
"tests/test_psych_design_public_release.py",
"tests/test_psych_design_release_proof.py",
"tests/test_release_025_metadata.py",
"tools/check_psych_design_public_release.py",
"tools/check_psych_design_release_proof.py",
"tools/verify_pystatsv1_public_release.py"
],
"authorization": {
"authorized_on_local_date": "2026-07-30",
"authorized_scope": "Publish PyStatsV1 0.26.0 to PyPI through the existing trusted-publisher workflow and verify the public artifacts.",
"basis": "Explicit repository-owner instruction for PyStatsV1 Drop-in 035.",
"status": "explicitly_authorized"
},
"authorization_state": {
"book_binding_authorized": false,
"portal_release_authorized": false,
"pypi_release_authorized": true,
"real_data_authorized": false
},
"companion_identity": {
"asset_bytes": 136801,
"asset_manifest_sha256": "24f496631758a955a91d53193868b3c02ce9d62bb218fd59d3bb52ea9305e52f",
"asset_path": "src/pystatsv1/assets/psychological_statistics_by_design_companion_v0_1.zip",
"asset_sha256": "bd0932c1d126758f37fab180173d6b95b5e4c31bc654724251aa6eb6296243c1",
"companion_version": "v0.1",
"immutable_source_file_count": 151,
"study_index_sha256": "1c2525fa1ef4b720d758a32f5e3ad987264e8dfeb28f3967201efca575ef6df7"
},
"dropin": "035",
"protected_release_boundaries": {
"analysis_or_dataset_changes_allowed": false,
"book_or_portal_changes_allowed": false,
"companion_asset_changes_allowed": false,
"package_runtime_changes_allowed": false,
"proof_contract_changes_allowed": false,
"real_data_authorized": false
},
"public_artifact_policy": {
"expected_sdist_name": "pystatsv1-0.26.0.tar.gz",
"expected_wheel_name": "pystatsv1-0.26.0-py3-none-any.whl",
"fresh_public_install_required": true,
"public_hashes_recorded_after_publication": true,
"required_commands": [
"pystatsv1 psych-design info",
"pystatsv1 psych-design init",
"pystatsv1 psych-design verify --dest .",
"pystatsv1 psych-design doctor --dest .",
"make first-result",
"pystatsv1 psych-design verify --dest ."
],
"required_index": "https://pypi.org/simple",
"trusted_publisher_required": true
},
"release_identity": {
"approved_parent_commit": "400a3d688fb3c341fd393aca715de6d941b7f1e6",
"candidate_commit": "58d92f85b865cb657bf49c731fefc381970c8bda",
"candidate_tag": "psych-design-companion-v0-1-candidate",
"package_name": "pystatsv1",
"package_version": "0.26.0",
"proof_tag": "psych-design-companion-v0-1-release-proof",
"release_commit_policy": "The annotated v0.26.0 tag must resolve to the exact merged Drop-in 035 authorization commit whose complete diff from approved_parent_commit is restricted to allowed_release_commit_paths.",
"release_tag": "v0.26.0"
},
"required_prepublication_state": {
"candidate_implementation_passed": true,
"clean_ubuntu_proof_passed": true,
"clean_wsl_proof_passed": true,
"cross_platform_comparison_passed": true,
"dropin_034_readiness_gates_remain_closed": true,
"technical_release_ready": true
},
"schema_version": "pystatsv1-psych-design-pypi-release-authorization-v0.1",
"status": "owner_authorized_pending_publication"
}
Loading
Loading