diff --git a/.github/scripts/test_patch_0_1_1_crates_publication_approval_decision.py b/.github/scripts/test_patch_0_1_1_crates_publication_approval_decision.py new file mode 100644 index 0000000..4cf6157 --- /dev/null +++ b/.github/scripts/test_patch_0_1_1_crates_publication_approval_decision.py @@ -0,0 +1,140 @@ +#!/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 + + +ROOT = Path(__file__).resolve().parents[2] +RECORD = ROOT / "docs/validation/patch-0-1-1-crates-publication-approval-decision-validation-2026-06-24.md" +REQUEST = ROOT / "docs/validation/patch-0-1-1-crates-publication-approval-request-validation-2026-06-24.md" +VALIDATION_README = ROOT / "docs/validation/README.md" +MAKEFILE = ROOT / "Makefile" + +SOURCE_SHORT = "5de6014" +SOURCE_COMMIT = "5de6014e0fe668bac306eb2c2f5b2963ab5baf96" +SOURCE_TREE = "6fc0207e61681da6ba868772e77bcbc808c98bfb" +PACKAGE_SOURCE_COMMIT = "a0851030e28c155c12f5f966af8fa0739a536ea9" +PACKAGE_SOURCE_TREE = "0238c3f6bfd264f8803708e4a828d8352320f08f" +CRATES = ("ethos-doc-core", "ethos-verify", "ethos-pdf") +FORBIDDEN = ( + "crates are published", + "published crates", + "hosted surfaces approved", + "production-ready", + "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 Patch011CratesPublicationApprovalDecisionTests(unittest.TestCase): + def test_decision_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.1 crates.io publication approval decision", readme.lower()) + self.assertIn(f"Validated source HEAD before this record: `{SOURCE_SHORT}`", read(RECORD)) + self.assertIn(f"Patch 0.1.1 crates publication approval decision source commit: `{SOURCE_COMMIT}`", record) + self.assertIn(f"Patch 0.1.1 crates publication approval decision 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_decision_accepts_exact_request_packet(self) -> None: + record = normalized(RECORD) + + self.assertIn(REQUEST.name, record) + self.assertIn("Decision: accept exact patch `0.1.1` crates.io publication decision packet.", record) + self.assertIn(f"Package source commit accepted by this decision: `{PACKAGE_SOURCE_COMMIT}`", record) + self.assertIn(f"Package source tree accepted by this decision: `{PACKAGE_SOURCE_TREE}`", record) + for crate in CRATES: + self.assertIn(crate, record) + self.assertIn(f"{crate} = 0.1.1", record) + self.assertIn(f"cargo publish --locked -p {crate}", record) + self.assertIn("ethos-package-ethos-doc-core-0.1.1", record) + self.assertIn("ethos-package-ethos-verify-0.1.1", record) + self.assertIn("ethos-package-ethos-pdf-0.1.1", record) + + def test_decision_allows_only_later_operator_actions_with_boundaries(self) -> None: + raw = read(RECORD) + lower = normalized(RECORD).lower() + record = normalized(RECORD) + + for expected in ( + "This decision record does not run `cargo publish`.", + "Publication remains a separate operator action.", + "After this decision record is merged and validation passes on merged source, an operator may run only these commands:", + "The operator must publish `ethos-doc-core` first.", + "The operator must wait for crates.io to report `ethos-doc-core = 0.1.1` before publishing dependent crates.", + "Public installation wording remains blocked until registry availability is closed out.", + "`ethos-doc` remains blocked.", + "`ethos-rag` remains blocked.", + ): + self.assertIn(expected, record) + for forbidden in FORBIDDEN: + self.assertNotIn(forbidden, lower) + self.assertNotIn("/Users/", raw) + self.assertNotIn("/private/tmp", raw) + self.assertNotIn("/var/folders", raw) + self.assertNotIn("saumildiwaker", raw) + + def test_publish_surface_remains_limited_in_manifests(self) -> None: + for manifest in ( + ROOT / "crates/ethos-core/Cargo.toml", + ROOT / "crates/ethos-verify/Cargo.toml", + ROOT / "crates/ethos-pdf/Cargo.toml", + ): + text = read(manifest) + self.assertNotIn("publish = false", text, str(manifest)) + self.assertIn('publication_status = "approved_for_crates_io_publication"', text, str(manifest)) + + for manifest in ( + ROOT / "crates/ethos-cli/Cargo.toml", + ROOT / "crates/ethos-layout/Cargo.toml", + ROOT / "crates/ethos-tables/Cargo.toml", + ): + self.assertIn("publish = false", read(manifest), str(manifest)) + + def test_release_candidate_prep_runs_decision_guard_after_request_guard(self) -> None: + makefile = read(MAKEFILE) + request_guard = "$(PYTHON) .github/scripts/test_patch_0_1_1_crates_publication_approval_request.py" + decision_guard = "$(PYTHON) .github/scripts/test_patch_0_1_1_crates_publication_approval_decision.py" + + self.assertIn(decision_guard, makefile) + self.assertEqual(1, makefile.count(decision_guard)) + self.assertLess(makefile.index(request_guard), makefile.index(decision_guard)) + self.assertLess( + makefile.index(decision_guard), + makefile.index("$(PYTHON) .github/scripts/test_pdfium_manual_setup_contract.py"), + ) + + +if __name__ == "__main__": + unittest.main() diff --git a/.github/scripts/test_release_candidate_prep.py b/.github/scripts/test_release_candidate_prep.py index 5aafec8..a315c80 100644 --- a/.github/scripts/test_release_candidate_prep.py +++ b/.github/scripts/test_release_candidate_prep.py @@ -38,6 +38,7 @@ "$(PYTHON) .github/scripts/test_npm_publication_final_approval_decision.py", "$(PYTHON) .github/scripts/test_npm_publication_closeout.py", "$(PYTHON) .github/scripts/test_patch_0_1_1_crates_publication_approval_request.py", + "$(PYTHON) .github/scripts/test_patch_0_1_1_crates_publication_approval_decision.py", "$(PYTHON) .github/scripts/test_pdfium_manual_setup_contract.py", "$(PYTHON) .github/scripts/test_release_artifact_workflow_prep.py", "$(PYTHON) .github/scripts/test_patch_0_1_1_release_artifact_evidence.py", diff --git a/CHANGELOG.md b/CHANGELOG.md index 4688912..6c8c2e6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Unreleased +- boundary-exception: approve exact patch `0.1.1` Rust crates.io publication decision for later operator publish; no `cargo publish` or support-boundary change. - boundary-exception: request exact patch `0.1.1` Rust crates.io publication approval for decider review; no `cargo publish` or support-boundary change. - boundary-exception: close patch `0.1.1` npm publication with exact registry evidence; no hosted, production, Windows, bundled PDFium, benchmark, `ethos-doc`, or `ethos-rag` boundary change. - boundary-exception: approve exact patch `0.1.1` npm publication decision for later operator publish; no npm publish or support-boundary change. diff --git a/Makefile b/Makefile index 8301242..83d2731 100644 --- a/Makefile +++ b/Makefile @@ -280,6 +280,7 @@ release-candidate-prep: $(PYTHON) .github/scripts/test_npm_publication_final_approval_decision.py $(PYTHON) .github/scripts/test_npm_publication_closeout.py $(PYTHON) .github/scripts/test_patch_0_1_1_crates_publication_approval_request.py + $(PYTHON) .github/scripts/test_patch_0_1_1_crates_publication_approval_decision.py $(PYTHON) .github/scripts/test_pdfium_manual_setup_contract.py $(PYTHON) .github/scripts/test_release_artifact_workflow_prep.py $(PYTHON) .github/scripts/test_patch_0_1_1_release_artifact_evidence.py diff --git a/docs/validation/README.md b/docs/validation/README.md index 5125d5f..0d0dfe3 100644 --- a/docs/validation/README.md +++ b/docs/validation/README.md @@ -607,6 +607,10 @@ recording the exact current-main source candidate and required follow-up evidenc `ethos-verify`, and `ethos-pdf` `0.1.1` crate set, source commit, package tag names, local crate artifact hashes, publish order, and retained blockers for decider review; `cargo publish` remains blocked. +- `patch-0-1-1-crates-publication-approval-decision-validation-2026-06-24.md` - patch 0.1.1 + crates.io publication approval decision validation accepts the exact `ethos-doc-core`, + `ethos-verify`, and `ethos-pdf` `0.1.1` crate set, package source binding, package tag names, + dependency-ordered operator commands, and retained blockers; operator publish remains pending. - `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-1-crates-publication-approval-decision-validation-2026-06-24.md b/docs/validation/patch-0-1-1-crates-publication-approval-decision-validation-2026-06-24.md new file mode 100644 index 0000000..952e7c1 --- /dev/null +++ b/docs/validation/patch-0-1-1-crates-publication-approval-decision-validation-2026-06-24.md @@ -0,0 +1,141 @@ +# Patch 0.1.1 crates.io Publication Approval Decision Validation - 2026-06-24 + +Validated source HEAD before this record: `5de6014`. + +Patch 0.1.1 crates publication approval decision source commit: `5de6014e0fe668bac306eb2c2f5b2963ab5baf96`. + +Patch 0.1.1 crates publication approval decision source tree: `6fc0207e61681da6ba868772e77bcbc808c98bfb`. + +Status: **patch 0.1.1 crates.io publication approval decision recorded; operator publish remains pending** + +This record accepts the exact patch `0.1.1` crates.io publication request packet after decider +approval. It approves only the bounded later operator actions for `ethos-doc-core`, +`ethos-verify`, and `ethos-pdf` version `0.1.1`. It does not run `cargo publish`, publish any +crate, change public 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: Rust crates publication +- Approval owner: `docushell-admin` +- Approval request record: + `docs/validation/patch-0-1-1-crates-publication-approval-request-validation-2026-06-24.md` +- Package source commit accepted by this decision: `a0851030e28c155c12f5f966af8fa0739a536ea9` +- Package source tree accepted by this decision: `0238c3f6bfd264f8803708e4a828d8352320f08f` + +## Exact Decision Fields + +- Decision: accept exact patch `0.1.1` crates.io publication decision packet. +- Approver: `docushell-admin` acting as decider. +- Date: 2026-06-24. +- Exact candidate crate list accepted by this decision: `ethos-doc-core`, `ethos-verify`, and + `ethos-pdf` only. +- Exact package version map accepted by this decision: `ethos-doc-core = 0.1.1`, + `ethos-verify = 0.1.1`, and `ethos-pdf = 0.1.1`. +- Exact package tag name set accepted by this decision: `ethos-package-ethos-doc-core-0.1.1`, + `ethos-package-ethos-verify-0.1.1`, and `ethos-package-ethos-pdf-0.1.1`. +- Exact package tag source commit accepted by this decision: + `a0851030e28c155c12f5f966af8fa0739a536ea9`. +- Exact package tag source tree accepted by this decision: + `0238c3f6bfd264f8803708e4a828d8352320f08f`. +- Exact operator commands accepted by this decision: + - `cargo publish --locked -p ethos-doc-core` + - `cargo publish --locked -p ethos-verify` + - `cargo publish --locked -p ethos-pdf` + +## Approved Operator Action + +After this decision record is merged and validation passes on merged source, an operator may run +only these commands: + +```sh +cargo publish --locked -p ethos-doc-core +cargo publish --locked -p ethos-verify +cargo publish --locked -p ethos-pdf +``` + +The operator must publish `ethos-doc-core` first. The operator must wait for crates.io to report +`ethos-doc-core = 0.1.1` before publishing dependent crates. The operator must stop if candidate +contents differ, package versions differ, crates.io reports any unexpected version state, or any +retained blocker is softened. + +Publication remains a separate operator action. This decision record does not run `cargo publish`. + +## Required Operator Pre-Publish Checks + +Before publishing, the operator must run: + +```sh +cargo package --locked --offline -p ethos-doc-core --allow-dirty --no-verify +cargo check --locked --offline -p ethos-verify +cargo check --locked --offline -p ethos-pdf +python3 .github/scripts/test_patch_0_1_1_crates_publication_approval_decision.py +python3 .github/scripts/test_patch_0_1_1_crates_publication_approval_request.py +make release-candidate-prep PYTHON=python3 +git diff --check +``` + +## Explicit Exclusions + +- `ethos-cli` remains excluded from crates.io publication. +- `ethos-layout` remains excluded from crates.io publication. +- `ethos-tables` remains excluded from crates.io publication. +- `ethos-grounding-opendataloader-json` remains excluded from crates.io publication. +- 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. +- Broader public wording remains blocked. + +## Evidence Bound To This Decision + +- Decider decision supplied: Approved; exact patch `0.1.1` Rust crates.io publication request + accepted. +- `python3 .github/scripts/test_patch_0_1_1_crates_publication_approval_request.py` passed. +- `python3 .github/scripts/test_milestone_e_package_publication_current_registry_assembly.py` + passed. +- `python3 .github/scripts/test_milestone_e_package_publication_dry_run_smoke.py` passed. +- `cargo package --locked --offline -p ethos-doc-core --allow-dirty --no-verify` passed. +- `cargo check --locked --offline -p ethos-verify` passed. +- `cargo check --locked --offline -p ethos-pdf` passed. +- `make release-candidate-prep PYTHON=python3` passed on merged `main` before this decision branch. + +## Non-Actions + +- This decision record does not run `cargo publish`. +- This decision record does not publish any crate. +- This decision record does not create package tags. +- This decision record does not approve public installation wording. +- This decision record does not approve hosted surfaces. +- This decision record does not approve production positioning. +- This decision record does not approve public benchmark reports. +- This decision record does not approve public benchmark claims. +- This decision record does not approve Windows packaged artifacts. +- This decision record does not approve bundled project-maintained PDFium builds. +- This decision record does not approve `ethos-doc`. +- This decision record does not approve `ethos-rag`. + +## Retained Blockers + +- Public installation wording remains blocked until registry availability is closed out. +- 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. + +## Result + +The exact patch `0.1.1` crates.io publication decision packet for `ethos-doc-core`, +`ethos-verify`, and `ethos-pdf` is accepted. Actual crates.io publication remains a separate +operator action requiring final pre-publish checks, crates.io credentials, dependency-order +discipline, and later registry closeout evidence.