diff --git a/.github/scripts/test_patch_0_1_2_python_publication_approval_request.py b/.github/scripts/test_patch_0_1_2_python_publication_approval_request.py new file mode 100644 index 0000000..e1f7e4d --- /dev/null +++ b/.github/scripts/test_patch_0_1_2_python_publication_approval_request.py @@ -0,0 +1,170 @@ +#!/usr/bin/env python3 +# +# Copyright 2026 The Ethos maintainers +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# + +from __future__ import annotations + +import re +import subprocess +import unittest +from pathlib import Path + +from makefile_guard import target_block + + +ROOT = Path(__file__).resolve().parents[2] +RECORD = ROOT / "docs/validation/patch-0-1-2-python-publication-approval-request-validation-2026-06-25.md" +VALIDATION_README = ROOT / "docs/validation/README.md" +PYPROJECT = ROOT / "pyproject.toml" +INIT = ROOT / "python/ethos_pdf/__init__.py" +MAKEFILE = ROOT / "Makefile" + +SOURCE_SHORT = "e431982" +SOURCE_COMMIT = "e431982cca2922d4cc59ddc7cacb9e72538b1cd0" +SOURCE_TREE = "f59ddd018d234eeee0ac77292b417f4acb892b4e" +PACKAGE = "ethos-pdf==0.1.2" +WHEEL = "ethos_pdf-0.1.2-py3-none-any.whl" +DETERMINISTIC_SHA256 = "6f17240954f1257ece3c762c820ad771ccb114353bfb699fe87f418a5ceb663c" +WHEEL_FILES = ( + "ethos_pdf/__init__.py", + "ethos_pdf/_cli.py", + "ethos_pdf-0.1.2.dist-info/METADATA", + "ethos_pdf-0.1.2.dist-info/RECORD", + "ethos_pdf-0.1.2.dist-info/WHEEL", + "ethos_pdf-0.1.2.dist-info/licenses/LICENSE", + "ethos_pdf-0.1.2.dist-info/licenses/NOTICE", + "ethos_pdf-0.1.2.dist-info/top_level.txt", +) +FORBIDDEN = ( + "pypi upload approved", + "pypi publication approved", + "python package is published", + "wheel is published", + "twine upload approved", + "python installation wording approved", + "production-ready", + "hosted surfaces approved", + "windows packaged artifacts approved", + "bundled pdfium approved", + "ethos-doc approved", + "ethos-rag approved", +) + + +def read(path: Path) -> str: + return path.read_text(encoding="utf-8") + + +def normalized(path: Path) -> str: + return re.sub(r"\s+", " ", read(path)) + + +def git(*args: str) -> str: + return subprocess.check_output( + ["git", *args], + cwd=ROOT, + encoding="utf-8", + stderr=subprocess.DEVNULL, + ).strip() + + +class Patch012PythonPublicationApprovalRequestTests(unittest.TestCase): + def test_request_record_is_source_bound_and_indexed(self) -> None: + record = normalized(RECORD) + readme = normalized(VALIDATION_README) + + self.assertIn(RECORD.name, readme) + self.assertIn("patch 0.1.2 Python PyPI publication approval request", readme) + self.assertIn(f"Validated source HEAD before this record: `{SOURCE_SHORT}`", read(RECORD)) + self.assertIn(f"Patch 0.1.2 Python publication approval request source commit: `{SOURCE_COMMIT}`", record) + self.assertIn(f"Patch 0.1.2 Python publication approval request source tree: `{SOURCE_TREE}`", record) + self.assertEqual(SOURCE_COMMIT, git("rev-parse", SOURCE_SHORT)) + self.assertEqual(SOURCE_TREE, git("rev-parse", f"{SOURCE_SHORT}^{{tree}}")) + + def test_request_names_exact_deterministic_wheel_candidate_and_metadata(self) -> None: + record = normalized(RECORD) + + for expected in ( + PACKAGE, + WHEEL, + DETERMINISTIC_SHA256, + "SOURCE_DATE_EPOCH=0", + "Name: `ethos-pdf`", + "Version: `0.1.2`", + "License-Expression: `Apache-2.0`", + "Requires-Python: `>=3.8`", + "Wheel-Version: `1.0`", + "Root-Is-Purelib: `true`", + "Tag: `py3-none-any`", + "member timestamps: `1980-01-01 00:00:00`", + "version `0.1.2`", + "EthosCli", + "EthosCommandError", + "Python `3.9.6`", + "build `1.4.4`", + ): + self.assertIn(expected, record) + for wheel_file in WHEEL_FILES: + self.assertIn(wheel_file, record) + + def test_request_requires_decision_and_keeps_upload_blocked(self) -> None: + raw = read(RECORD) + record = normalized(RECORD) + lower = record.lower() + + for expected in ( + "Manual action is required before any PyPI upload.", + "A decider must accept or reject this exact deterministic request packet.", + "This request record does not approve PyPI upload.", + "This request record does not upload any Python distribution.", + "This request record does not approve the deterministic wheel hash.", + "Actual PyPI upload remains blocked pending explicit decider approval.", + "Python public installation wording remains blocked pending PyPI availability closeout.", + "PDFium remains caller-provided through `ETHOS_PDFIUM_LIBRARY_PATH`.", + ): + self.assertIn(expected, record) + for forbidden in FORBIDDEN: + self.assertNotIn(forbidden, lower) + for private in ( + "/" + "Users/", + "/" + "tmp", + "/" + "private/tmp", + "/" + "private/var", + "/" + "var/folders", + "saumil" + "diwaker", + "Desktop/" + "Stuff", + "project/repo/" + "ethos", + ): + self.assertNotIn(private, raw) + + def test_source_metadata_keeps_current_python_surface_shape(self) -> None: + pyproject = read(PYPROJECT) + init = read(INIT) + + self.assertIn('name = "ethos-pdf"', pyproject) + self.assertIn('version = "0.1.2"', pyproject) + self.assertIn('requires-python = ">=3.8"', pyproject) + self.assertIn('license = "Apache-2.0"', pyproject) + self.assertIn('readme = "python/README.md"', pyproject) + self.assertIn('__version__ = "0.1.2"', init) + self.assertIn('"EthosCli"', init) + self.assertIn('"EthosCommandError"', init) + + def test_release_candidate_prep_runs_request_guard_after_rust_wording(self) -> None: + makefile = read(MAKEFILE) + rust_wording_guard = "$(PYTHON) .github/scripts/test_patch_0_1_2_rust_public_install_wording_closeout.py" + guard = "$(PYTHON) .github/scripts/test_patch_0_1_2_python_publication_approval_request.py" + first_public_guard = "$(PYTHON) .github/scripts/test_first_public_release_artifact_evidence.py" + block = target_block("release-candidate-prep") + + self.assertIn(guard, block) + self.assertEqual(1, makefile.count(guard)) + self.assertLess(block.index(rust_wording_guard), block.index(guard)) + self.assertLess(block.index(guard), block.index(first_public_guard)) + + +if __name__ == "__main__": + unittest.main() diff --git a/.github/scripts/test_release_candidate_prep.py b/.github/scripts/test_release_candidate_prep.py index 9d86bbd..bccdbb2 100644 --- a/.github/scripts/test_release_candidate_prep.py +++ b/.github/scripts/test_release_candidate_prep.py @@ -73,6 +73,7 @@ "$(PYTHON) .github/scripts/test_patch_0_1_2_crates_publication_approval_decision.py", "$(PYTHON) .github/scripts/test_patch_0_1_2_crates_publication_closeout.py", "$(PYTHON) .github/scripts/test_patch_0_1_2_rust_public_install_wording_closeout.py", + "$(PYTHON) .github/scripts/test_patch_0_1_2_python_publication_approval_request.py", "$(PYTHON) .github/scripts/test_first_public_release_artifact_evidence.py", "$(PYTHON) .github/scripts/test_first_public_release_final_decider.py", "$(PYTHON) .github/scripts/test_first_public_release_linux_x64_artifact_evidence.py", diff --git a/CHANGELOG.md b/CHANGELOG.md index 71b32f4..2691c56 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Unreleased +- boundary-exception: request decider review for exact deterministic patch `0.1.2` Python PyPI wheel publication while keeping PyPI upload, Python public install wording, hosted, production, Windows, bundled PDFium, benchmark, `ethos-doc`, and `ethos-rag` surfaces blocked. - boundary-exception: close patch `0.1.2` Rust public install wording for published crates `ethos-doc-core`, `ethos-verify`, and `ethos-pdf` while keeping PyPI publication, hosted, production, Windows, bundled PDFium, benchmark, `ethos-doc`, and `ethos-rag` surfaces blocked. - boundary-exception: close patch `0.1.2` crates.io publication for Rust crates `ethos-doc-core`, `ethos-verify`, and `ethos-pdf` while keeping Rust public install wording, PyPI publication, hosted, production, Windows, bundled PDFium, benchmark, `ethos-doc`, and `ethos-rag` surfaces blocked. - boundary-exception: record decider approval for bounded later crates.io publication of patch `0.1.2` Rust crates `ethos-doc-core`, `ethos-verify`, and `ethos-pdf` while keeping actual operator publication, package tag creation, Rust public install wording, PyPI publication, hosted, production, Windows, bundled PDFium, benchmark, `ethos-doc`, and `ethos-rag` surfaces blocked. diff --git a/Makefile b/Makefile index 29671ca..1839b37 100644 --- a/Makefile +++ b/Makefile @@ -324,6 +324,7 @@ release-candidate-prep: $(PYTHON) .github/scripts/test_patch_0_1_2_crates_publication_approval_decision.py $(PYTHON) .github/scripts/test_patch_0_1_2_crates_publication_closeout.py $(PYTHON) .github/scripts/test_patch_0_1_2_rust_public_install_wording_closeout.py + $(PYTHON) .github/scripts/test_patch_0_1_2_python_publication_approval_request.py $(PYTHON) .github/scripts/test_first_public_release_artifact_evidence.py $(PYTHON) .github/scripts/test_first_public_release_final_decider.py $(PYTHON) .github/scripts/test_first_public_release_linux_x64_artifact_evidence.py diff --git a/docs/execution-status.md b/docs/execution-status.md index 5ad7895..fe4114c 100644 --- a/docs/execution-status.md +++ b/docs/execution-status.md @@ -73,6 +73,14 @@ The public README and public boundary inventory now point Rust crate installatio `ethos-pdf==0.1.1` until separate PyPI `0.1.2` approval, operator publication, and closeout records pass. +Patch `0.1.2` Python PyPI publication approval request is recorded in +`docs/validation/patch-0-1-2-python-publication-approval-request-validation-2026-06-25.md`. It +binds the exact deterministic `ethos-pdf==0.1.2` wheel candidate, source commit, source tree, +metadata, SHA256, and local install/import smoke for decider review only. PyPI upload, Python +public installation wording, package tag creation, hosted surfaces, production positioning, Windows +packaged artifacts, bundled project-maintained PDFium builds, `ethos-doc`, `ethos-rag`, and public +benchmark claims remain blocked. + Public approval lane blocker prep is recorded in `docs/milestone-e-public-approval-lane-blockers.json` and schema-bound by `schemas/ethos-milestone-e-public-approval-lane-blockers.schema.json`. This public approval lane diff --git a/docs/public-release-checklist.md b/docs/public-release-checklist.md index 12b2f72..90d6ab4 100644 --- a/docs/public-release-checklist.md +++ b/docs/public-release-checklist.md @@ -151,6 +151,14 @@ remain blocked, production positioning remains blocked, Windows packaged artifac bundled project-maintained PDFium builds remain blocked, `ethos-doc` remains blocked, `ethos-rag` remains blocked, and public benchmark claims remain blocked. +Patch `0.1.2` Python PyPI publication approval request is recorded in +`docs/validation/patch-0-1-2-python-publication-approval-request-validation-2026-06-25.md`. It +requests decider review for the exact deterministic `ethos-pdf==0.1.2` wheel candidate only. PyPI +upload remains blocked, Python public installation wording remains blocked, hosted surfaces remain +blocked, production positioning remains blocked, Windows packaged artifacts remain blocked, bundled +project-maintained PDFium builds remain blocked, `ethos-doc` remains blocked, `ethos-rag` remains +blocked, and public benchmark claims remain blocked. + ## Required Before Public Push - Package-name and trademark decision is closed by accepted ADR-0006 in diff --git a/docs/validation/README.md b/docs/validation/README.md index 78ca7f2..ede883b 100644 --- a/docs/validation/README.md +++ b/docs/validation/README.md @@ -738,6 +738,11 @@ recording the exact current-main source candidate and required follow-up evidenc for `ethos-doc-core`, `ethos-verify`, and `ethos-pdf` at `0.1.2`; PyPI publication, hosted, production, Windows, bundled PDFium, benchmark, `ethos-doc`, and `ethos-rag` surfaces remain blocked until separate closeout or approval records pass. +- `patch-0-1-2-python-publication-approval-request-validation-2026-06-25.md` - patch 0.1.2 + Python PyPI publication approval request validation binds the exact deterministic + `ethos-pdf==0.1.2` wheel candidate, source commit, source tree, metadata, SHA256, and local + install/import smoke for decider review; PyPI upload and Python public installation wording + remain blocked until separate decision, operator, and closeout records pass. - `milestone-e-validation-command-index-validation-2026-06-20.md` - internal Milestone E validation-command index validation passed through command-alignment checks, schema enum checks, row-record checks, public-surface posture checks, `make milestone-e-prep`, and diff hygiene; the diff --git a/docs/validation/patch-0-1-2-python-publication-approval-request-validation-2026-06-25.md b/docs/validation/patch-0-1-2-python-publication-approval-request-validation-2026-06-25.md new file mode 100644 index 0000000..b22e4f8 --- /dev/null +++ b/docs/validation/patch-0-1-2-python-publication-approval-request-validation-2026-06-25.md @@ -0,0 +1,145 @@ +# Patch 0.1.2 Python PyPI Publication Approval Request Validation - 2026-06-25 + +Validated source HEAD before this record: `e431982`. + +Patch 0.1.2 Python publication approval request source commit: +`e431982cca2922d4cc59ddc7cacb9e72538b1cd0`. + +Patch 0.1.2 Python publication approval request source tree: +`f59ddd018d234eeee0ac77292b417f4acb892b4e`. + +Status: **patch 0.1.2 Python PyPI publication approval request recorded; PyPI upload remains blocked** + +This record requests decider review for publishing exactly the deterministic patch `0.1.2` Ethos +Python wheel to PyPI. It does not approve or perform PyPI upload, create package tags, change public +Python installation wording, approve hosted surfaces, approve production positioning, approve +Windows packaged artifacts, approve bundled project-maintained PDFium builds, approve `ethos-doc`, +approve `ethos-rag`, or approve public benchmark reports or claims. + +## Subject + +- Repository: `docushell/ethos` +- Lane: Python PyPI deterministic wheel publication +- Candidate package: `ethos-pdf==0.1.2` +- Import package: `ethos_pdf` +- Candidate wheel: `ethos_pdf-0.1.2-py3-none-any.whl` +- Deterministic build input: `SOURCE_DATE_EPOCH=0` +- Deterministic candidate wheel SHA256: + `6f17240954f1257ece3c762c820ad771ccb114353bfb699fe87f418a5ceb663c` + +## Exact Request Fields + +- Decision requested: approve exact deterministic patch `0.1.2` Python PyPI wheel publication + preparation inputs for later operator execution. +- Approver requested: `docushell-admin` acting as decider. +- Date requested: 2026-06-25. +- Exact package requested: `ethos-pdf==0.1.2`. +- Exact distribution requested: `ethos_pdf-0.1.2-py3-none-any.whl` only. +- Exact deterministic build input requested: `SOURCE_DATE_EPOCH=0`. +- Exact source commit requested: `e431982cca2922d4cc59ddc7cacb9e72538b1cd0`. +- Exact source tree requested: `f59ddd018d234eeee0ac77292b417f4acb892b4e`. +- Exact deterministic wheel SHA256 requested: + `6f17240954f1257ece3c762c820ad771ccb114353bfb699fe87f418a5ceb663c`. + +## Wheel Metadata Bound To This Request + +- Name: `ethos-pdf` +- Version: `0.1.2` +- Summary: `Python wrapper for the Ethos document evidence CLI.` +- License-Expression: `Apache-2.0` +- Requires-Python: `>=3.8` +- Wheel-Version: `1.0` +- Root-Is-Purelib: `true` +- Tag: `py3-none-any` +- Build Python: Python `3.9.6` +- Build frontend: build `1.4.4` +- Wheel member timestamps: `1980-01-01 00:00:00` + +Wheel file list: + +- `ethos_pdf/__init__.py` +- `ethos_pdf/_cli.py` +- `ethos_pdf-0.1.2.dist-info/METADATA` +- `ethos_pdf-0.1.2.dist-info/RECORD` +- `ethos_pdf-0.1.2.dist-info/WHEEL` +- `ethos_pdf-0.1.2.dist-info/licenses/LICENSE` +- `ethos_pdf-0.1.2.dist-info/licenses/NOTICE` +- `ethos_pdf-0.1.2.dist-info/top_level.txt` + +## Local Evidence Bound To This Request + +- `SOURCE_DATE_EPOCH=0 python3 -m build --wheel --outdir ` built + `ethos_pdf-0.1.2-py3-none-any.whl` twice in isolated build environments. +- Both deterministic builds produced SHA256 + `6f17240954f1257ece3c762c820ad771ccb114353bfb699fe87f418a5ceb663c`. +- Wheel metadata inspection reported `Name: ethos-pdf`, `Version: 0.1.2`, + `License-Expression: Apache-2.0`, `Requires-Python: >=3.8`, and `Tag: py3-none-any`. +- Wheel ZIP member timestamp inspection reported `1980-01-01 00:00:00` for every member. +- Local install smoke used `python3 -m pip install --no-deps --force-reinstall `. +- Import smoke reported version `0.1.2`. +- Import smoke resolved `EthosCli`. +- Import smoke resolved `EthosCommandError`. + +## Manual Decision Gate + +Manual action is required before any PyPI upload. A decider must accept or reject this exact +deterministic request packet. Only after that decision record passes may an operator upload the +exact deterministic wheel named above with the exact SHA256 named above. + +This request does not select an sdist, alternate wheel, additional package name, additional Python +module, or broad package-publication class. If any artifact filename, version, hash, source commit, +source tree, metadata, build input, public wording, or blocker set changes, this request must be +replaced by a new evidence record and a new decider review. + +## Non-Approvals + +- This request record does not approve PyPI upload. +- This request record does not upload any Python distribution. +- This request record does not approve the deterministic wheel hash. +- This request record does not approve an sdist. +- This request record does not approve another wheel. +- This request record does not approve package tags. +- This request record does not approve Python public installation wording. +- This request record does not approve hosted surfaces. +- This request record does not approve production positioning. +- This request record does not approve Windows packaged artifacts. +- This request record does not approve bundled project-maintained PDFium builds. +- This request record does not approve public benchmark reports. +- This request record does not approve public benchmark claims. +- This request record does not approve `ethos-doc`. +- This request record does not approve `ethos-rag`. + +## Retained Blockers + +- Actual PyPI upload remains blocked pending explicit decider approval. +- Python public installation wording remains blocked pending PyPI availability closeout. +- Package tag creation remains blocked pending explicit decider approval. +- Hosted surfaces remain blocked. +- Production positioning remains blocked. +- Public benchmark reports remain blocked. +- Public benchmark claims remain blocked. +- Windows packaged artifacts remain blocked. +- Bundled project-maintained PDFium builds remain blocked. +- `ethos-doc` remains blocked. +- `ethos-rag` remains blocked. +- PDFium remains caller-provided through `ETHOS_PDFIUM_LIBRARY_PATH`. + +## Commands + +```sh +SOURCE_DATE_EPOCH=0 python3 -m build --wheel --outdir +shasum -a 256 /ethos_pdf-0.1.2-py3-none-any.whl +python3 .github/scripts/test_patch_0_1_2_python_publication_approval_request.py +python3 .github/scripts/test_python_public_api_policy.py +PYTHONPATH=python python3 -m unittest discover -s python/tests +make release-candidate-prep PYTHON=python3 +git diff --check +``` + +## Result + +```text +patch 0.1.2 Python PyPI publication approval request recorded +Exact deterministic wheel, build input, source binding, metadata, SHA256, local install/import smoke, and retained blockers were recorded +PyPI upload remains blocked pending explicit decider approval and later operator action +```