Skip to content

Commit 7d3e2ba

Browse files
authored
build: add clean-room package validation (#282)
* build: add clean-room package gate * fix: complete package gate coverage
1 parent 2ec77ad commit 7d3e2ba

9 files changed

Lines changed: 308 additions & 27 deletions

File tree

.maintainer/README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ Commands remain canonical in `AGENTS.md` and `Makefile`; contribution and
1919
architecture policy remain in `CONTRIBUTING.md` and `ARCHITECTURE.md`.
2020
Read the relevant module-level `AGENTS.md` when reviewing its implementation.
2121

22-
Review, triage and Discussions are configured. The owner confirmed `make tag`
23-
as the release trigger. The package-install gate is deferred to
24-
[issue #279](https://github.com/lfnovo/esperanto/issues/279), so release configuration
25-
remains incomplete until that command exists.
22+
Review, triage, Discussions and release are configured. The owner confirmed
23+
`make tag` as the release trigger. `make package-check` is the canonical
24+
clean-room package gate implemented by
25+
[issue #279](https://github.com/lfnovo/esperanto/issues/279).
2626
A valid profile is not evidence that release checks have passed.
2727
Discussions is enabled, with its live category IDs in `profile.toml`.
2828
The application smoke skill does not apply to this library. Real-provider

.maintainer/decisions.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,14 @@ been made by this profile bootstrap.
1818
.github/workflows/publish.yml; verified GitHub settings, categories and labels;
1919
https://github.com/lfnovo/esperanto/issues/279.
2020
- This authorizes profile adoption and repository setup, not a release publication.
21+
22+
## 2026-09-05 — Implement the package gate for 2.27.0
23+
24+
- Decision: implement issue #279 now and make `make package-check` the mandatory
25+
clean-room artifact gate for the 2.27.0 release.
26+
- Decision: the gate verifies fresh wheel and sdist builds, isolated bare
27+
installs, a wheel rebuilt from the sdist, every declared optional extra and
28+
SHA-256 artifact identities.
29+
- Evidence: explicit maintainer approval during the 2.27.0 release session and
30+
local execution of `make package-check` on Python 3.13.11.
31+
- This decision configures the gate; it does not authorize merging or publishing.

.maintainer/profile.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ merge_own_prs = "ask-once-per-session"
5757

5858
[artifacts.pypi]
5959
package = "esperanto"
60-
gate = "TODO implement canonical package-check gate in issue #279; see .maintainer/release/runbook.md"
60+
gate = "make package-check"
6161
surfaces = ["library"]
6262
extras = ["transformers", "validation"]
6363
identity = "sha256"

.maintainer/release/runbook.md

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,19 @@ use the narrower validator documented in AGENTS.md.
1616
Record the candidate SHA, interpreter, command, exit status and evidence. CI's
1717
extra mxbai-rerank install and its Python matrix are documented in test.yml.
1818

19-
## Package gate — missing canonical command
19+
## Package gate
2020

21-
TODO: define and validate a canonical build-and-clean-room-install command in
22-
AGENTS.md or Makefile, then replace artifacts.pypi.gate with its reference.
23-
The owner deferred implementation to [issue #279](https://github.com/lfnovo/esperanto/issues/279).
24-
The existing uv build step in publish.yml is build-only; it cannot satisfy this gate.
21+
Run `make package-check`. The command builds fresh wheel and sdist artifacts in
22+
a temporary directory, checks their metadata and packaged runtime files, and
23+
records SHA-256 identities. It installs the wheel outside the checkout with
24+
isolated Python, verifies a bare import and credential-free factory discovery,
25+
then builds a second wheel from the sdist and repeats the clean-room smoke. It
26+
also resolves the `transformers` and `validation` extras independently. The
27+
existing uv build step in publish.yml is build-only and cannot satisfy this gate.
2528

26-
The gate must build wheel and sdist into a clean output location, check metadata
27-
against the candidate version, inspect packaged assets, install the wheel outside
28-
the checkout with isolated Python imports, import Esperanto and exercise a
29-
credential-free public API call. Confirm optional dependencies stay optional and
30-
that both transformers and validation extras resolve. Verify the sdist can build
31-
an installable wheel. Record SHA-256 identities and actual module origins.
32-
No package-gate pass or release GO is possible until this evidence exists.
29+
Capture the command output as release evidence. It includes the interpreter,
30+
artifact identities and actual module origins. A package-gate pass applies only
31+
to those exact locally built artifacts and candidate revision.
3332

3433
## Bucket C — maintainer-run integrations
3534

@@ -68,8 +67,19 @@ Publish rebuilds the artifacts: distinguish tested local builds from index build
6867
If creating GitHub release notes, attach approved notes to the existing tag and
6968
verify the release page; publish.yml does not create a GitHub Release itself.
7069

71-
TODO: document canonical index-install verification commands alongside the package
72-
gate. This verification completes publication; it cannot run before publication.
70+
Install the exact published version outside the checkout with:
71+
72+
```bash
73+
check_dir="$(mktemp -d)"
74+
cd "$check_dir"
75+
uv run --isolated --no-project --with "esperanto==<version>" \
76+
python -I -c 'import esperanto; print(esperanto.__file__)'
77+
```
78+
79+
Repeat with `esperanto[transformers]==<version>` and
80+
`esperanto[validation]==<version>`, download the wheel and sdist from PyPI, and
81+
record their SHA-256 identities. This verification completes publication; it
82+
cannot run before publication.
7383

7484
## Cleanup
7585

.maintainer/release/test-matrix.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ Record passed, failed, not-run and not-applicable checks with revision and evide
1010
| Default mocked suite | commands.validator -> make test | pytest excludes release marker |
1111
| Lint | commands.ruff -> AGENTS.md | Same check as lint.yml |
1212
| Types | commands.mypy -> AGENTS.md | src/esperanto, as in lint.yml |
13-
| Packaging | artifacts.pypi.gate | Missing canonical clean-room gate; blocks release |
13+
| Packaging | artifacts.pypi.gate -> make package-check | Fresh wheel/sdist, metadata, packaged runtime files, clean-room imports, extras and SHA-256 identities |
1414

1515
The setup target installs all extras. CI additionally installs mxbai-rerank.
1616
CI tests 3.10/3.11/3.12; package metadata also supports 3.13. Track actual coverage.
@@ -24,8 +24,6 @@ Do not claim a provider was exercised merely because a shared base test passed.
2424

2525
## Bucket B — investment candidates
2626

27-
- Implement the package gate described in runbook.md, including wheel/sdist and extras
28-
([issue #279](https://github.com/lfnovo/esperanto/issues/279), deferred by the owner).
2927
- Add Python 3.13 CI coverage if the maintainer elects to cover the full declared range.
3028
- Reconcile the CI-specific mxbai-rerank setup with local validation documentation.
3129

AGENTS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,7 @@ All providers use utility mixins:
242242
- **Run all tests**: `uv run pytest -v`
243243
- **Run specific test**: `uv run pytest tests/providers/llm/test_openai.py -v`
244244
- **Run integration tests**: `uv run pytest tests/integration/ -v`
245+
- **Validate package artifacts**: `make package-check`
245246
- **Check types**: `uv run mypy src/esperanto`
246247
- **Fix lint issues**: `uv run ruff check . --fix`
247248

CONTRIBUTING.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -248,10 +248,13 @@ Run the release suite **before tagging a release** — it's the last gate that c
248248
3. Run `uv run pytest` (default, mocked) — must be green.
249249
4. Run `uv run ruff check .` and `uv run mypy src/esperanto` — must be green.
250250
5. **Run `uv run pytest -m release`** — must be green or have only known-tracked xfails.
251-
6. Bump version, commit, tag, push tag.
252-
7. Build + publish.
251+
6. Bump the version, regenerate `uv.lock`, and run `make package-check` against
252+
the exact candidate — its clean-room wheel/sdist checks must be green.
253+
7. Commit the release cut, then repeat any gate invalidated by that commit.
254+
8. After the explicit release GO, run `make tag`; its tag push triggers the
255+
publish workflow.
253256

254-
If step 5 surfaces a real regression, the release waits.
257+
If a gate surfaces a real regression, the release waits.
255258

256259
**6. Audio fixture**
257260

Makefile

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
.PHONY: setup ruff lint test
1+
.PHONY: setup ruff lint test package-check
22

33
setup:
44
uv venv
@@ -13,6 +13,9 @@ ruff:
1313
test:
1414
uv run pytest -v
1515

16+
package-check:
17+
uv run python scripts/package_check.py
18+
1619

1720
build-docs:
1821
repomix . --include "**/*.py" --compress --style xml -o ai_docs/all_docs.txt
@@ -23,4 +26,3 @@ tag:
2326
echo "Creating tag v$$version"; \
2427
git tag "v$$version"; \
2528
git push origin "v$$version"
26-

0 commit comments

Comments
 (0)