Releases and versioning¶
ctower uses Semantic Versioning and Release Please. The repository currently records
version 0.21.0. The authored HTTP contract still records 0.0.0 because it makes no compatibility
promise. Neither number means that a supported product release exists.
The private-VPS E2 shadow path builds and verifies a wheel plus runtime manifest from source, but neither is
published and the release workflow does not deploy them. A release contains the tagged source tree,
generated changelog, and GitHub release notes only.
Public API¶
The public API is any documented surface that users or external integrations are expected to depend on. It includes:
- published HTTP and event contracts;
- CLI commands, flags, output schemas, and exit behavior;
- versioned workflow, policy, extension, and adapter contracts;
- supported configuration keys and environment variables;
- persisted formats that promise import, export, backup, or restore compatibility.
Internal modules, database tables, generated implementation details, experimental surfaces explicitly marked unstable, and unpublished design proposals are not public API. A surface does not become public merely because it is visible in the source tree.
VERSION is the canonical repository release version. .release-please-manifest.json is
Release Please's tracking state; the root package.json and pyproject.toml versions mirror
VERSION for workspace tooling and do not imply npm or Python package publication. The release
pull request updates all four values atomically, and just check rejects version drift.
SemVer policy¶
fix:is a backward-compatible correction and proposes a patch release.feat:is backward-compatible functionality and proposes a minor release.type!:or aBREAKING CHANGE:footer proposes a major release.- Other accepted Conventional Commit types may appear in release notes but do not necessarily cause a release on their own.
Versions before 1.0.0 describe an actively developing public API. Minor releases may make
breaking changes when they are clearly documented; patch releases remain backward compatible
within their minor line. 0.x.y is pre-1.0 maturity, not a SemVer prerelease suffix. If the
project later publishes preview builds such as 1.0.0-rc.1, Release Please prerelease mode
must first be enabled by a reviewed configuration change.
Pull request and release flow¶
- Give every pull request a Conventional Commit title, for example
feat(cli): add ticket assignmentorfix(workflow): preserve retry lineage. - Merge with squash merge so that the validated pull request title becomes the commit on
main. The title check is therefore part of the release contract, not cosmetic lint. - Release Please reads releasable commits on
mainand creates or updates one release pull request. That pull request owns the proposedVERSIONandCHANGELOG.mdchanges. - Review the generated version and notes. The release pull request must pass the same required verification, documentation build, and review checks as any other pull request.
- Merge the release pull request. Release Please then creates the immutable
vX.Y.Ztag and the matching GitHub Release. This pipeline does not publish packages or deploy ctower. - Verify that the tag targets the release pull request merge commit, the GitHub Release notes
match
CHANGELOG.md, and the public documentation build for that commit succeeds.
The write-capable Release Please job has no manual trigger. It runs only for an exact push to
refs/heads/main in simjak/ctower; its job-level guard must remain in place even if trigger syntax is
edited later.
Do not edit VERSION or create release tags manually during normal operation. An exceptional
operator-directed version uses Release Please's documented Release-As: X.Y.Z commit footer and
still flows through a reviewed release pull request.
Documentation release gate¶
A stale or overclaiming document blocks release. Before merging a release pull request:
- build the site with
just docs-check(mkdocs build --strictin an external temporary directory); - update current-state guidance for every changed public surface;
- regenerate inventories and reference material from verified source truth where applicable;
- distinguish proven behavior from planned or residual work, live behavior from snapshots, and wired functionality from placeholders;
- include migration and rollback guidance for compatibility-affecting changes;
- use repository-relative links and include no secrets or personally identifiable information.
For authored contracts, the current deterministic code-truth path starts at
contracts/traceability/sources.json. Run python3 -m tools.checks.traceability --root . --write to update
generated/traceability-index.json and its manifest entry, then run the same command with --check as the
release gate. Narrative pages remain authored and must be reviewed against the changed code and contracts.
GitHub Pages is built on every pull request but deployed only from trusted main. A successful
page deployment proves publication, not runtime correctness.
Verification provenance¶
The required release gate job is safe for public fork pull requests: it has read-only repository
permission, receives no repository secrets, checks out complete candidate history without persisted
credentials, and invokes the canonical just check and just verify recipes. Python dependencies are
installed from the hash-locked requirements/verify.txt; JavaScript uses the frozen pnpm-lock.yaml with
lifecycle scripts disabled. Node distributions and the pnpm, just, Actionlint, and Gitleaks release assets
are fetched with bounded HTTPS requests and checked against committed SHA-256 values before execution.
Those versions describe the verification host only. They do not select a supported ctower Python runtime, create a product lock, or supersede D6. Update a binary pin only from the producer's release checksum or release-asset digest, update its version and digest together, and let the repository supply-chain tests prove the linkage. Remote GitHub Actions and pre-commit hooks remain pinned to immutable 40-character commits.
Corrections, rollback, and withdrawal¶
Published version numbers, tags, changelog entries, and release assets are immutable: never move a tag, replace an asset under the same version, or reuse a version number.
- For a normal defect, revert the deployment if one exists, fix forward, and publish a new patch or otherwise SemVer-appropriate version.
- For incorrect release notes or documentation, correct them in source and publish the correction in a newer release. GitHub release prose may add a prominent pointer to the correction, but it must not erase the historical record.
- GitHub has no package yank in the current source-only release posture. If package publication is added later, each registry's deprecation or yank mechanism must be documented before use; a withdrawn version is never republished.
- If continued distribution would expose a secret, personal data, or an active vulnerability, invoke the security incident process and restrict access as necessary. Record the exception, rotate affected credentials, publish a replacement version, and never reuse the compromised version number.
Runtime deployment rollback is separate from source release history. Point the environment at a previous verified immutable artifact; do not mutate the release that produced it.
Required repository settings¶
After the workflows reach GitHub, a maintainer must:
- set Pages source to GitHub Actions and restrict the
github-pagesenvironment tomain; - add a fine-grained
RELEASE_PLEASE_TOKENActions secret with repository Contents, Issues, and Pull requests read/write access. The workflow safely falls back toGITHUB_TOKEN, so an unset secret does not make everymainbuild fail; however, pull requests created by that fallback token do not trigger their own required verification workflows. Without the secret, a maintainer must cause a fresh pull-request event (for example, close and reopen the release PR) before it can satisfy branch protection; - require the stable
release gate,build documentation, andconventional titlechecks onmain; - enable squash merge and use the pull request title as the default squash commit title;
- prevent force pushes and tag deletion for released versions.