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
19 changes: 11 additions & 8 deletions .github/scripts/test_patch_0_1_1_crates_publication_closeout.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@

from __future__ import annotations

import json
import re
import subprocess
import unittest
import urllib.request
from pathlib import Path


Expand Down Expand Up @@ -49,13 +51,14 @@ def git(*args: str) -> str:
).strip()


def cargo_search(crate: str) -> str:
return subprocess.check_output(
["cargo", "search", crate, "--limit", "1"],
cwd=ROOT,
encoding="utf-8",
stderr=subprocess.DEVNULL,
).strip()
def crates_io_version(crate: str, version: str) -> str:
request = urllib.request.Request(
f"https://crates.io/api/v1/crates/{crate}/{version}",
headers={"User-Agent": "ethos-release-validation"},
)
with urllib.request.urlopen(request, timeout=20) as response:
payload = json.load(response)
return payload["version"]["num"]


class Patch011CratesPublicationCloseoutTests(unittest.TestCase):
Expand Down Expand Up @@ -84,7 +87,7 @@ def test_closeout_records_all_published_crates_and_commands(self) -> None:

def test_live_crates_io_reports_patch_versions(self) -> None:
for crate in CRATES:
self.assertIn(f'{crate} = "0.1.1"', cargo_search(crate))
self.assertEqual("0.1.1", crates_io_version(crate, "0.1.1"))

def test_closeout_keeps_other_surfaces_blocked(self) -> None:
raw = read(RECORD)
Expand Down
145 changes: 145 additions & 0 deletions .github/scripts/test_patch_0_1_2_crates_publication_closeout.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
#!/usr/bin/env python3
#
# Copyright 2026 The Ethos maintainers
#
# Licensed under the Apache License, Version 2.0 (the "License");
#

from __future__ import annotations

import json
import re
import subprocess
import unittest
import urllib.request
from pathlib import Path

from makefile_guard import target_block


ROOT = Path(__file__).resolve().parents[2]
RECORD = ROOT / "docs/validation/patch-0-1-2-crates-publication-closeout-validation-2026-06-25.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"

SOURCE_SHORT = "35d0cca"
SOURCE_COMMIT = "35d0cca87669217f079793ce0553c9ac1121884b"
SOURCE_TREE = "3fcad87f2fc67c59c2f102f4f2c73d9e5c382724"
VERSION = "0.1.2"
CRATES = ("ethos-doc-core", "ethos-verify", "ethos-pdf")
FORBIDDEN = (
"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()


def crates_io_version(crate: str, version: str) -> str:
request = urllib.request.Request(
f"https://crates.io/api/v1/crates/{crate}/{version}",
headers={"User-Agent": "ethos-release-validation"},
)
with urllib.request.urlopen(request, timeout=20) as response:
payload = json.load(response)
return payload["version"]["num"]


class Patch012CratesPublicationCloseoutTests(unittest.TestCase):
def test_closeout_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 crates.io publication closeout", readme.lower())
self.assertIn(f"Validated source HEAD before this record: `{SOURCE_SHORT}`", read(RECORD))
self.assertIn(f"Patch 0.1.2 crates publication closeout source commit: `{SOURCE_COMMIT}`", record)
self.assertIn(f"Patch 0.1.2 crates publication closeout 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_closeout_records_all_published_crates_and_commands(self) -> None:
record = normalized(RECORD)

for crate in CRATES:
self.assertIn(f"{crate} = {VERSION}", record)
self.assertIn(f"cargo publish --locked -p {crate}", record)
self.assertIn(f"Published {crate} v{VERSION} at registry `crates-io`", record)
self.assertIn(f'{crate} = "{VERSION}"', record)
self.assertIn("`ethos-doc-core` was published before dependent crates", record)
self.assertIn("`ethos-verify` was published after ethos-doc-core was visible", record)
self.assertIn("`ethos-pdf` was published after ethos-verify was visible", record)

def test_live_crates_io_reports_patch_versions(self) -> None:
for crate in CRATES:
self.assertEqual(VERSION, crates_io_version(crate, VERSION))

def test_status_docs_reference_closeout_and_keep_remaining_boundaries(self) -> None:
for path in (EXECUTION_STATUS, PUBLIC_RELEASE_CHECKLIST):
text = normalized(path)
self.assertIn(RECORD.name, text, str(path))
self.assertIn("Rust crate public installation wording remains blocked", text, str(path))
self.assertIn("Python installation remains at `ethos-pdf==0.1.1`", text, str(path))
self.assertIn("hosted", text.lower(), str(path))
self.assertIn("production", text.lower(), str(path))

def test_closeout_keeps_other_surfaces_blocked(self) -> None:
raw = read(RECORD)
record = normalized(RECORD)
lower = record.lower()

for expected in (
"Rust crate public installation wording remains blocked until a separate wording and availability record.",
"Python installation remains at `ethos-pdf==0.1.1` until separate PyPI `0.1.2` publication records pass.",
"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.",
"PDFium remains caller-provided through `ETHOS_PDFIUM_LIBRARY_PATH`.",
):
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_release_candidate_prep_runs_closeout_after_decision_guard(self) -> None:
makefile = read(MAKEFILE)
decision_guard = "$(PYTHON) .github/scripts/test_patch_0_1_2_crates_publication_approval_decision.py"
closeout_guard = "$(PYTHON) .github/scripts/test_patch_0_1_2_crates_publication_closeout.py"
first_public_guard = "$(PYTHON) .github/scripts/test_first_public_release_artifact_evidence.py"
block = target_block("release-candidate-prep")

self.assertIn(closeout_guard, block)
self.assertEqual(1, makefile.count(closeout_guard))
self.assertLess(block.index(decision_guard), block.index(closeout_guard))
self.assertLess(block.index(closeout_guard), block.index(first_public_guard))


if __name__ == "__main__":
unittest.main()
1 change: 1 addition & 0 deletions .github/scripts/test_release_candidate_prep.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
"$(PYTHON) .github/scripts/test_patch_0_1_2_public_install_wording_closeout.py",
"$(PYTHON) .github/scripts/test_patch_0_1_2_crates_publication_approval_request.py",
"$(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_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",
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## Unreleased

- 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.
- boundary-exception: request decider review for exact patch `0.1.2` Rust crates.io publication of `ethos-doc-core`, `ethos-verify`, and `ethos-pdf` while keeping `cargo publish`, package tag creation, Rust public install wording, PyPI publication, hosted, production, Windows, bundled PDFium, benchmark, `ethos-doc`, and `ethos-rag` surfaces blocked.
- boundary-exception: close patch `0.1.2` public install wording for the published npm package and GitHub Release CLI artifacts while keeping Rust crates and Python wheel install wording on `0.1.1`, and retaining hosted, production, Windows, bundled PDFium, benchmark, `ethos-doc`, and `ethos-rag` blockers.
Expand Down
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,7 @@ release-candidate-prep:
$(PYTHON) .github/scripts/test_patch_0_1_2_public_install_wording_closeout.py
$(PYTHON) .github/scripts/test_patch_0_1_2_crates_publication_approval_request.py
$(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_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
Expand Down
7 changes: 7 additions & 0 deletions docs/execution-status.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,13 @@ wording remains blocked until registry availability closeout, and Python install
`ethos-pdf==0.1.1` until separate PyPI `0.1.2` approval, operator publication, and closeout records
pass.

Patch `0.1.2` crates.io publication closeout is recorded in
`docs/validation/patch-0-1-2-crates-publication-closeout-validation-2026-06-25.md`. crates.io now
reports `ethos-doc-core`, `ethos-verify`, and `ethos-pdf` at `0.1.2`. Rust crate public
installation wording remains blocked until a separate wording and availability closeout, and Python
installation remains at `ethos-pdf==0.1.1` until separate PyPI `0.1.2` approval, operator
publication, and closeout records pass.

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
Expand Down
9 changes: 9 additions & 0 deletions docs/public-release-checklist.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,15 @@ surfaces remain blocked, production positioning remains blocked, Windows package
blocked, 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` crates.io publication closeout is recorded in
`docs/validation/patch-0-1-2-crates-publication-closeout-validation-2026-06-25.md`. crates.io
reports `ethos-doc-core`, `ethos-verify`, and `ethos-pdf` at `0.1.2`. Rust crate public
installation wording remains blocked until a separate wording and availability closeout, PyPI
publication 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
Expand Down
5 changes: 5 additions & 0 deletions docs/validation/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -728,6 +728,11 @@ recording the exact current-main source candidate and required follow-up evidenc
creation, Rust crate public installation wording, 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-crates-publication-closeout-validation-2026-06-25.md` - patch 0.1.2 crates.io
publication closeout validation records operator evidence and live crates.io visibility for
`ethos-doc-core`, `ethos-verify`, and `ethos-pdf` `0.1.2`; Rust crate public installation
wording, PyPI publication, hosted, production, Windows, bundled PDFium, benchmark, `ethos-doc`,
and `ethos-rag` surfaces remain blocked until separate closeout or approval 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
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
# Patch 0.1.2 crates.io Publication Closeout Validation - 2026-06-25

Validated source HEAD before this record: `35d0cca`.

Patch 0.1.2 crates publication closeout source commit: `35d0cca87669217f079793ce0553c9ac1121884b`.

Patch 0.1.2 crates publication closeout source tree: `3fcad87f2fc67c59c2f102f4f2c73d9e5c382724`.

Status: **patch 0.1.2 Rust crates published to crates.io**

This record closes the bounded patch `0.1.2` crates.io publication lane for `ethos-doc-core`,
`ethos-verify`, and `ethos-pdf`. It records operator publish evidence and live crates.io
verification. It does not approve Rust crate public installation wording, PyPI publication, hosted
surfaces, production positioning, Windows packaged artifacts, bundled project-maintained PDFium
builds, `ethos-doc`, `ethos-rag`, public benchmark reports, public benchmark claims, or broader
public wording.

## Published Crates

- `ethos-doc-core = 0.1.2`
- `ethos-verify = 0.1.2`
- `ethos-pdf = 0.1.2`

## Operator Publish Evidence

`ethos-doc-core` command:

```text
cargo publish --locked -p ethos-doc-core
```

Observed result:

```text
Uploaded ethos-doc-core v0.1.2 to registry `crates-io`
Published ethos-doc-core v0.1.2 at registry `crates-io`
```

Registry visibility check:

```text
ethos-doc-core = "0.1.2"
```

`ethos-verify` command:

```text
cargo publish --locked -p ethos-verify
```

Observed result:

```text
Uploaded ethos-verify v0.1.2 to registry `crates-io`
Published ethos-verify v0.1.2 at registry `crates-io`
```

Registry visibility check:

```text
ethos-verify = "0.1.2"
```

`ethos-pdf` command:

```text
cargo publish --locked -p ethos-pdf
```

Observed result:

```text
Uploaded ethos-pdf v0.1.2 to registry `crates-io`
Published ethos-pdf v0.1.2 at registry `crates-io`
```

Registry visibility check:

```text
ethos-pdf = "0.1.2"
```

## Dependency-Order Evidence

- `ethos-doc-core` was published before dependent crates.
- `ethos-verify` was published after ethos-doc-core was visible on crates.io.
- `ethos-pdf` was published after ethos-verify was visible on crates.io.

## Retained Blockers

- Rust crate public installation wording remains blocked until a separate wording and availability record.
- Python installation remains at `ethos-pdf==0.1.1` until separate PyPI `0.1.2` publication
records pass.
- 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
python3 .github/scripts/test_patch_0_1_2_crates_publication_closeout.py
python3 .github/scripts/test_patch_0_1_2_crates_publication_approval_decision.py
python3 .github/scripts/test_patch_0_1_2_crates_publication_approval_request.py
cargo search ethos-doc-core --limit 1
cargo search ethos-verify --limit 1
cargo search ethos-pdf --limit 1
make release-candidate-prep PYTHON=python3
git diff --check
```

## Result

```text
patch 0.1.2 Rust crates.io publication closeout recorded
ethos-doc-core, ethos-verify, and ethos-pdf 0.1.2 are live on crates.io
Rust crate public installation wording, PyPI, and unrelated public/support surfaces remain blocked
```
Loading