From f435d25d794c6e1bc012762a2c42f8dc90015b0b Mon Sep 17 00:00:00 2001 From: docushell-admin Date: Wed, 1 Jul 2026 17:27:33 +0530 Subject: [PATCH] Record v0.3 package evidence Signed-off-by: docushell-admin --- ...ackage_publication_candidate_activation.py | 27 +- .../test_v0_3_0_package_build_evidence.py | 363 ++++++++++++++++++ CHANGELOG.md | 4 + Makefile | 1 + docs/execution-status.md | 8 + docs/public-release-checklist.md | 8 + docs/validation/README.md | 8 + ...ge-build-evidence-validation-2026-07-01.md | 175 +++++++++ 8 files changed, 583 insertions(+), 11 deletions(-) create mode 100644 .github/scripts/test_v0_3_0_package_build_evidence.py create mode 100644 docs/validation/v0-3-0-package-build-evidence-validation-2026-07-01.md diff --git a/.github/scripts/package_publication_candidate_activation.py b/.github/scripts/package_publication_candidate_activation.py index 69349da..d7fa359 100644 --- a/.github/scripts/package_publication_candidate_activation.py +++ b/.github/scripts/package_publication_candidate_activation.py @@ -18,6 +18,7 @@ from __future__ import annotations import argparse +import gzip import hashlib import io import json @@ -327,6 +328,7 @@ def add_archive_file(archive: tarfile.TarFile, source: Path, arcname: str) -> No info.gid = 0 info.uname = "" info.gname = "" + info.mtime = 0 with source.open("rb") as handle: archive.addfile(info, handle) @@ -340,6 +342,7 @@ def add_archive_text(archive: tarfile.TarFile, text: str, arcname: str) -> None: info.gid = 0 info.uname = "" info.gname = "" + info.mtime = 0 archive.addfile(info, fileobj=io.BytesIO(data)) @@ -358,17 +361,19 @@ def assemble_candidate_package( crate_path.parent.mkdir(parents=True, exist_ok=True) root = f"{package}-{VERSION}" - with tarfile.open(crate_path, "w:gz") as archive: - for rel in file_list: - arcname = f"{root}/{rel}" - if rel == "Cargo.toml": - add_archive_text(archive, generated_manifest(package), arcname) - elif rel == "Cargo.toml.orig": - add_archive_file(archive, package_dir / "Cargo.toml", arcname) - elif rel == "Cargo.lock": - add_archive_file(archive, workspace / "Cargo.lock", arcname) - else: - add_archive_file(archive, package_dir / rel, arcname) + with crate_path.open("wb") as raw: + with gzip.GzipFile(filename="", mode="wb", fileobj=raw, mtime=0) as compressed: + with tarfile.open(fileobj=compressed, mode="w") as archive: + for rel in file_list: + arcname = f"{root}/{rel}" + if rel == "Cargo.toml": + add_archive_text(archive, generated_manifest(package), arcname) + elif rel == "Cargo.toml.orig": + add_archive_file(archive, package_dir / "Cargo.toml", arcname) + elif rel == "Cargo.lock": + add_archive_file(archive, workspace / "Cargo.lock", arcname) + else: + add_archive_file(archive, package_dir / rel, arcname) manifest = read_packaged_manifest(crate_path, package) record_command(f"assemble candidate package artifact -p {package}", commands, "\n".join(file_list)) diff --git a/.github/scripts/test_v0_3_0_package_build_evidence.py b/.github/scripts/test_v0_3_0_package_build_evidence.py new file mode 100644 index 0000000..d57f307 --- /dev/null +++ b/.github/scripts/test_v0_3_0_package_build_evidence.py @@ -0,0 +1,363 @@ +#!/usr/bin/env python3 +# +# Copyright 2026 The Ethos maintainers +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# + +from __future__ import annotations + +import hashlib +import json +import os +import re +import shutil +import subprocess +import sys +import tempfile +import unittest +import zipfile +from pathlib import Path + +from makefile_guard import target_block +from validation_record_source import assert_record_source_binding + + +ROOT = Path(__file__).resolve().parents[2] +SCRIPT = ROOT / ".github/scripts/package_publication_candidate_activation.py" +RECORD = ROOT / "docs/validation/v0-3-0-package-build-evidence-validation-2026-07-01.md" +VALIDATION_README = ROOT / "docs/validation/README.md" +EXECUTION_STATUS = ROOT / "docs/execution-status.md" +PUBLIC_RELEASE_CHECKLIST = ROOT / "docs/public-release-checklist.md" +MAKEFILE = ROOT / "Makefile" +PYPROJECT = ROOT / "pyproject.toml" +PY_INIT = ROOT / "python/ethos_pdf/__init__.py" +NPM_PACKAGE = ROOT / "packages/npm/ethos-pdf/package.json" + +SOURCE_SHORT = "4b6d219" +SOURCE_COMMIT = "4b6d219df1757b6e4728c16c8023bee5c8cf8962" +SOURCE_TREE = "2920f830f92f8290c2bf4cc661874c2641499688" +VERSION = "0.3.0" +WHEEL = "ethos_pdf-0.3.0-py3-none-any.whl" +WHEEL_SHA256 = "9eb106deafcd1d9717e5e7b67dc9413180421aba25a5257266352d09540b3265" +EXPECTED_CRATES = { + "ethos-doc-core": ( + "ethos-doc-core-0.3.0.crate", + "7ba41a2ae299a53a4677153beaaec5ed486a07b5da08b2ef13974b9a0be141cb", + ), + "ethos-verify": ( + "ethos-verify-0.3.0.crate", + "00f001455ca207e65aaf464551d3ba05945cda0b06e9e1036f49ac587accbb95", + ), + "ethos-pdf": ( + "ethos-pdf-0.3.0.crate", + "c2f4f2ccb6de6e54cd3257597cd28e7f6dec2a6d22befbd230d2c4cf31931cfd", + ), +} +EXPECTED_WHEEL_FILES = ( + "ethos_pdf/__init__.py", + "ethos_pdf/_cli.py", + "ethos_pdf-0.3.0.dist-info/METADATA", + "ethos_pdf-0.3.0.dist-info/RECORD", + "ethos_pdf-0.3.0.dist-info/WHEEL", + "ethos_pdf-0.3.0.dist-info/licenses/LICENSE", + "ethos_pdf-0.3.0.dist-info/licenses/NOTICE", + "ethos_pdf-0.3.0.dist-info/top_level.txt", +) +FORBIDDEN = ( + "pypi upload approved", + "pypi publication approved", + "crates.io publication approved", + "npm publication approved", + "github release publication approved", + "public installation approved", + "public install wording approved", + "installable 0.3.0 wording approved", + "doc shell integration approved", + "docushell integration approved", + "production-ready", + "hosted surfaces approved", + "windows packaged artifacts approved", + "bundled pdfium approved", + "public benchmark claims approved", +) +PRIVATE_PATH_MARKERS = ( + "/" + "Users/", + "/" + "private/tmp", + "/" + "private/var", + "/" + "var/folders", + "saumil" + "diwaker", + "Desktop/" + "Stuff", + "project/repo/" + "ethos", +) + + +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 run(command: list[str], cwd: Path, env: dict[str, str] | None = None) -> subprocess.CompletedProcess[str]: + return subprocess.run( + command, + cwd=cwd, + env=env, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, + check=False, + ) + + +def sha256(path: Path) -> str: + digest = hashlib.sha256() + with path.open("rb") as handle: + for chunk in iter(lambda: handle.read(1024 * 1024), b""): + digest.update(chunk) + return digest.hexdigest() + + +def run_candidate_activation() -> dict: + result = run(["python3", str(SCRIPT), "--json"], ROOT) + if result.returncode != 0: + raise AssertionError( + "candidate activation script failed\n" + f"stdout:\n{result.stdout}\n" + f"stderr:\n{result.stderr}" + ) + return json.loads(result.stdout) + + +def should_ignore(_: str, names: list[str]) -> set[str]: + ignored = { + ".git", + "target", + "build", + "__pycache__", + ".pytest_cache", + ".mypy_cache", + "ethos_pdf.egg-info", + } + return {name for name in names if name in ignored} + + +def build_python_wheel() -> dict[str, object]: + with tempfile.TemporaryDirectory(prefix="ethos-v0-3-python-wheel-") as temp: + workspace = Path(temp) / "ethos" + out_dir = Path(temp) / "dist" + install_dir = Path(temp) / "install" + shutil.copytree(ROOT, workspace, ignore=should_ignore) + + env = dict(os.environ) + env["SOURCE_DATE_EPOCH"] = "0" + build = run( + [ + sys.executable, + "-m", + "build", + "--wheel", + "--outdir", + str(out_dir), + ], + workspace, + env=env, + ) + if build.returncode != 0: + raise AssertionError( + "python wheel build failed\n" + f"stdout:\n{build.stdout}\n" + f"stderr:\n{build.stderr}" + ) + + wheel = out_dir / WHEEL + if not wheel.is_file(): + raise AssertionError(f"missing expected wheel: {WHEEL}") + + install = run( + [ + sys.executable, + "-m", + "pip", + "install", + "--no-deps", + "--force-reinstall", + "--target", + str(install_dir), + str(wheel), + ], + workspace, + ) + if install.returncode != 0: + raise AssertionError( + "python wheel install smoke failed\n" + f"stdout:\n{install.stdout}\n" + f"stderr:\n{install.stderr}" + ) + + smoke_env = dict(os.environ) + smoke_env["PYTHONPATH"] = str(install_dir) + smoke = run( + [ + sys.executable, + "-c", + ( + "import ethos_pdf; " + "from ethos_pdf import EthosCli, proof_summary, app_answer_release_decision; " + "print(ethos_pdf.__version__); " + "print(EthosCli.__name__); " + "print(callable(proof_summary)); " + "print(callable(app_answer_release_decision)); " + "summary = {" + "'proof_status': 'verified'," + "'request_certified': True," + "'reusable_grounded_check_ids': ['v0001']," + "'needs_review_check_ids': []," + "'proof_limitations': []" + "}; " + "decision = app_answer_release_decision(" + "'What was revenue?'," + "summary," + "[{" + "'id': 'claim-revenue'," + "'text': 'Revenue was $12.4M.'," + "'check_ids': ['v0001']," + "'question_relevance': 'direct_answer'," + "'claim_type': 'source_fact'" + "}]" + "); " + "print(decision['app_status']); " + "print(decision['final_answer_claim_ids'][0])" + ), + ], + workspace, + env=smoke_env, + ) + if smoke.returncode != 0: + raise AssertionError( + "python wheel import/helper smoke failed\n" + f"stdout:\n{smoke.stdout}\n" + f"stderr:\n{smoke.stderr}" + ) + + with zipfile.ZipFile(wheel) as archive: + files = sorted(archive.namelist()) + metadata = archive.read("ethos_pdf-0.3.0.dist-info/METADATA").decode("utf-8") + wheel_metadata = archive.read("ethos_pdf-0.3.0.dist-info/WHEEL").decode("utf-8") + + return { + "wheel": wheel.name, + "sha256": sha256(wheel), + "files": files, + "metadata": metadata, + "wheel_metadata": wheel_metadata, + "smoke_stdout": smoke.stdout.strip().splitlines(), + } + + +class V030PackageBuildEvidenceTests(unittest.TestCase): + @classmethod + def setUpClass(cls) -> None: + cls.candidate = run_candidate_activation() + cls.wheel = build_python_wheel() + + def test_record_is_source_bound_and_indexed(self) -> None: + raw = read(RECORD) + record = normalized(RECORD) + + assert_record_source_binding( + self, + root=ROOT, + raw_record=raw, + normalized_record=record, + validated_head=SOURCE_SHORT, + source_label="v0.3.0 package/build evidence", + source_commit=SOURCE_COMMIT, + source_tree=SOURCE_TREE, + ) + for path in (VALIDATION_README, EXECUTION_STATUS, PUBLIC_RELEASE_CHECKLIST): + text = normalized(path) + self.assertIn(RECORD.name, text, str(path)) + self.assertIn("v0.3.0 package/build evidence", text.lower(), str(path)) + self.assertIn("installable `0.3.0` wording remains blocked", text.lower(), str(path)) + + def test_rust_candidate_artifacts_are_0_3_0_and_registry_equivalent(self) -> None: + candidate = self.candidate + artifacts = {artifact["package"]: artifact for artifact in candidate["artifacts"]} + + self.assertEqual("pass", candidate["status"]) + self.assertEqual(VERSION, candidate["candidate_version"]) + self.assertEqual(["ethos-doc-core", "ethos-verify", "ethos-pdf"], candidate["candidate_packages"]) + self.assertEqual("pass", candidate["registry_equivalent_consumer_check"]) + self.assertFalse(candidate["package_publication_approved"]) + self.assertFalse(candidate["public_installation_approved"]) + self.assertEqual(set(EXPECTED_CRATES), set(artifacts)) + for package, (crate_file, crate_hash) in EXPECTED_CRATES.items(): + self.assertEqual(crate_file, artifacts[package]["crate_file"]) + self.assertEqual(crate_hash, artifacts[package]["sha256"]) + + def test_python_wheel_candidate_is_0_3_0_and_helper_smoke_passes(self) -> None: + wheel = self.wheel + + self.assertEqual(WHEEL, wheel["wheel"]) + self.assertEqual(WHEEL_SHA256, wheel["sha256"]) + for expected in EXPECTED_WHEEL_FILES: + self.assertIn(expected, wheel["files"]) + self.assertIn("Name: ethos-pdf", str(wheel["metadata"])) + self.assertIn("Version: 0.3.0", str(wheel["metadata"])) + self.assertIn("Requires-Python: >=3.8", str(wheel["metadata"])) + self.assertIn("License-Expression: Apache-2.0", str(wheel["metadata"])) + self.assertIn("Wheel-Version: 1.0", str(wheel["wheel_metadata"])) + self.assertIn("Root-Is-Purelib: true", str(wheel["wheel_metadata"])) + self.assertIn("Tag: py3-none-any", str(wheel["wheel_metadata"])) + self.assertEqual( + ["0.3.0", "EthosCli", "True", "True", "certified", "claim-revenue"], + wheel["smoke_stdout"], + ) + + def test_source_metadata_and_public_install_baseline_remain_split(self) -> None: + self.assertIn('version = "0.3.0"', read(PYPROJECT)) + self.assertIn('__version__ = "0.3.0"', read(PY_INIT)) + self.assertEqual("0.2.1", json.loads(read(NPM_PACKAGE))["version"]) + + def test_record_keeps_publication_artifact_npm_and_docushell_boundaries_blocked(self) -> None: + raw = read(RECORD) + record = normalized(RECORD) + lower = record.lower() + + for expected in ( + WHEEL_SHA256, + "ethos-doc-core-0.3.0.crate", + "ethos-verify-0.3.0.crate", + "ethos-pdf-0.3.0.crate", + "This record does not approve `cargo publish`.", + "This record does not approve PyPI upload.", + "This record does not approve `npm publish`.", + "This record does not approve GitHub Release artifact publication.", + "This record does not approve installable `0.3.0` public wording.", + "This record does not approve DocuShell integration.", + "CLI artifact evidence remains out of scope for this record.", + "npm package evidence remains out of scope for this record.", + ): + self.assertIn(expected, record) + for forbidden in FORBIDDEN: + self.assertNotIn(forbidden, lower) + for marker in PRIVATE_PATH_MARKERS: + self.assertNotIn(marker, raw) + + def test_v0_3_release_prep_runs_package_evidence_guard_before_claims(self) -> None: + block = target_block("v0-3-release-prep") + activation_guard = "$(PYTHON) .github/scripts/test_v0_3_0_version_activation.py" + evidence_guard = "$(PYTHON) .github/scripts/test_v0_3_0_package_build_evidence.py" + claims_guard = "$(PYTHON) .github/scripts/claims_gate.py" + + self.assertIn(evidence_guard, block) + self.assertEqual(1, block.count(evidence_guard)) + self.assertLess(block.index(activation_guard), block.index(evidence_guard)) + self.assertLess(block.index(evidence_guard), block.index(claims_guard)) + + +if __name__ == "__main__": + unittest.main() diff --git a/CHANGELOG.md b/CHANGELOG.md index 86d5979..83c251b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +- boundary-exception: record v0.3.0 Rust package candidate and Python wheel evidence while keeping + `cargo publish`, PyPI upload, npm publish, GitHub Release artifact publication, release/package + tags, installable `0.3.0` wording, npm alignment, hosted, production, Windows, bundled PDFium, + benchmark, `ethos-doc`, `ethos-rag`, and DocuShell integration blocked. - boundary-exception: harden v0.3.0 release-candidate CI guards and document the current release workflow artifact smoke pin while keeping `cargo publish`, PyPI upload, npm publish, GitHub Release artifact publication, release/package tags, installable `0.3.0` wording, hosted, diff --git a/Makefile b/Makefile index b1e89e6..d4545ed 100644 --- a/Makefile +++ b/Makefile @@ -91,6 +91,7 @@ v0-3-release-prep: $(PYTHON) .github/scripts/test_v0_3_0_release_approval_decision.py $(PYTHON) .github/scripts/test_v0_3_0_version_activation.py $(PYTHON) .github/scripts/test_validation_record_source.py + $(PYTHON) .github/scripts/test_v0_3_0_package_build_evidence.py $(PYTHON) .github/scripts/test_public_surface_posture.py $(PYTHON) .github/scripts/claims_gate.py $(PYTHON) .github/scripts/public_boundary_claims_gate.py diff --git a/docs/execution-status.md b/docs/execution-status.md index 4463060..4d50130 100644 --- a/docs/execution-status.md +++ b/docs/execution-status.md @@ -4,6 +4,14 @@ Date: 2026-07-01 Owner: product / decider Status: v0.2.0 public beta/evaluation surfaces are live for the GitHub source repository; Rust library crates `ethos-doc-core`, `ethos-verify`, and `ethos-pdf` at `0.2.0`; the Python `ethos-pdf` wheel at `0.2.0`; npm `@docushell/ethos-pdf@0.2.1`; and GitHub Release `v0.2.0` macOS arm64/Linux x64 CLI artifacts. npm `@docushell/ethos-pdf@0.2.0` is deprecated because it shipped stale CLI binaries that reported `ethos 0.1.2`; use `0.2.1`. v0.3.0 release-candidate source metadata is active in the repository for app-answer-release validation only; no public `0.3.0` install wording, publication, artifact, tag, npm alignment, or DocuShell integration is approved. PDFium-backed commands use caller-provided PDFium through `ETHOS_PDFIUM_LIBRARY_PATH`. Hosted surfaces, production positioning, Windows packaged artifacts, bundled project-maintained PDFium builds, public benchmark reports, public benchmark claims, speed, footprint, parser-quality, table-quality, `ethos-doc`, and `ethos-rag` remain blocked. +v0.3.0 package/build evidence is recorded in +`docs/validation/v0-3-0-package-build-evidence-validation-2026-07-01.md`. Rust candidate package +assembly passed for `ethos-doc-core`, `ethos-verify`, and `ethos-pdf` at `0.3.0`, the +registry-equivalent Rust consumer check passed, and the local Python wheel build/install/helper +smoke passed for `ethos-pdf==0.3.0`. Installable `0.3.0` wording remains blocked, and `cargo +publish`, PyPI upload, npm publication, GitHub Release artifact publication, tag creation, npm +alignment, and DocuShell integration remain blocked. + v0.3.0 release approval decision is recorded in `docs/validation/v0-3-0-release-approval-decision-validation-2026-07-01.md`. It accepts the exact app-answer-release contract release-prep packet and authorizes source activation on diff --git a/docs/public-release-checklist.md b/docs/public-release-checklist.md index a2221b3..3d096b4 100644 --- a/docs/public-release-checklist.md +++ b/docs/public-release-checklist.md @@ -16,6 +16,14 @@ public benchmark reports, public benchmark claims, speed, footprint, parser-qual the repository for app-answer-release validation only; no public `0.3.0` install wording, publication, artifact, tag, npm alignment, or DocuShell integration is approved. +v0.3.0 package/build evidence is recorded in +`docs/validation/v0-3-0-package-build-evidence-validation-2026-07-01.md`. It records passing local +Rust candidate package assembly for `ethos-doc-core`, `ethos-verify`, and `ethos-pdf` at `0.3.0`, a +passing registry-equivalent Rust consumer check, and a passing local Python wheel +build/install/helper smoke for `ethos-pdf==0.3.0`. Installable `0.3.0` wording remains blocked; no +`cargo publish`, PyPI upload, npm publication, GitHub Release artifact publication, tag creation, +npm alignment, or DocuShell integration is approved by that record. + v0.3.0 release approval decision is recorded in `docs/validation/v0-3-0-release-approval-decision-validation-2026-07-01.md`. It accepts the exact app-answer-release contract prep packet and authorizes release-candidate source activation on diff --git a/docs/validation/README.md b/docs/validation/README.md index 06c950b..bbce56c 100644 --- a/docs/validation/README.md +++ b/docs/validation/README.md @@ -10,6 +10,14 @@ in `docs/public-release-checklist.md`. Records: +v0.3.0 package/build evidence is recorded in +`v0-3-0-package-build-evidence-validation-2026-07-01.md`. It records local Rust candidate package +assembly for `ethos-doc-core`, `ethos-verify`, and `ethos-pdf` at `0.3.0`, a passing +registry-equivalent Rust consumer check, and a passing local Python wheel build/install/helper smoke +for `ethos-pdf==0.3.0`. Installable `0.3.0` wording remains blocked, and `cargo publish`, PyPI +upload, npm publication, GitHub Release artifact publication, tag creation, npm alignment, and +DocuShell integration remain blocked. + v0.3.0 release approval decision is recorded in `v0-3-0-release-approval-decision-validation-2026-07-01.md`. It accepts the exact app-answer-release contract release-prep packet and authorizes source activation on diff --git a/docs/validation/v0-3-0-package-build-evidence-validation-2026-07-01.md b/docs/validation/v0-3-0-package-build-evidence-validation-2026-07-01.md new file mode 100644 index 0000000..69d14fc --- /dev/null +++ b/docs/validation/v0-3-0-package-build-evidence-validation-2026-07-01.md @@ -0,0 +1,175 @@ +# v0.3.0 Package Build Evidence Validation - 2026-07-01 + +Validated source HEAD before this record: `4b6d219`. + +v0.3.0 package/build evidence source commit: +`4b6d219df1757b6e4728c16c8023bee5c8cf8962`. + +v0.3.0 package/build evidence source tree: +`2920f830f92f8290c2bf4cc661874c2641499688`. + +Status: **local Rust and Python package evidence recorded; publication and installable wording remain blocked** + +This record captures the first local package/build evidence after `v0.3.0` source metadata +activation. It validates that the current source can assemble candidate Rust crate artifacts and a +candidate Python wheel for the app-answer-release contract without publishing anything and without +changing public install wording. + +## Subject + +- Repository: `docushell/ethos` +- Lane: v0.3.0 local package/build evidence +- Source commit: `4b6d219df1757b6e4728c16c8023bee5c8cf8962` +- Source tree: `2920f830f92f8290c2bf4cc661874c2641499688` +- Rust candidate packages: `ethos-doc-core`, `ethos-verify`, and `ethos-pdf` +- Python candidate package: `ethos-pdf==0.3.0` +- Python candidate wheel: `ethos_pdf-0.3.0-py3-none-any.whl` +- npm package metadata remains `@docushell/ethos-pdf@0.2.1` + +## Rust Package Evidence + +Command: + +```sh +python3 .github/scripts/package_publication_candidate_activation.py --json +``` + +Result: + +```text +status: pass +candidate_version: 0.3.0 +candidate_packages: ethos-doc-core, ethos-verify, ethos-pdf +registry_equivalent_consumer_check: pass +package_publication_approved: false +public_installation_approved: false +``` + +Candidate crate artifacts: + +```text +ethos-doc-core-0.3.0.crate +sha256: 7ba41a2ae299a53a4677153beaaec5ed486a07b5da08b2ef13974b9a0be141cb + +ethos-verify-0.3.0.crate +sha256: 00f001455ca207e65aaf464551d3ba05945cda0b06e9e1036f49ac587accbb95 + +ethos-pdf-0.3.0.crate +sha256: c2f4f2ccb6de6e54cd3257597cd28e7f6dec2a6d22befbd230d2c4cf31931cfd +``` + +The candidate helper assembled the package artifacts in a temporary workspace and ran the +registry-equivalent consumer check offline. + +## Python Wheel Evidence + +Command: + +```sh +SOURCE_DATE_EPOCH=0 python3 -m build --wheel --outdir +``` + +Result: + +```text +Successfully built ethos_pdf-0.3.0-py3-none-any.whl +``` + +Wheel SHA256: + +```text +9eb106deafcd1d9717e5e7b67dc9413180421aba25a5257266352d09540b3265 +``` + +Wheel metadata: + +```text +Name: ethos-pdf +Version: 0.3.0 +Summary: Python wrapper for the Ethos document evidence CLI. +License-Expression: Apache-2.0 +Requires-Python: >=3.8 +Tag: py3-none-any +``` + +Wheel file list: + +```text +ethos_pdf/__init__.py +ethos_pdf/_cli.py +ethos_pdf-0.3.0.dist-info/METADATA +ethos_pdf-0.3.0.dist-info/RECORD +ethos_pdf-0.3.0.dist-info/WHEEL +ethos_pdf-0.3.0.dist-info/licenses/LICENSE +ethos_pdf-0.3.0.dist-info/licenses/NOTICE +ethos_pdf-0.3.0.dist-info/top_level.txt +``` + +Install and helper smoke: + +```sh +python3 -m pip install --no-deps --force-reinstall --target ethos_pdf-0.3.0-py3-none-any.whl +PYTHONPATH= python3 -c '' +``` + +Result: + +```text +Successfully installed ethos-pdf-0.3.0 +0.3.0 +EthosCli +True +True +certified +claim-revenue +``` + +The helper smoke imported `EthosCli`, `proof_summary`, and `app_answer_release_decision` from the +installed wheel, then checked that a direct, grounded `source_fact` claim with a reusable Ethos +check ID returns `app_status: certified`. + +## Explicit Out Of Scope + +- CLI artifact evidence remains out of scope for this record. +- npm package evidence remains out of scope for this record. +- GitHub Release artifact evidence remains out of scope for this record. +- DocuShell integration evidence remains out of scope for this record. + +## Boundary + +- This record does not approve `cargo publish`. +- This record does not approve PyPI upload. +- This record does not approve `npm publish`. +- This record does not approve GitHub Release artifact publication. +- This record does not approve release tag creation. +- This record does not approve package tag creation. +- This record does not approve installable `0.3.0` public wording. +- This record does not approve DocuShell integration. +- Hosted surfaces remain blocked. +- Production positioning remains blocked. +- Windows packaged artifacts remain blocked. +- Bundled project-maintained PDFium builds remain blocked. +- Public benchmark reports remain blocked. +- Public benchmark claims remain blocked. +- `ethos-doc` remains blocked. +- `ethos-rag` remains blocked. +- PDFium remains caller-provided through `ETHOS_PDFIUM_LIBRARY_PATH`. + +## Commands + +```sh +python3 .github/scripts/test_v0_3_0_package_build_evidence.py +make v0-3-release-prep PYTHON=python3 +python3 .github/scripts/check_release_boundary_paths.py +python3 .github/scripts/validation_record_integrity.py +git diff --check +``` + +## Result + +```text +v0.3.0 Rust candidate package assembly: PASS +v0.3.0 registry-equivalent Rust consumer check: PASS +v0.3.0 Python wheel build/install/helper smoke: PASS +publication, artifacts, tags, installable wording, npm alignment, and DocuShell integration: BLOCKED +```