Repository navigation
[Release] Establish changelog-driven fleet release pipeline #1552
Description
Buyer / operator problem
ContextualWisdomLab repositories use a mix of Git Flow (develop as the default integration branch) and GitHub Flow (main/master as the default branch). Many repositories have CI/security/package gates and CHANGELOG.md, but there is no single protected-main organization contract that turns an eligible CHANGELOG.md release section into an immutable software release across the fleet. Repository-local implementations must not drift into dozens of unrelated release engines.
Authority and DDD boundary
.github owns the generic release-governance and reusable GitHub Actions delivery boundary. Product repositories own product version files, packaging/build commands, migration compatibility, buyer acceptance and the decision that a given integrated head is release-eligible. Do not move product/domain behavior into .github and do not duplicate generic changelog parsing/tag/release logic in every product.
If a repository has a product-specific publisher (PyPI/npm/crates.io/GHCR/desktop updater/etc.), keep that adapter in the owning product or an already-existing canonical publishing library; the central workflow should invoke a versioned published contract rather than copy it.
Required branch strategies
GitHub Flow
When the repository default branch is main or master:
- only the exact protected default-branch integrated head may release;
- all applicable current-head CI/security/SAST/coverage/package/SBOM/provenance/review gates must be terminal-success before release authority is granted;
- the top release section in
CHANGELOG.mdis the release-notes and version source; - no release is emitted while only
Unreleasedexists.
Git Flow
When the repository default branch is develop:
- development remains on protected
develop; - production release must be represented by a reviewed integration/release PR from
develop(or a bounded release branch cut from exactdevelop) into the repository's production branchmainormaster; - the release tag/GitHub Release is created only from the exact protected production-branch integrated head after all applicable release gates succeed there;
- do not tag
developas the production release merely because it is the default branch; - if
main/masteris missing, stale, unprotected, or not an admissible production branch, fail closed and open/maintain a repository-scoped branch-governance gap instead of inventing a new convention.
Non-standard defaults
Repositories whose default branch is not develop, main, or master (developmental, release/*, version branch, gh-pages, etc.) must not be auto-released until an ADR/repository contract proves the branch model and a migration or explicit exception is accepted.
CHANGELOG.md contract
Adopt a strict, executable Keep-a-Changelog/SemVer-compatible release contract:
## [Unreleased]may exist but is never released;- the next releasable section must carry one immutable SemVer version and release date;
- release notes must be non-empty and customer/developer meaningful;
- version must be newer than the highest compatible release tag;
- a tag that already exists with a different target fails closed;
- package/application version declarations must agree with the changelog release version when the repository has such declarations;
- release note extraction must be deterministic and covered by tests;
- no heuristic version bumping from commit messages is authoritative when it conflicts with
CHANGELOG.md.
Central reusable release workflow
Create a reusable workflow and executable validator owned here, with tests and doctoring, that at minimum:
- resolves and verifies the exact caller repository/ref/SHA;
- classifies Git Flow vs GitHub Flow from live repository metadata and declared release contract;
- validates branch protection/release eligibility fail-closed;
- parses
CHANGELOG.mddeterministically; - validates version coherence and existing tags/releases;
- consumes repository-provided build/package evidence rather than rebuilding with guessed commands;
- creates an immutable
vX.Y.Ztag and GitHub Release from the same exact integrated SHA; - records source SHA, tree SHA, changelog section hash, artifact digests, SBOM/provenance references and workflow-source SHA in a release receipt;
- supports dry-run/audit mode and idempotent retries;
- never force-pushes, rewrites tags, self-approves, weakens rulesets, fabricates check success, or treats queued/skipped/neutral/cancelled evidence as passing.
Prefer GitHub OIDC/trusted publishing for package registries where supported. Keep registry credentials and provider-specific publication outside the generic domain unless .github is already the canonical owner.
Fleet adoption
After the reusable contract lands:
- inventory every non-archived ContextualWisdomLab repository;
- classify software/package/service vs docs/site/data/reference-only repositories;
- for software repositories, record default branch strategy, production branch,
CHANGELOG.md, current version, release workflows, package/publish surfaces, latest release/tag, and blockers; - add only a thin caller/release contract to repositories lacking a pipeline;
- migrate duplicated generic release logic to the central reusable contract;
- update
docs/product-technical-gap-baseline.mdin each owning repository with release status and branch-model gaps; - release only repositories whose exact integrated head is actually release-ready; do not manufacture releases to satisfy an inventory count.
DDD fitness during adoption
Every release-gap repair must inspect repository/package/module paths against the owning bounded context. If release work exposes generic dumping paths, foreign product code copied locally, outdated product names, cross-context database access, or a locally reimplemented library that has a canonical CWL owner, repair/migrate that responsibility in the same bounded slice when safe; otherwise record the owner/callers/migration sequence and acceptance evidence in the product gap baseline.
Acceptance evidence
- central validator/reusable workflow: 100% production statement/branch coverage and public docstrings;
- deterministic fixture coverage for GitHub Flow, Git Flow, existing-tag idempotency, malformed/future/duplicate changelog versions, stale/unprotected production branch, non-standard default branch, mismatched package version, and missing/queued/failed release gates;
- action dependencies pinned immutably;
- shell/YAML/Python/Rust as applicable pass static analysis;
- no release write from PR/fork-untrusted code;
- at least one real GitHub-Flow repository and one real Git-Flow repository complete a changelog-driven release through the new contract before the fleet capability is considered proven;
- every actual release receipt is bound to one exact source SHA and artifact digest set.
First follow-up inventory
A live 2026-09-01 organization read shows both default-branch families plus non-standard exceptions. Start with the lowest-risk, independently release-ready libraries/services that already have clean packaging and release evidence; do not start with repositories carrying large unresolved PR/release backlogs merely to demonstrate the pipeline.
This issue is the canonical central owner for the generic release-pipeline capability. Product-specific readiness remains owned by each repository.
Activity
seonghobae commentedon Sep 1, 2026
2026-09-01 live fleet evidence
The first audit pass confirms that release adoption must distinguish missing pipeline, pipeline present but blocked, and branch-governance migration rather than creating tags indiscriminately.
EgressWeave — GitHub Flow (
main): repository already has a substantial product-specificrelease.ymlandCHANGELOG.md/SemVer contract. GitHub Releases is still empty, while the protectedmainpackage version remains0.3.0and substantial later work is still inUnreleased. There are currently 27 open PRs, including multiple Draft release-evidence/supply-chain hardening PRs. Do not manufacture a0.3.0tag from current source and do not cut0.4.0until the release-hardening chain and exact release gates are accepted. This is pipeline-present / release-not-ready, not a missing-pipeline repository.ThreadWeave — GitHub Flow (
main): repository-side0.2.0release readiness is integrated. Issue Stop OpenCode bridge waiting after requested changes #17 records the sole remaining prerequisite as external GitHubpypienvironment protection plus the PyPI Trusted Publisher identity; the repository explicitly forbids long-lived-token/manual-upload bypass. This is pipeline-present / external-publisher-identity-blocked. Central adoption must surface this class without trying to solve account authority in source.context-graph-contracts — Git Flow migration (
developdefault): live repository metadata still reportsdevelopas default while the accepted program integration/release target is protectedmain; current stacked PRs explicitly cite.github#1137as owner of that administrative transition. Treat this as a concrete Git Flow proof case only after the production branch is protected and the dependency stack integrates. Never tagdevelopsimply because it is the default branch.Non-standard defaults observed in the organization include
developmental,release/v3.8.50,v8, andgh-pages; keep them fail-closed until each repository has an explicit branch/release ADR.Implementation priority remains: central deterministic changelog/branch eligibility validator + reusable release workflow first; thin repository callers second; first proof releases only from repositories that are independently release-ready. Product-specific PyPI/npm/crates/GHCR publishers stay in their owning repositories/adapters and consume the central eligibility/receipt contract rather than being copied into
.github.seonghobae commentedon Sep 1, 2026
PyPI credential policy correction — 2026-09-01
The organization already has approved PyPI publishing credentials in GitHub Secrets under the exact existing names
PIPY_TOKENandPIPY_USERNAME. Do not read or expose their values.Update the fleet release contract accordingly:
PIPY_USERNAME+PIPY_TOKENpair is available to the protected release job.trusted_publishingorgithub_secret_credentialsexplicitly. Do not guess/fallback after irreversible side effects.github_secret_credentials, inject only through GitHub Actions secrets; never print, persist, include in receipts/provenance/cache keys/job outputs, or expose in command diagnostics.PIPY_*secret names until an accepted migration replaces them. Do not rename the organization secrets merely to correct the historical spelling.ThreadWeave issue #17 has been corrected to this dual-mode contract and should no longer wait solely for external Trusted Publisher configuration.
seonghobae commentedon Sep 1, 2026
2026-09-01 registry credential update — crates.io
CARGO_REGISTRY_TOKENis now registered in ContextualWisdomLab GitHub Secrets and is an approved crates.io publisher credential. Treat its value as non-observable secret material: never print, echo, persist, hash into receipts/provenance, expose through shell tracing, cache keys, job outputs, model jobs, build/test jobs, or diagnostics.Fleet release adoption must now classify Rust packages explicitly:
Cargo.tomlpermit public registry distribution; version must agree with the datedCHANGELOG.mdrelease and immutable tag; requirecargo package --locked/cargo publish --dry-run --locked, full test/clippy/doc/security/license/SBOM/provenance gates, then isolateCARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}to the finalcargo publish --lockedpublisher job;publish = false, fuzz crate, Tauri/application-only crate, internal workspace support crate, example/bench, or package without an accepted public-crate contract. Record this as an intentional distribution boundary, not a failed release;--no-verifyas the normal release path;Current org search found no existing workflow reference to
CARGO_REGISTRY_TOKEN; therefore the first Rust adopter must add the contract deliberately rather than assuming legacy behavior. Existing examples such as Wardnet fuzz packages and DiskSage Tauri application packages withpublish = falseare intentionally excluded from crates.io publication.seonghobae commentedon Sep 1, 2026
Concrete first-consumer handoff from ThreadWeave PR #35 (current release branch work, 2026-09-01):
PIPY_TOKENis materialized only in the fully SHA-pinnedpypa/gh-action-pypi-publishjob;PIPY_USERNAMEis intentionally not injected because API-token publication uses__token__.concurrencyindependent of source SHA) and the credential-minimal readiness stage is the release-authority linearization point. It binds one exact protected integrated source SHA, verifies the current protected production ref at that point, verifies exact integrated checks plus the exact authorizing PR/check identity, resolves version/changelog/public-registry state, and only then permits build/attestation/tag/release/publish.CARGO_REGISTRY_TOKENis available, but token availability must not turn internal crates into public products.fast-mlsirmowner work (fix(noema-review): bound both jobs to a job-level timeout-minutes #1715 / docs: add reusable README template and evidence standard #1694 / ADR-0027) explicitly classifiesmlsirm-coreas an internal Maturin/PyPI numerical core and addspublish = false; therefore it is a negative fixture for the central crates.io classifier, not a publish candidate. Require an explicit accepted public-crate contract before enablingcargo publish.Please incorporate these as executable fixtures/contract tests in the #1552 central reusable release implementation rather than duplicating ThreadWeave-specific workflow code.
seonghobae commentedon Sep 1, 2026
Quarantine Runtime Git-Flow release-governance canary (fresh 2026-09-01):
ContextualWisdomLab/quarantine-sandbox-runtimedefault/integration branch isdevelop; productionmainexists at6d27dba3d5b013b922e21757431330d048a91d70but live branch metadata reportsprotected=false. Stacked release workquarantine-sandbox-runtime#10correctly fail-closes its tag-driven preflight by requiring the tagged SHA to equalorigin/mainandbranches/main.protected == true; therefore the first commercial release cannot be authorized whilemainremains unprotected. This is exactly the Git-Flow branch-governance gap described by #1552, not a reason to tagdevelopor weaken release preflight. RED: default=develop, candidate production=main,main.protected=false, release preflight necessarily rejects. GREEN: establish the repository’s production-branch protection/ruleset formainto the release-grade standard while preserving protecteddevelopintegration; then a reviewed develop/release→main integration can produce one exact protected-main SHA and the product-owned release gate can bind version/CHANGELOG/package/SBOM/provenance/hostile-runtime evidence to it. Do not change quarantine source from the central writer; advance only the generic/repository-governance surface owned here.seonghobae commentedon Sep 1, 2026
Quarantine Git-Flow release-governance handoff — fresh 2026-09-02 KST evidence.
ContextualWisdomLab/quarantine-sandbox-runtimecurrently reports default/protected integrationdevelop@60a85c7633e03b425b67159ec6822c8178cf87ea. Production branchmainexists only at initial commit6d27dba3d5b013b922e21757431330d048a91d70and GitHub reportsprotected=false/ protection disabled. The product release slicequarantine-sandbox-runtime#10is Draft and its tag-driven.github/workflows/release.ymlcorrectly fails closed unless the tagged exact SHA equals protectedmain; its hostile-runtime release gate additionally requires the dedicated rootless Podman + SELinux runner.This matches #1552's Git-Flow branch-governance gap class: do not tag
develop, do not weaken the release preflight, and do not treat the stale unprotectedmainas production authority.RED: a release-eligible exact
developintegration cannot be promoted into an admissible production branch because currentmainis stale and unprotected. GREEN for the central owner path: before the first release candidate, establish protectedmainas the production branch under the repository's live deterministic/security/review policy; require a reviewed exact-develop->mainrelease integration (or the centrally approved bounded release branch model); after integration, run release gates on the exact protectedmainSHA and only then create the immutable tag/GitHub Release. Preservedevelopas the integration default unless a separate accepted branch migration changes that contract. Product-specific readiness and hostile-runner evidence remain owned by the quarantine writer.seonghobae commentedon Sep 20, 2026
Fresh Git Flow consumer evidence from
ContextualWisdomLab/quarantine-sandbox-runtime(2026-09-20): repository metadata still reportsdefault_branch=develop;develop@60a85c7633e03b425b67159ec6822c8178cf87eais protected, whilemain@6d27dba3d5b013b922e21757431330d048a91d70is unprotected. The two refs currently resolve to the same tree, butmainis not admissible release authority.The repository’s Draft release owner #10 is currently test-only
bb587667e049c900f0dec578f083b35ed50f21c7. Its witness was being hardened toward “release from the live default branch,” while production.github/workflows/release.ymlis still hard-coded todevelop. That direction conflicts with this central issue’s Git Flow contract:developis development integration; production tag/GitHub Release must come from an exact protected productionmain/masterintegrated head. I opened product-scopedquarantine-sandbox-runtime#140and am keeping #10 Draft/RED rather than implementing the wrong local GREEN.Fresh QSR ruleset inventory currently exposes only organization branch ruleset
18156473(CWL Central required workflows, targetbranch). This does not establish release/tag immutability. GitHub’s current immutable-release control is separate from branch/tag rulesets and, when enabled, locks the published release assets and associated tag while producing release attestation. The available QSR repository connector cannot read the authenticated immutable-release setting endpoint, so enablement is recorded as unverified rather than guessed.Please include QSR as a concrete Git Flow adoption fixture for #1552: classify
develop+ unprotectedmainas fail-closed, establish/release the central production-branch contract, protect/admit the production branch before use, then let QSR replace duplicated local branch classification with a thin released-contract caller while retaining product-specific Rust package/SBOM/provenance/SELinux evidence. No tag fromdevelop, no mutable central source consumption, and no predecessor status transfer.seonghobae commentedon Sep 20, 2026
QSR consumer evidence update: central release implementation has now surfaced as Draft PR #2260 at exact
dccacc77cd7be310d443b126ea98aec19216c816, and it currently contradicts this issue's Git Flow rule.#2260's reusablerelease-tag.ymlrequires dispatch ongithub.event.repository.default_branchand only provesrelease_commitancestry to that default-branch dispatch SHA. ADR-0032/tests intentionally preserve that default-branch provenance model; package doctoring likewise callscontrol_plane_committhe protected default-branch SHA. Forquarantine-sandbox-runtime, live authority remains default/protecteddevelopwith unprotectedmain, so adopting #2260 as written could authorize a release from develop lineage instead of failing closed on missing protected production authority.I recorded the exact-head finding on #2260 as review
5259865339. Required central RED is a Git Flow consumer fixture (default=develop, production=main`) where develop-only ancestry is rejected; GREEN must distinguish dispatch/control-plane authority from production-release authority and prove the release source exact SHA is on the protected production branch lineage. GitHub Flow repos where default==production should continue to work. Missing/unprotected production authority must remain fail closed.QSR issue #140 now tracks #2260 as the implementation candidate but will not consume the mutable head or copy classification logic locally. #2260 also remains independently blocked by #2261 and existing CO/Noema owner prerequisites.