diff --git a/.github/scripts/test_patch_0_1_2_artifact_package_evidence.py b/.github/scripts/test_patch_0_1_2_artifact_package_evidence.py new file mode 100644 index 0000000..5c1c999 --- /dev/null +++ b/.github/scripts/test_patch_0_1_2_artifact_package_evidence.py @@ -0,0 +1,339 @@ +#!/usr/bin/env python3 +# +# Copyright 2026 The Ethos maintainers +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under 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 + + +ROOT = Path(__file__).resolve().parents[2] +SCRIPT = ROOT / ".github/scripts/package_publication_candidate_activation.py" +RECORD = ROOT / "docs/validation/patch-0-1-2-artifact-package-evidence-validation-2026-06-24.md" +VALIDATION_README = ROOT / "docs/validation/README.md" +EXECUTION_STATUS = ROOT / "docs/execution-status.md" +PUBLIC_RELEASE_CHECKLIST = ROOT / "docs/public-release-checklist.md" +PYPROJECT = ROOT / "pyproject.toml" +PY_INIT = ROOT / "python/ethos_pdf/__init__.py" +NPM_PACKAGE = ROOT / "packages/npm/ethos-pdf/package.json" + +SOURCE_SHORT = "6f81938" +SOURCE_COMMIT = "6f819381e189e98f5aa3177deb52901c89447ab4" +SOURCE_TREE = "7cae3956d5d01aac1005b675332c97451df3cbb8" +VERSION = "0.1.2" +WHEEL = "ethos_pdf-0.1.2-py3-none-any.whl" +EXPECTED_CRATES = { + "ethos-doc-core": "ethos-doc-core-0.1.2.crate", + "ethos-verify": "ethos-verify-0.1.2.crate", + "ethos-pdf": "ethos-pdf-0.1.2.crate", +} +EXPECTED_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", + "crates.io publication approved", + "npm publication approved", + "github release publication approved", + "public installation approved", + "public install wording approved", + "vendor payload refreshed", + "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 git(*args: str) -> str: + return subprocess.check_output( + ["git", *args], + cwd=ROOT, + encoding="utf-8", + stderr=subprocess.DEVNULL, + ).strip() + + +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(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 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-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) + + build = run( + [ + sys.executable, + "-m", + "build", + "--wheel", + "--outdir", + str(out_dir), + ], + workspace, + ) + 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}" + ) + + env = dict(os.environ) + env["PYTHONPATH"] = str(install_dir) + smoke = run( + [ + sys.executable, + "-c", + ( + "import ethos_pdf; " + "print(ethos_pdf.__version__); " + "print(ethos_pdf.EthosCli.__name__); " + "print(ethos_pdf.EthosCommandError.__name__)" + ), + ], + workspace, + env=env, + ) + if smoke.returncode != 0: + raise AssertionError( + "python wheel import 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.1.2.dist-info/METADATA").decode("utf-8") + wheel_metadata = archive.read("ethos_pdf-0.1.2.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 Patch012ArtifactPackageEvidenceTests(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) + readme = normalized(VALIDATION_README) + + self.assertIn(f"Validated source HEAD before this record: `{SOURCE_SHORT}`", raw) + self.assertIn(f"Patch 0.1.2 artifact/package evidence source commit: `{SOURCE_COMMIT}`", record) + self.assertIn(f"Patch 0.1.2 artifact/package evidence 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}}")) + self.assertIn(RECORD.name, readme) + self.assertIn("patch 0.1.2 artifact/package evidence validation", readme) + + def test_crate_candidate_artifacts_are_0_1_2_and_registry_equivalent_consumer_checks(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 in EXPECTED_CRATES.items(): + self.assertEqual(crate_file, artifacts[package]["crate_file"]) + self.assertRegex(artifacts[package]["sha256"], r"^[0-9a-f]{64}$") + + def test_python_wheel_candidate_is_0_1_2_and_importable(self) -> None: + wheel = self.wheel + + self.assertEqual(WHEEL, wheel["wheel"]) + self.assertRegex(str(wheel["sha256"]), r"^[0-9a-f]{64}$") + for expected in EXPECTED_WHEEL_FILES: + self.assertIn(expected, wheel["files"]) + self.assertIn("Name: ethos-pdf", str(wheel["metadata"])) + self.assertIn("Version: 0.1.2", 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.1.2", "EthosCli", "EthosCommandError"], wheel["smoke_stdout"]) + + def test_source_metadata_and_public_install_baseline_remain_split(self) -> None: + self.assertIn('version = "0.1.2"', read(PYPROJECT)) + self.assertIn('__version__ = "0.1.2"', read(PY_INIT)) + self.assertEqual("0.1.1", json.loads(read(NPM_PACKAGE))["version"]) + + for path in (EXECUTION_STATUS, PUBLIC_RELEASE_CHECKLIST): + doc = normalized(path) + self.assertIn(RECORD.name, doc, str(path)) + self.assertIn("public install baseline remains `0.1.1`", doc, str(path)) + self.assertIn("public installation wording remains blocked", doc, str(path)) + + def test_record_keeps_publication_vendor_refresh_and_claim_boundaries_blocked(self) -> None: + raw = read(RECORD) + record = normalized(RECORD) + lower = record.lower() + + for expected in ( + "This record does not approve publishing any package.", + "This record does not approve PyPI upload.", + "This record does not approve crates.io publication.", + "This record does not approve npm publication.", + "This record does not approve GitHub Release artifact publication.", + "This record does not refresh the checked-in npm vendor payload.", + "public install baseline remains `0.1.1`", + "Actual registry publication remains blocked", + "GitHub Release artifact publication remains blocked", + "npm vendor refresh remains blocked", + "Public installation wording remains blocked", + "PDFium remains caller-provided through `ETHOS_PDFIUM_LIBRARY_PATH`.", + ): + self.assertIn(expected, record) + for forbidden in FORBIDDEN: + self.assertNotIn(forbidden, lower) + for marker in PRIVATE_PATH_MARKERS: + self.assertNotIn(marker, raw) + + def test_release_candidate_prep_runs_this_guard_after_version_activation(self) -> None: + block = target_block("release-candidate-prep") + version_guard = "$(PYTHON) .github/scripts/test_patch_0_1_2_version_activation.py" + evidence_guard = "$(PYTHON) .github/scripts/test_patch_0_1_2_artifact_package_evidence.py" + first_public_guard = "$(PYTHON) .github/scripts/test_first_public_release_artifact_evidence.py" + + self.assertIn(evidence_guard, block) + self.assertEqual(1, block.count(evidence_guard)) + self.assertLess(block.index(version_guard), block.index(evidence_guard)) + self.assertLess(block.index(evidence_guard), block.index(first_public_guard)) + + +if __name__ == "__main__": + unittest.main() diff --git a/.github/scripts/test_release_artifact_workflow_prep.py b/.github/scripts/test_release_artifact_workflow_prep.py index bbfb796..ae62fdf 100644 --- a/.github/scripts/test_release_artifact_workflow_prep.py +++ b/.github/scripts/test_release_artifact_workflow_prep.py @@ -48,6 +48,7 @@ def test_workflow_generates_draft_artifacts_without_publication(self) -> None: self.assertIn("cargo build --locked --release -p ethos-cli", text) self.assertIn("write_release_artifact_inventory.py", text) self.assertIn("smoke_release_cli_artifact.py", text) + self.assertIn('--expected-version "ethos 0.1.2"', text) self.assertIn("--target \"${{ matrix.artifact_target }}\"", text) self.assertIn("*.smoke.json", text) self.assertIn("validate_release_artifact_inventory.py", text) diff --git a/.github/scripts/test_release_candidate_prep.py b/.github/scripts/test_release_candidate_prep.py index 539825b..7f5fccf 100644 --- a/.github/scripts/test_release_candidate_prep.py +++ b/.github/scripts/test_release_candidate_prep.py @@ -58,6 +58,7 @@ "$(PYTHON) .github/scripts/test_launch_copy_approval_scaffold.py", "$(PYTHON) .github/scripts/test_patch_0_1_2_readiness_prep.py", "$(PYTHON) .github/scripts/test_patch_0_1_2_version_activation.py", + "$(PYTHON) .github/scripts/test_patch_0_1_2_artifact_package_evidence.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/.github/workflows/release.yml b/.github/workflows/release.yml index 0878476..5d69b58 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -65,6 +65,7 @@ jobs: run: | python3 .github/scripts/smoke_release_cli_artifact.py \ --artifact-dir "target/release-artifacts/ethos-${{ matrix.artifact_target }}" \ + --expected-version "ethos 0.1.2" \ --target "${{ matrix.artifact_target }}" \ --out "target/release-artifacts/ethos-${{ matrix.artifact_target }}.smoke.json" - name: validate draft artifact inventory diff --git a/CHANGELOG.md b/CHANGELOG.md index f89cd97..41d9e88 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Unreleased +- boundary-exception: record patch `0.1.2` artifact/package evidence prep and update draft CLI artifact smoke expectations to `ethos 0.1.2` while keeping npm, public install wording, registry publication, GitHub Release publication, hosted, production, Windows, bundled PDFium, benchmark, `ethos-doc`, and `ethos-rag` surfaces blocked. - boundary-exception: activate Rust workspace and Python source/package metadata for patch `0.1.2` candidate validation while keeping npm and public install wording on the published `0.1.1` baseline; no release, tag, package publication, hosted, production, Windows, bundled PDFium, benchmark, `ethos-doc`, or `ethos-rag` boundary change. - boundary-exception: record narrow patch `0.1.2` readiness prep and professional public README beta wording while retaining `0.1.1` install baselines; no release, tag, package publication, hosted, production, Windows, bundled PDFium, benchmark, `ethos-doc`, or `ethos-rag` boundary change. - boundary-exception: add an `evidence_anchor` v1 guard target, CI guard step, and schema-bound inventory for the merged source-only command; no hosted, production, Windows, bundled PDFium, benchmark, parser-quality, table-quality, or release-posture boundary change. diff --git a/Makefile b/Makefile index 72271c1..207e067 100644 --- a/Makefile +++ b/Makefile @@ -309,6 +309,7 @@ release-candidate-prep: $(PYTHON) .github/scripts/test_launch_copy_approval_scaffold.py $(PYTHON) .github/scripts/test_patch_0_1_2_readiness_prep.py $(PYTHON) .github/scripts/test_patch_0_1_2_version_activation.py + $(PYTHON) .github/scripts/test_patch_0_1_2_artifact_package_evidence.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 5b898b4..0ba2b23 100644 --- a/docs/execution-status.md +++ b/docs/execution-status.md @@ -272,6 +272,8 @@ The patch `0.1.2` readiness prep record in `docs/validation/patch-0-1-2-readines The patch `0.1.2` version activation record in `docs/validation/patch-0-1-2-version-activation-validation-2026-06-24.md` moves the Rust workspace and Python source/package metadata to `0.1.2` for candidate validation only. npm and public install wording remain on the published `0.1.1` baseline until matching `0.1.2` CLI artifacts, registry/GitHub Release evidence, and operator actions are recorded. This activation does not approve a release, tag, package publish, GitHub Release artifact, hosted surface, production positioning, Windows packaged artifact, bundled project-maintained PDFium build, public benchmark report, or public benchmark claim. +The patch `0.1.2` artifact/package evidence record in `docs/validation/patch-0-1-2-artifact-package-evidence-validation-2026-06-24.md` adds a dynamic release-candidate-prep guard for local `0.1.2` Rust crate candidates and the `ethos_pdf-0.1.2-py3-none-any.whl` candidate, and updates draft CLI artifact workflow smoke expectations to `ethos 0.1.2`. The public install baseline remains `0.1.1`, public installation wording remains blocked, registry publication remains blocked, GitHub Release artifact publication remains blocked, and npm vendor refresh remains blocked until separate approval, operator evidence, and closeout records pass. + | Work item | Current status | Remaining blocker | | --- | --- | --- | | PDFium Phase 1 profile | Landed: pinned profile, V8/XFA-disabled state, platform hashes, runtime library hashes, and provenance are recorded | Phase 2 project-maintained builds still block Public Beta | diff --git a/docs/public-release-checklist.md b/docs/public-release-checklist.md index 3b5c5f0..9acfb8d 100644 --- a/docs/public-release-checklist.md +++ b/docs/public-release-checklist.md @@ -35,6 +35,15 @@ evidence exist, and does not approve a release, tag, package publish, GitHub Rel hosted surface, production positioning, Windows packaged artifact, bundled project-maintained PDFium build, public benchmark report, or public benchmark claim. +Patch `0.1.2` artifact/package evidence is recorded in +`docs/validation/patch-0-1-2-artifact-package-evidence-validation-2026-06-24.md` for local +candidate validation only. It dynamically checks `0.1.2` Rust crate candidates and the +`ethos_pdf-0.1.2-py3-none-any.whl` candidate, and it updates draft CLI artifact workflow smoke +expectations to `ethos 0.1.2`. The public install baseline remains `0.1.1`, public installation +wording remains blocked, registry publication remains blocked, GitHub Release artifact publication +remains blocked, and npm vendor refresh remains blocked until separate approval, operator evidence, +and closeout records pass. + ## 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 56c0e8d..b9bfcf9 100644 --- a/docs/validation/README.md +++ b/docs/validation/README.md @@ -659,6 +659,12 @@ recording the exact current-main source candidate and required follow-up evidenc publication evidence exist, and leaves release, tag, publication, GitHub Release artifact, hosted, production, Windows, bundled PDFium, benchmark, `ethos-doc`, and `ethos-rag` surfaces unapproved. +- `patch-0-1-2-artifact-package-evidence-validation-2026-06-24.md` - patch 0.1.2 + artifact/package evidence validation dynamically checks `0.1.2` Rust crate candidates and the + `ethos_pdf-0.1.2-py3-none-any.whl` candidate, updates draft CLI artifact workflow smoke + expectations to `ethos 0.1.2`, and keeps npm at `0.1.1`, public install wording blocked, + registry publication blocked, GitHub Release artifact publication blocked, hosted, production, + Windows, bundled PDFium, benchmark, `ethos-doc`, and `ethos-rag` surfaces unapproved. - `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-artifact-package-evidence-validation-2026-06-24.md b/docs/validation/patch-0-1-2-artifact-package-evidence-validation-2026-06-24.md new file mode 100644 index 0000000..904a267 --- /dev/null +++ b/docs/validation/patch-0-1-2-artifact-package-evidence-validation-2026-06-24.md @@ -0,0 +1,104 @@ +# Patch 0.1.2 Artifact/Package Evidence Validation - 2026-06-24 + +Validated source HEAD before this record: `6f81938`. + +Patch 0.1.2 artifact/package evidence source commit: +`6f819381e189e98f5aa3177deb52901c89447ab4`. + +Patch 0.1.2 artifact/package evidence source tree: +`7cae3956d5d01aac1005b675332c97451df3cbb8`. + +Status: **patch 0.1.2 artifact/package evidence prep recorded; publication remains blocked** + +This record captures the first source-bound artifact/package evidence gate after patch `0.1.2` +source version activation. It validates that the current source can assemble candidate Rust crate +artifacts and a candidate Python wheel for `0.1.2` without publishing anything and without changing +public install wording. + +## Subject + +- Repository: `docushell/ethos` +- Lane: patch `0.1.2` artifact/package evidence prep +- Source commit: `6f819381e189e98f5aa3177deb52901c89447ab4` +- Source tree: `7cae3956d5d01aac1005b675332c97451df3cbb8` +- Rust candidate packages: `ethos-doc-core`, `ethos-verify`, and `ethos-pdf` +- Python candidate package: `ethos-pdf==0.1.2` +- Python candidate wheel: `ethos_pdf-0.1.2-py3-none-any.whl` +- npm package metadata remains `@docushell/ethos-pdf@0.1.1` + +## Local Evidence Gate + +The guard `python3 .github/scripts/test_patch_0_1_2_artifact_package_evidence.py` dynamically +checks the following in temporary workspaces: + +- `python3 .github/scripts/package_publication_candidate_activation.py --json` reports + candidate version `0.1.2`. +- Candidate crate files are assembled for: + - `ethos-doc-core-0.1.2.crate` + - `ethos-verify-0.1.2.crate` + - `ethos-pdf-0.1.2.crate` +- Each candidate crate artifact reports a SHA256-shaped digest. +- The registry-equivalent consumer check passes offline. +- The candidate activation report keeps `package_publication_approved` false. +- The candidate activation report keeps `public_installation_approved` false. +- `python3 -m build --wheel --outdir ` builds + `ethos_pdf-0.1.2-py3-none-any.whl`. +- The wheel reports `Name: ethos-pdf`, `Version: 0.1.2`, + `License-Expression: Apache-2.0`, `Requires-Python: >=3.8`, and `Tag: py3-none-any`. +- Local install/import smoke resolves version `0.1.2`, `EthosCli`, and `EthosCommandError`. + +## Release Workflow Prep + +The draft CLI artifact workflow now passes `--expected-version "ethos 0.1.2"` to +`smoke_release_cli_artifact.py`. This lane records only workflow preparedness for the version +activated source; it does not record downloaded `0.1.2` GitHub Actions artifacts or approve +publishing those artifacts to a GitHub Release. + +## Boundary + +This record does not approve publishing any package. This record does not approve PyPI upload. This +record does not approve crates.io publication. This record does not approve npm publication. This +record does not approve GitHub Release artifact publication. This record does not approve creating +or moving a tag. This record does not refresh the checked-in npm vendor payload. This record does +not approve public installation wording for `0.1.2`. + +The public install baseline remains `0.1.1` until separate registry/GitHub Release evidence, +operator actions, npm vendor refresh, and public wording closeout records pass. + +## Retained Blockers + +- Actual registry publication remains blocked. +- GitHub Release artifact publication remains blocked. +- npm vendor refresh remains blocked. +- npm publication remains blocked. +- 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. +- 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_patch_0_1_2_artifact_package_evidence.py +python3 .github/scripts/test_patch_0_1_2_version_activation.py +python3 .github/scripts/test_release_artifact_workflow_prep.py +python3 .github/scripts/test_public_surface_posture.py +python3 .github/scripts/public_boundary_claims_gate.py +make release-candidate-prep PYTHON=python3 +git diff --check +``` + +## Result + +```text +patch 0.1.2 artifact/package evidence prep recorded +0.1.2 crate candidates and Python wheel candidate are locally evidence-checked +public install baseline remains 0.1.1 +publication and GitHub Release artifact actions remain blocked pending separate approval and operator evidence +```