diff --git a/.claude/skills/intentumdiff-release/SKILL.md b/.claude/skills/intentumdiff-release/SKILL.md index 51ca2c6..3d5c319 100644 --- a/.claude/skills/intentumdiff-release/SKILL.md +++ b/.claude/skills/intentumdiff-release/SKILL.md @@ -63,6 +63,120 @@ impossible. 3. Tag from `main`; the tag triggers publication 4. Open the next RC branch immediately, so in-flight work has a base +## Definition of ready to release + +**Nothing is published until every box below is ticked.** Not "mostly", not "the important +ones" — all of them. This list exists because 0.0.1 was published with green CI and had to +be pulled from three registries within a day. + +If a box cannot be ticked, the release does not happen. The correct response to schedule +pressure is a later release, never a lower bar. + +### Artefact + +- [ ] `smoke_published_wheel.py` passes against a **locally built** artefact +- [ ] Every check inside it passes — install, import, console script, `python -m`, a real + diff, **clean stderr**, **all URLs resolve** +- [ ] The extension VSIX installs into a **clean VS Code profile** and works there +- [ ] Extension host log is clean — no errors, no warnings about missing files +- [ ] Tested on every platform the artefact claims to support + +### Docs + +- [ ] Documentation site is **live**, not planned +- [ ] **Every** example in **every** README has been extracted and run verbatim, and its + real output matches what the doc claims +- [ ] **Every** link in user-facing docs resolves — READMEs, error messages, `--help`, + the Marketplace listing +- [ ] No reference to a page, domain or command that does not exist +- [ ] Demo media shows the CURRENT build, not an older UI + +### Correctness + +- [ ] Full test suite green in every affected repo, run in **that** repo +- [ ] The headline claim demonstrably works on a real repository — not a fixture +- [ ] Known limitations are written down and honest. A missing capability documented is + fine; one implied to work is not +- [ ] No regression against the previous release on a real-world diff + +### Release hygiene + +- [ ] Version is a **prerelease** unless the artefact has been used in anger +- [ ] Tag matches the manifest exactly +- [ ] CHANGELOG says what changed, in the user's terms +- [ ] Prior broken versions yanked or unpublished +- [ ] A rollback plan exists — and note that for PyPI and the marketplaces, "rollback" + means yank plus a new version, never delete + +### The rule behind the list + +**Green CI is not evidence a product works.** It is evidence the code compiles and the +tests we thought to write pass. Every 0.0.1 defect passed CI and was obvious thirty seconds +after installing the package. + +Before publishing, someone must install the artefact and use it the way the README says to. +Every time. No exceptions, however small the change looks. + +## MANDATORY: smoke-test the artefact before any publish + +**CI proves the code builds. It does not prove the artefact works.** These are different +claims, and only the second one matters to a user. + +IntentumDiff **0.0.1 shipped broken and had to be pulled from PyPI and both extension +marketplaces**, despite every check being green. Four defects, all invisible to CI and all +obvious within thirty seconds of installing the published package: + +| Defect | Why CI could not see it | +|---|---| +| ~69 "Failed to catalog parser plugin" errors on every run | the distribution name was missing from the package's own first-party trust list; in a source checkout the distribution resolves differently and the check passes | +| `python -m intentumdiff` failed | no `__main__.py`; nothing in CI invoked it | +| Error message linked to an unregistered domain | no test followed a documented URL | +| README's headline example raised `NameError` | it was a fragment; nothing ever ran it | + +None of these is exotic. All four were found by installing the wheel and typing what the +README says to type. + +### The gate + +Before tagging **any** release: + +```bash +python scripts/smoke_published_wheel.py --wheel dist/.whl # pre-publish +python scripts/smoke_published_wheel.py # post-publish +``` + +It installs into a clean venv and checks what a user does in their first five minutes: +install, import, console script, `python -m`, a real diff, **clean stderr**, and that +**every URL in the output resolves**. + +Two of those deserve emphasis, because exit codes hide both: + +- **Clean stderr.** 0.0.1 returned correct results *and* printed 69 errors. Exit code 0. +- **Live URLs.** A link in an error message is a promise; a dead one is worse than none. + +### Beyond the script + +The script is the floor, not the ceiling. Also required before a release: + +- **Run every example in every README verbatim.** Extract the code block, execute it, + compare against the documented output. A fragment that cannot run is a broken example. +- **Follow every link in user-facing docs.** Dead links are how docs rot silently. +- **Exercise the extension in a vanilla VS Code**, not a dev host — a clean profile, no + workspace settings, no other extensions. +- **Confirm the claimed feature actually works.** Not "the code path is covered" — install + it and watch it do the thing. + +## Ship beta first + +The first release of anything user-facing is a **prerelease**: `0.0.2b1`, `0.0.2-beta.1`. + +A version without a beta marker is a claim of stability. Make that claim after the artefact +has been installed and used, never before — the cost of retracting it is far higher than +the cost of a `b1` suffix. PyPI cannot delete a version and a Marketplace listing cannot be +overwritten, so "we can fix it in the next one" is not a recovery plan. + +Promote to a stable version only once the beta has been smoke-tested and actually used. + ## Version rules - The tag **must** match the version in the manifest — `pyproject.toml`, `package.json`, diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index eac3770..e77e0cd 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -230,7 +230,7 @@ jobs: with: persist-credentials: false - - uses: actions/download-artifact@c850b930e6ba138125429b7e5c93fc707a7f8427 # v4.1.4 + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: pattern: dist-* path: downloaded-dist/ @@ -295,7 +295,7 @@ jobs: with: persist-credentials: false - - uses: actions/download-artifact@c850b930e6ba138125429b7e5c93fc707a7f8427 # v4.1.4 + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: pattern: dist-* path: downloaded-dist/