ci.yaml's toolchain-free job carries two inline Python programs of ~35 lines each β the artefact fences for ub-test-reports (git ls-files packages/ub-test-reports/src | uv run --no-project python -c "β¦", around line 515 at 39b73156) and for sphinx-test-reports (around line 562) β plus the shorter python -c assertions (the toolchain-absent / xdist-present checks, and the same pair in plugin-floor). Marco's review of #2009: scripts of more than three or four lines belong in a dedicated file, so they can run locally as well.
Proposal: one script, tools/src/sn_tools/check_artefacts.py <dist>, run by path like check_workspace.py β it builds the member in the release's shape (uv build --package <dist> --no-sources, sdist then wheel from it), then checks the sdist and wheel against git ls-files packages/<dist>/src with per-member expectations: flit members ship exactly one top-level package (ub-test-reports, ub-project), sphinx-test-reports ships exactly sphinx_test_reports + sphinxcontrib and nothing under sphinxcontrib/ but test_reports/; no tests/ or docs/ in an sdist; the licence file set; the per-member must-ship files (schemas/JUnit.xsd, py.typed). A poe task per member (check-artefacts-<name>) so a developer can run the same fence before pushing. ci.yaml then calls the script, and the inline blocks go. The release.yaml build job could call the same script after its own uv build, so the artefact checked at release time is checked the same way. Keep the two-line assertions inline (they are the fence's fence, and short).
While there: the Lint job's type-gate canary loop (~15 lines of shell) is the other candidate.
ci.yaml'stoolchain-freejob carries two inline Python programs of ~35 lines each β the artefact fences forub-test-reports(git ls-files packages/ub-test-reports/src | uv run --no-project python -c "β¦", around line 515 at39b73156) and forsphinx-test-reports(around line 562) β plus the shorterpython -cassertions (the toolchain-absent / xdist-present checks, and the same pair inplugin-floor). Marco's review of #2009: scripts of more than three or four lines belong in a dedicated file, so they can run locally as well.Proposal: one script,
tools/src/sn_tools/check_artefacts.py <dist>, run by path likecheck_workspace.pyβ it builds the member in the release's shape (uv build --package <dist> --no-sources, sdist then wheel from it), then checks the sdist and wheel againstgit ls-files packages/<dist>/srcwith per-member expectations: flit members ship exactly one top-level package (ub-test-reports,ub-project),sphinx-test-reportsships exactlysphinx_test_reports+sphinxcontriband nothing undersphinxcontrib/buttest_reports/; notests/ordocs/in an sdist; the licence file set; the per-member must-ship files (schemas/JUnit.xsd,py.typed). A poe task per member (check-artefacts-<name>) so a developer can run the same fence before pushing.ci.yamlthen calls the script, and the inline blocks go. Therelease.yamlbuild job could call the same script after its ownuv build, so the artefact checked at release time is checked the same way. Keep the two-line assertions inline (they are the fence's fence, and short).While there: the Lint job's type-gate canary loop (~15 lines of shell) is the other candidate.