Uh oh!
There was an error while loading. Please reload this page.
release-train: develop -> staging - #217
Merged
Merged
Conversation
…ller exists (backend#1681) (#209) * feat(inventory): assert WHICH checks are required, not just that a caller exists (backend#1681) The guard opened `required_status_checks`, kept `strict`, and threw the rest away. So `required` has meant "a caller workflow exists somewhere in this repo", never "this check can block a merge" -- and the two are not the same thing. What that cost, measured 2026-08-11: * `.github/staging` required exactly ONE context (`actionlint`) while the inventory reported it conformant. Two release-train promotions merged with the contract audit RED -- .github#203 (-> staging) and #205 (-> main), both with `audit` and `gate` at conclusion=failure. * `quality / gitleaks` is required on 16/16 develops but only 13/16 staging and prod, and the three gaps are public repos. This adds `required_checks` as a per-branch-role policy key: * READ from BOTH protection systems and BOTH API spellings -- classic `checks` (modern) and `contexts` (legacy), plus ruleset-supplied `required_status_checks`. Reading only the modern spelling would report a branch's required set as EMPTY, which is the fail-open shape this guard exists to eliminate. * COMPARED AS A SUBSET, not equality: backend's Django suite and cli's golangci-lint sit on top of the baseline legitimately. The policy is a floor. * SCHEMA-ENFORCED, so a missing value is a failure rather than a default, and `divergent` may narrow the set only with a written reason naming it. Baselines are the measured status quo, not aspiration: develop asserts the three contexts already required in all 16 repos; staging/prod assert fr-gate plus the two content gates. The real gaps become NAMED divergences instead of silence -- `docs` ([], its 2026-06-04 exemption is broader than review alone), `model-zoo` and `start-training` (["gate / gate"], content gates missing on both promotion branches). `quality / action-pins` is deliberately NOT in the staging/prod baseline: 16/16 on develop and 0/32 on promotion branches is an asymmetry nobody has decided, so the file records the question rather than blessing it. Its first live run also surfaced three postures nobody had stated: claude-skills, release-train and rfcs carry a `divergent` prod cell for being working branches, which never said anything about required checks, so they inherited a baseline naming the fr-gate -- a gate that only exists on a promotion pipeline they do not have. Now written down. release-train states its REAL set (actionlint, mutation, shell) rather than [], since it is the tool that performs every promotion. Verified, not asserted: * selftest 86 -> 97 pass, 0 fail. The load-bearing case is "a check that runs but cannot block IS a finding"; also covered are subset-not-equality, the legacy spelling, ruleset-supplied contexts, a divergent cell judged against its own list (and still failing when that list is unmet), and four schema shapes that would silently assert less than they appear to. * LIVE against all 20 repos: "No drift. Every repo read, every entry matched." * MUTATION: the same run with one impossible context added to the develop baseline produces 16 findings, one per repo carrying that role, each naming it. Green here means something because red is reachable. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * style(caller-drift): drop a duplicated comment block (Bugbot, .github#209) My edit adding `required_checks` to OVERRIDABLE re-emitted the explanatory comment that was already above it. Comment-only; no behaviour change. Selftest re-run: 97 pass, 0 fail. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…d (backend#1668) (#215) `.github`'s own entry said "action-pins itself stays unarmed until #159 reaches main". #159 reached main and action-pins was armed on 2026-08-06 (backend#1603 step 2), but the line was never updated -- so the single source of truth denied a control the repo actually has. Measured on origin/develop: this repo's `code-quality-caller.yml` passes `action-pins: true` + `action-pins-soft-fail: false`, and `quality / action-pins` is a REQUIRED status check on develop. The original caveat is kept rather than deleted, because it explains WHY arming had to wait: a caller may only pass inputs the @main callee declares, or the whole call dies with startup_failure. Comment-only; selftest re-run: 97 pass, 0 fail. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…end#1681) (#213) * fix(conformance-gate): the gate was not in its own GUARDED list (backend#1681) A PR touching ONLY `.github/workflows/conformance-gate.yml` matched nothing in GUARDED, took the "does not touch the repo contract" branch and exited 0. So the gate could be defanged on a green check -- drop `repo-inventory.yml` from the list, or replace the poll with `exit 0` -- and a FOLLOW-UP PR then edited the contract against a gate that no longer guarded it. Two PRs, both green, no audit ever demanded. Adding the file to its own list closes that path: a change to the gate now requires caller-drift to have PASSED on that exact head, the same as a change to the inventory or the checker. Verified offline against the real matcher (`grep -qxF` over the changed-file list), both directions: a gate-only PR now yields TOUCHED=conformance-gate.yml, an unrelated PR still yields nothing, and a near-miss path (`workflows/conformance-gate.yml`) correctly does not match, since the comparison is whole-line. This PR is also its own live test - it touches the file it adds, so the gate must now demand the audit on it. NOT claimed, and written into the file so nobody reads more into it: `pull_request` workflows run from the PR's merge ref, so the gate evaluating a PR is that PR's version of the gate, and caller-drift.py is likewise supplied by the head. This family's integrity still rests on the required human review. This removes the SILENT path; it does not make the gate self-hosting. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(caller-drift): trigger on conformance-gate.yml too (Bugbot #213) --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…ntory list (backend#1681) (#214) `reusables` is a hand-written list and the audit iterates it, so a reusable added to tracebloc/.github but never added to that list was compared against no repo and reported by nothing. That is the one direction of drift this guard could not see: it checked that every LISTED reusable is handled, never that every SHIPPED reusable is listed. `version-bump-pr.yml` is how it surfaced. It exists, has ZERO callers org-wide, and cannot be called as written -- it requires a `pr-token` secret no repo supplies. It is Layer 2 of backend#1563, the automated post-release bump-PR opener meant to prevent the version staleness that stalled tracebloc-py-package's prod leg (backend#1561). It shipped, was never wired up, and nothing said so. `check_source_reusables()` now walks the source workflow directory, parses each file, and refuses in BOTH directions: * a `workflow_call` workflow absent from the list (checked against nobody) * a listed name that is not a reusable there (a rename or delete leaves every repo's row asserting a ghost) Deliberately a die(), not a finding: the inventory is the contract, and a contract that does not mention half the artifacts it governs cannot be audited against. `on:` is read as both `"on"` and `True`, because YAML 1.1 parses the bare key as a boolean. version-bump-pr.yml is now listed and exempt in all 20 repos behind one shared reason that states plainly that it was never wired -- the same posture as wip-limit-check. That turns an invisible gap into a written decision: wire it or delete it. Verified: * selftest 97 -> 102 pass, 0 fail. New cases: an unlisted reusable is refused, a listed-but-absent one is refused, a push-triggered workflow is correctly NOT demanded, a missing workflows dir is refused rather than passed, and a fully-tracked tree passes. * Against the real source dir BEFORE the inventory rows: died naming version-bump-pr.yml. AFTER: passes. * Mutation: removing any single entry from the list makes it die (exit 2). * ruff --isolated --select E4,E7,E9,F scripts/ -> All checks passed! Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
LukasWodka
commented
Aug 11, 2026
ContributorAuthor
bugbot run |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 5075572. Configure here.
Uh oh!
There was an error while loading. Please reload this page.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Automated promotion by the release train (RFC-0008 D14). Head is the train-managed
release-train/to-stagingbranch (a mirror ofdevelop), so it never collides with a human PR. Merged only when the fr-gate is green.Note
High Risk
Changes branch-protection contract enforcement and CI gate behavior org-wide; misconfigured
required_checksor gate paths could block merges or allow contract edits without audit until fixed.Overview
backend#1681 tightens the org repo contract and the drift guard so promotion branches cannot look compliant while checks only run (not block), and so the conformance gate cannot be weakened in a green-only PR.
repo-inventory.ymladds fleetrequired_checksbaselines per branch role (develop vs staging/prod), documents narrower sets viadivergentcells (e.g. model-zoo, start-training, docs, release-train), listsversion-bump-pr.ymlwith org-wideexemptreasons, and corrects stale.githubnotes on armed action-pins.caller-drift.pynow unions required status contexts from classic protection (bothchecksand legacycontexts) and rulesets, enforces inventoryrequired_checksas a floor (subset, not exact match), andcheck_source_reusablesfails startup if anyworkflow_callin the source repo is missing from or phantom inreusables.Conformance gate includes itself in
GUARDEDand caller-drift path filters includeconformance-gate.yml, closing the two-PR path where only the gate file changed and no audit ran. Selftests coverrequired_checksand source reusable enumeration.Reviewed by Cursor Bugbot for commit 5075572. Bugbot is set up for automated code reviews on this repo. Configure here.