Contributing and documentation¶
Start with the repository AGENTS.md contract. Architectural work follows the
reusable .github/skills/architecture-review/SKILL.md audit; documentation scope is
selected with .github/skills/docs/SKILL.md. These checklists point to canonical
code and documentation rather than duplicating the architecture.
Build and test¶
Use the environment-provided Qt and Slang SDKs. The normal native checks are CTest and the Python tests configured by CI. Do not introduce compiler subprocesses or a Python render-core mirror.
Teaching documentation¶
Authored text lives in src/docs. Screenshots and Sphinx HTML are generated
artifacts: neither belongs in Git. A single command performs the required native
capture, image-manifest validation, and warning-as-error Sphinx build:
python -m pip install -r src/docs/requirements.txt
python -m ci.build_docs --output build/documentation/site
The helper writes temporary captures to ignored src/docs/images before Sphinx
copies the same verified files into the site. Pull requests upload that complete
site as a Documentation Preview Artifact. The native build remains read-only.
A same-repository PR may pass that already-built artifact to the dedicated publisher
and update /dev/; a fork PR can never enter the write-enabled job.
Publication and versioning¶
The canonical public entry point is https://samjay3d.github.io/miskeyed-workbench/. Generated output is
committed only to the disposable docs deployment branch. A release publishes an immutable
version directory such as /0.3.0/ and updates the root redirect to that version.
Existing version directories are preserved. Trusted pushes to main or
release/** and same-repository PRs use the same built artifact to replace the
mutable /dev/ site. Fork PRs remain artifact-only.
The generated branch layout is:
index.html stable redirect to the current release
.nojekyll
dev/ mutable trusted development site
X.Y.Z/ immutable release site
next-version/ future immutable release, without deleting X.Y.Z
previews/ reserved for a future explicit trusted-preview policy
Sphinx names copied image assets _images/ inside each complete site, alongside
_static/, architecture, Slang, rendering, and tool pages.
One-time maintainer setup is required before publishing the package. Open
Settings → Pages and choose GitHub Actions as the deployment source. The
publisher keeps the docs branch as generated history, then uploads that complete
tree with actions/upload-pages-artifact and deploys it with
actions/deploy-pages. It does not rely on the GITHUB_TOKEN branch push to
trigger Pages. Native build/test jobs and fork PRs never receive publication
permission. Only the dedicated publisher job receives contents: write,
pages: write, and id-token: write. Branch rules must allow GITHUB_TOKEN to
update the generated branch.
GitHub creates the github-pages environment automatically when the Actions source
is configured; maintainers do not need to pre-create it. Do not add required reviewers,
because that would introduce a manual release gate. If deployment branch/tag rules are
enabled, allow main and any intentionally pushed v* tags used by the manual
re-release path.
The environment is shared by development and release publication jobs. Only a trusted
main push replaces https://samjay3d.github.io/miskeyed-workbench/dev/ and performs a development deployment;
pull requests retain their reviewable documentation artifact without publishing the
repository’s live site. The mutable /dev/ gate verifies the build, screenshots,
generated branch contents, Pages artifact, and explicit deployment. Immutable release
publication additionally retains the stricter public-URL check before TestPyPI and PyPI.
The release gate runs in this order: detect the release; build distributions; install
the Windows 3.11 release wheel; capture and verify images; build Sphinx; update and
verify the docs history branch; upload and deploy the complete Pages site; retry
the public URL while Pages propagates; publish TestPyPI; publish PyPI; then create the
tag and GitHub Release with a link to
the immutable /<version>/ documentation. A documentation failure therefore blocks
the package release.
Release work¶
Release distributions cross an explicit candidate boundary. The reusable
build-distributions.yml workflow builds and validates the native matrix, then seals
the uniquely named wheel transports, sdist, validation identities, source SHA, version,
and SHA-256 digests into the release-candidate artifact. Candidate artifacts are
retained for 60 days. Publication consumes that envelope through
ci/assemble_release.py; it does not rediscover or flatten matrix payloads.
If TestPyPI, PyPI, or tag creation fails after the candidate was sealed, dispatch the
release workflow from the Actions page. Supply the failed source run ID and expected
version and source SHA. GitHub’s artifact action retrieves the named candidate directly
from that run; no custom run-discovery layer sits in front of it. The candidate manifest
must identify this repository and release.yml on main or release/*. The
Workbench assembler checks those identities, all digests, tar safety, wheel identities,
and wheel CRCs before it
promotes anything. The manifest must contain all 12 Windows, Linux, macOS arm64, and
macOS x64 wheels for Python 3.11–3.13. Resume invokes no compiler, Qt SDK, Slang SDK,
or native matrix job and retains the existing release.yml trusted-publisher identity.
TestPyPI and PyPI use skip-existing behavior; an existing tag/release is accepted only
when it identifies the candidate source commit.
GitHub’s Re-run failed jobs and a dispatched release resume are intentionally different. A rerun uses the original run’s source SHA and workflow definition. Resume uses the current, corrected publication workflow with the old immutable candidate. Use resume when publication orchestration itself has been fixed. An expired artifact, a different manifest/version/SHA, a failed source run, or a disallowed source branch must be rebuilt rather than bypassed.
Product/package inputs (cpp/**, bindings/**, shaders/**,
python/miskeyed/**, CMake/package metadata, installed contracts, and the candidate
build workflow) invalidate the native candidate. Publication helpers/workflows and
documentation orchestration run their focused Python or documentation checks without
starting the release matrix. Documentation changes still rebuild and verify the site.
Read release health by evidence level: Package is a produced wheel, Installed
is a fresh-environment install/import, Contracts is the installed-package or native
contract suite, and Runtime is an actual QRhi draw through
miskeyed-workbench --rhi <backend> --rhi-smoke-test. A release support claim must
have a passing lane at the claimed level. Checkout-dependent architecture tests stay
in the source-tree suite; the installed-wheel suite must exercise only public package
behavior and packaged resources. Runner and ICD setup belongs in the workflow.
Validation follows a three-level confidence ladder. Ordinary development PRs run the
focused Python 3.11 source/native checks. A push to, or PR targeting, any release/*
branch additionally runs Release Stabilization across Windows, Linux, and both macOS
architectures on
Python 3.11 and 3.13; Python 3.11 owns native contracts and runtime smoke, while 3.13
proves the newest supported wheel and installed contracts. Any PR targeting main
and every push to main runs Main Integration, the exhaustive Python 3.11–3.13
distribution matrix. Stabilization is read-only and can never publish. Release detection
after the main gate alone decides whether immutable docs, TestPyPI, PyPI, a tag, and a
GitHub Release follow.
Branch protection requires the stable aggregate CI check. Confidence labels remain on
the component jobs so changing a destination label cannot leave the required context
waiting for a name that no workflow emits.
Keep CHANGELOG.md release-oriented, update the single package version in
pyproject.toml, run native/package checks, regenerate images, and build Sphinx
with warnings as errors. Deployment permissions are intentionally outside the docs
check.
Ordinary post-release work belongs under [Unreleased]. Work explicitly included in
an active release belongs in that release record. Do not encode one version’s state as
a permanent contributor rule; the prepare-release skill handles the mechanical
transition when a release is cut.