diff --git a/.release-reconciled-version b/.release-reconciled-version new file mode 100644 index 0000000..ac39a10 --- /dev/null +++ b/.release-reconciled-version @@ -0,0 +1 @@ +0.9.0 diff --git a/docs/engineering/execution_history/README.md b/docs/engineering/execution_history/README.md index 066336a..9d5c380 100644 --- a/docs/engineering/execution_history/README.md +++ b/docs/engineering/execution_history/README.md @@ -6,7 +6,7 @@ | Stable tag | Primary archived plan | Related context in the same archive | | --- | --- | --- | -| `v0.9.0` | [Unprotected-target integrity and OCR 1.11.2/1.11.3](releases.md#plan-toolkit-0-9-0) | Canonical reviewed-source identity, constrained unprotected-target reviews, action receipt v3 and receipt v8, additive diagnostic containment, OCR 1.11.2/1.11.3 qualification, complete Mermaid decision maps, retained semantic OCR remediation, Codex Security review, feature merge, development artifact verification, and stable-delivery handoff. | +| `v0.9.0` | [Unprotected-target integrity and OCR 1.11.2/1.11.3](releases.md#plan-toolkit-0-9-0) | Canonical reviewed-source identity, constrained unprotected-target reviews, action receipt v3 and receipt v8, additive diagnostic containment, OCR 1.11.2/1.11.3 qualification, complete Mermaid decision maps, retained semantic OCR remediation, Codex Security review, feature merge, development artifact verification, stable delivery, and external reconciliation. | | `v0.8.7` | [OCR 1.11.1, evidence integrity, and efficient built-in MCP](releases.md#plan-toolkit-0-8-7) | Evidence comparison integrity, bounded search and exact coverage tools, protected same-revision CI outcomes, OCR 1.11.1 qualification, three complete local reviews, controlled five-action MCP qualification, feature merge, development artifact verification, and stable-delivery handoff. | | `v0.8.6` | [OCR 1.11.0 and precise security signals](releases.md#plan-toolkit-0-8-6) | Contextual injection classification, provider-private OCR-state containment, OCR 1.11.0 qualification and Rules, one complete local semantic review with remediation, feature merge, development artifact verification, and stable-delivery handoff. | | `v0.8.5` | [Provider diagnostics and OCR 1.10.2](releases.md#plan-toolkit-0-8-5) | Closed numeric provider diagnostics, unchanged GitLab/DLP/receipt/approval projections, OCR 1.10.2 qualification and Rules, compatibility scheduling, explicit local OCR provider-failure waiver, feature merge, development artifact verification, and stable-delivery handoff. | diff --git a/docs/engineering/execution_history/releases.md b/docs/engineering/execution_history/releases.md index 7085b97..257e68a 100644 --- a/docs/engineering/execution_history/releases.md +++ b/docs/engineering/execution_history/releases.md @@ -6,10 +6,11 @@ This archive preserves completed execution plans moved out of the active registr ## Toolkit 0.9.0 — unprotected-target integrity and OCR 1.11.2/1.11.3 -Status: repository complete; external stable delivery pending +Status: completed; stable v0.9.0 delivery and external reconciliation verified Release classification: `release-required` Target stable version: `0.9.0` Repository completion date: 2026-09-03 +External reconciliation date: 2026-09-03 ### Goal and delivered scope @@ -69,22 +70,39 @@ is linked from the root `AGENTS.md`, documentation index, and toolkit strategy. Workflow and registry bytes, PEP 740 provenance, hosted verifier installs, and CLI smokes agree. -### Stable delivery handoff +### Stable delivery and external closure -The release PR is the final repository mutation. It sets +The release PR was the final repository mutation before stable publication. It set `.release-version=0.9.0`, `.next-version=0.9.1`, deterministic source epoch `1788423271`, exact sorted issues `[167,168,169,170,172]`, generated Towncrier notes, the stable example pin, and this archive while returning `PLANS.md` to its inactive template. -External closure remains pending until the exact reviewed release head is -squash-merged and the protected workflow is independently reconciled across -TestPyPI, PyPI, workflow artifacts, and the immutable GitHub Release. Closure -requires byte equality, PEP 740 provenance and GitHub attestations, annotated -`v0.9.0` tag and peeled target, immutable five-asset Release, validated -`release-receipt.json`, clean wheel and sdist installs on Python 3.12–3.14, -Actions-owned receipts, closed #167/#168/#169/#170/#172 and milestone `v0.9.0`, -deleted release branch, and clean `main == origin/main == v0.9.0^{}`. +Release PR #173 reviewed exact head +`255fac862edc5ef525b8a580b40095bc8ec7ff44` on base +`3c7e38c08a48c9af1d0b0c5e10ecf0ac8b5eacc3` and was squash-merged as +`39ff90a5eb58072f4a5ef5ea6657ba4cadbe1bb0`. All 13 protected check names +passed at the reviewed head with zero unresolved review threads. Protected +Release workflow run 33734006965 then completed stable TestPyPI and PyPI +publication, supported-Python verification, provenance and attestation checks, +and GitHub Release publication successfully. + +Annotated tag object `9d23caa017b8776dfc9c922ed6a4834dcf4f174e` peels to the release merge. GitHub +Release `v0.9.0` is immutable, non-draft, non-prerelease, and contains exactly +the wheel, sdist, `SHA256SUMS`, `artifact-hashes.json`, and +`release-receipt.json`. The receipt SHA-256 is +`1cc0d0641ea76675f403084c21e0f35b97c611e1ea11ea8328d3af7de6236857` and +validates the exact release PR, reviewed tree +`6f9d5ccef4a39ebeb9d53e6019be58fc44f9bafb`, workflow, issue set, registry, +provenance, attestation, tag, and Python 3.12–3.14 identities. + +GitHub Actions posted that receipt identity and closed #167, #168, #169, #170, +and #172. Milestone 11 `v0.9.0` is closed with zero open and five closed issues. +Both local and remote `release/v0.9.0` branches are absent, the worktree is +clean, and the final readback proves +`main == origin/main == v0.9.0^{}` at +`39ff90a5eb58072f4a5ef5ea6657ba4cadbe1bb0`. Stable v0.9.0 delivery and its +external reconciliation are complete. diff --git a/docs/release.md b/docs/release.md index 50ab536..2eeed50 100644 --- a/docs/release.md +++ b/docs/release.md @@ -23,9 +23,10 @@ The delivery sequence is: 4. prepare and merge a protected signed `release/vX.Y.Z` pull request; 5. monitor stable TestPyPI and PyPI publication, annotated tag, provenance, attestations, and immutable GitHub Release; 6. independently compare artifact hashes and smoke-install every supported Python boundary; -7. independently read the immutable `release-receipt.json`, close the tracked issues, and finish the active objective without another repository pull request. +7. independently read the immutable `release-receipt.json` and close the tracked issues and milestone; +8. reconcile the current archived plan and exact external receipts through one protected `no-release` closure pull request without changing the published release. -The release pull request is the final repository mutation. It owns repository-side preparation: stable and next version markers, deterministic source epoch, tracked release authorization metadata, generated Towncrier changelog, release notes, and reconciliation of the execution plan, history index, roadmap, backlog, strategy, and README where applicable. It archives the repository-complete plan with external delivery pending and returns `PLANS.md` to its template state. It must not claim that registry files, provenance, tag, immutable Release, receipt, or installs already exist. +The release pull request is the final repository mutation before stable publication. It owns repository-side preparation: stable and next version markers, deterministic source epoch, tracked release authorization metadata, generated Towncrier changelog, release notes, and reconciliation of the execution plan, history index, roadmap, backlog, strategy, and README where applicable. It archives the repository-complete plan with external delivery pending, leaves `.release-reconciled-version` at the previously reconciled stable version, and returns `PLANS.md` to its template state. It must not claim that registry files, provenance, tag, immutable Release, receipt, or installs already exist. After those facts exist and are independently read back, one documentation-only closure pull request replaces the current release's pending status with exact receipts and advances `.release-reconciled-version` to `.release-version`; it must not alter product/package source, release metadata, tag, stable distributions, hashes, attestations, provenance, or immutable receipt. CI requires the current archive section to be pending while the markers differ and completed when they match. The protected-main merge may run the normal TestPyPI development workflow described below; verify its workflow outcome, but do not treat that development build as another stable release or repeat stable artifact readback. The post-merge workflow executes its authorizer from the protected base SHA that predates the release PR; candidate head and squash-merge commits are inspected @@ -84,7 +85,7 @@ The immutable receipt carries the release PR, reviewed base/head/merge/tree, ori In the release PR, move the complete repository plan to `docs/engineering/execution_history/releases.md` with external delivery pending, link it from the stable-tag row in the [execution-history index](engineering/execution_history/README.md), and return `PLANS.md` to its template state. Review this as ordinary release documentation: preserve the decisions and receipts and keep a usable index link. Byte-exact prose preservation and archive-specific automation are unnecessary because Git retains the original text and trusted-base exact-tree authorization remains the publication boundary. -The immutable receipt and tracked issue comments make the post-merge result discoverable without another repository PR. Publication and independent readback complete delivery externally; they do not rewrite the pending-at-merge historical plan or create a closure PR. Preserve historical dates and receipts, and use stable tags rather than calendar years as lookup keys. +After publication and independent readback, create one protected `no-release` closure pull request. Update only the current release section from pending to completed truth, append the exact immutable release, workflow, tag, receipt, issue, milestone, branch, and synchronized-main evidence, advance `.release-reconciled-version` to the unchanged `.release-version`, and return the temporary closure plan in `PLANS.md` to its template state. Preserve the release-PR handoff as historical context, but do not leave its pre-publication status as the current release status. Do not revise older release sections opportunistically, publish another stable version, or mutate any existing external release object. Use stable tags rather than calendar years as lookup keys. Recovery dispatch is bound to the original release PR, version, merge commit, reviewed head, and protected reviewed base. It executes the same trusted-base diff --git a/tests/test_operations_docs.py b/tests/test_operations_docs.py index fa3c3c7..fab25da 100644 --- a/tests/test_operations_docs.py +++ b/tests/test_operations_docs.py @@ -1,6 +1,7 @@ """Contracts for the public GitLab operations documentation.""" import json +import re from pathlib import Path PROJECT_ROOT = Path(__file__).parents[1] @@ -126,6 +127,60 @@ def test_documentation_indexes_route_to_canonical_owners() -> None: assert "docs/README.md" in readme +def test_release_archive_reconciles_current_external_delivery_truth() -> None: + """Bind the current archive status to the external-reconciliation marker.""" + + release_guide = (PROJECT_ROOT / "docs" / "release.md").read_text(encoding="utf-8") + release_archive = ( + PROJECT_ROOT / "docs" / "engineering" / "execution_history" / "releases.md" + ).read_text(encoding="utf-8") + release_index = ( + PROJECT_ROOT / "docs" / "engineering" / "execution_history" / "README.md" + ).read_text(encoding="utf-8") + release_version = (PROJECT_ROOT / ".release-version").read_text(encoding="utf-8").strip() + reconciled_version = ( + (PROJECT_ROOT / ".release-reconciled-version").read_text(encoding="utf-8").strip() + ) + anchors = list( + re.finditer( + r'^$', + release_archive, + flags=re.MULTILINE, + ) + ) + assert anchors + archive_version = ".".join(anchors[0].groups()) + current_release = release_archive[ + anchors[0].start() : anchors[1].start() if len(anchors) > 1 else None + ] + status_match = re.search(r"^Status: (.+)$", current_release, flags=re.MULTILINE) + assert status_match + current_status = status_match.group(1) + release_version_key = tuple(int(part) for part in release_version.split(".")) + reconciled_version_key = tuple(int(part) for part in reconciled_version.split(".")) + + assert "one protected `no-release` closure pull request" in release_guide + assert "do not leave its pre-publication status as the current release status" in release_guide + assert archive_version == release_version + assert reconciled_version_key <= release_version_key + if reconciled_version == release_version: + assert "completed" in current_status + assert "external reconciliation verified" in current_status + assert "pending" not in current_status + assert "External reconciliation date:" in current_release + else: + assert f"plan-toolkit-{reconciled_version.replace('.', '-')}" in release_archive + assert "pending" in current_status + assert "External reconciliation date:" not in current_release + + current_index_row = next( + line for line in release_index.splitlines() if line.startswith(f"| `v{release_version}`") + ) + if reconciled_version == release_version: + assert "external reconciliation" in current_index_row + assert "stable-delivery handoff" not in current_index_row + + def test_review_signal_audit_keeps_group_data_outside_toolkit_authority() -> None: """Keep the completed BL-017 ownership and privacy conclusion explicit."""