Release 2.1.252 (2026-10-21)¶
Bug fixes¶
- update instead of aborting on stale failed checks when BEHIND (#3359) The failed-checks gate in wait_and_merge ran before the post-wait BEHIND recheck. When the lazily-computed mergeStateStatus missed a freshly-behind branch at the loop-top precheck, wait() returned at once on the already terminal (stale) checks and a stale red check hard-aborted the merge, never reaching the update-and-retry path from #2856.
Before aborting on failed checks, re-check BEHIND; if the branch is behind, update it via _update_or_abort() (update-branch cancels the stale runs and starts fresh ones) and loop, bounded by the shared _MAX_BRANCH_UPDATES cap. A failure on a current branch still aborts.
- pin confirm-develop to the back-merge commit, not the develop tip (#3360) confirm-develop polled for the CD run of the current origin/develop tip. On vrg-release --resume the tip can have moved (a dependency-update or feature PR merged after the back-merge), so the stage verified, or waited on and failed over, a run unrelated to the release.
back-merge-bump now records the back-merge PR's merge commit (mergeCommit.oid via github.merge_commit_sha) on ReleaseContext on every path: create, adopt-open and adopt-merged. The context is not persisted; a resume re-runs back-merge-bump, which adopts the PR and records the SHA again. confirm-develop polls for that SHA's run and fails loudly when none was recorded, with no fallback to the tip. confirm-main is unchanged.
close-finalize now runs vrg-finalize-pr with --no-wait-cd. Its cleanup-only cd-check has no merge to pin to and would watch the develop tip, with the same problem. confirm-develop has already verified the right run, finalize is reached only when it passed, and the second wait would also re-fail on a docs failure confirm-develop deferred. Documented in the release guide.
- resolve a leftover deps/update branch by its PR state instead of refusing (#3363)
vrg-update-deps preflight refused whenever deps/update-
existed locally or on origin, treating it as in flight. A branch can outlive its PR: GitHub's delete-on-merge never applies to a PR closed without merging, and occasionally skips its after-merge processing. A re-run at the same version, including the update-deps stage of vrg-release --resume, then failed even though nothing was in flight.
Preflight now looks up the branch's PRs (the vrg-branch-sweep helpers). If the newest PR merged, the update for that version is done: preflight reports it and the run exits 0 without updating, and the vrg-release update-deps stage records it as done rather than failed. If it was closed without merging, the stale branch is deleted on origin and locally, by name, and the update runs. An open PR, no PR, an unexpected state, or a tip that is not the last PR's head still refuses as in flight.
After merging its PR, the merge stage now deletes the branch on origin as its own API step (already-deleted is fine; a failure warns without failing the run). It does not pass gh pr merge --delete-branch: github.merge is shared, and gh would also try to switch the linked worktree off the branch, which can fail after a successful merge.
- fail loudly when scripts/bin/validate-custom is not executable (#3364) _find_custom_validator only returned scripts/bin/validate-custom when it was an executable regular file, so a script that lost its executable bit was treated exactly like an absent one: the custom stage vanished and vrg-validate reported green without running the repo's own gates.
Discovery now returns anything present at that path, and the custom stage checks it first (_check_custom_validator), failing with the path and the fix (chmod +x and commit the mode change) when it is not executable or not a regular file. An absent script is still a no-op.
-
stop reporting a stale in_progress CD job as a failed publish (#3366) Releasing vergil-vm v2.1.47, every step of release / package-matrix ran but the jobs API kept reporting it in_progress with a null conclusion after the run concluded success. _collect_deferred_publish counted the null conclusion as a failure and collapsed it to its family, so vrg-release reported 'CD publish jobs did not succeed: release', held the consumer refresh and left the tracking issue open for a fully delivered release.
-
The settle wait now waits, within the same bounded budget, for every job to reach completed, not only the release (or docs) job.
- Only completed jobs are judged as failed. A job still non-terminal after
the budget is checked against the run-level conclusion: under success the
record is stale, reported by name as a warning and never deferred; under
any other conclusion it is deferred as '
(never settled)'. - A failed job in the release job's own family is reported by its full name, so the message cannot read as the release itself failing.
- One combined stage warning, since mark_warn is last-call-wins.
-
The release guide documents stale job records.
-
detect stale check-runs while waiting, not only at the deadline (#3374)
- fix(github): detect stale check-runs while waiting, not only at the deadline
wait_for_checks now probes each pending Actions check's backing run (throttled to every 30s per run). A check still pending 60s after its run completed is decided by the backing job's own conclusion: success passes it with a named warning; any other or unreadable conclusion raises OrphanedCheckError at once. The deadline stays the backstop. Ref #3358
-
docs(finalize-pr): document in-wait stale check-run detection
-
ensure issue labels exist at the point of use (#3378) vrg-triage-create and vrg-issue-create now create every label they apply in the target repo, from data/labels.json, before creating the issue, so a repo that was never label-synced no longer fails with '
-
resolve the Conan audit token from its file at point of use (#3380) vrg-container-run now resolves CONAN_AUDIT_PROVIDER_TOKEN_CONANCENTER itself for cpp repos instead of relying on the ambient environment, which only an interactive bash sourcing ~/.bashrc populated. Precedence: a non-blank env var wins, then ~/.config/vergil/conan.env, then the conan_audit_token_path file in identities.toml. A source that exists but is unreadable, malformed or empty fails loudly; no token at all keeps the #2895 skip. The value reaches the runtime through its environment and is forwarded by name, so it never appears in argv. Consuming repos no longer need a [container].env-prefixes entry for it. The ~/.bashrc source line stays as a convenience for manual conan use. Ref #2902
-
fail fast on a stale check-run that is a required status check (#3383)
- fix(github): fail fast on a stale check-run that is a required status check
A stale check over a successful job is passed only when it is not required by the base branch. A required one, or one seen while the required set could not be read, raises OrphanedCheckError at once, since GitHub keeps blocking the merge on it. pr_merge passes the required-check lookup result through unchanged (None = unknown) instead of coercing it to an empty set, and its orphan abort now carries the waiter's detail. The normal wait path keeps the #3061 fallback. Ref #3379
-
docs(finalize-pr): document fail-fast for stale required check-runs
-
drop the deprecated run-standards input and stale CI, scripts/dev and deps/ guidance (#3389) render_ci_workflow no longer passes run-standards to ci-security.yml, which documents it as deprecated and ignored. CLAUDE.md drops the retired standards-compliance PR-CI gate and the scripts/dev/test.sh wrapper, and describes how vrg-container-test picks its language. The obsolete Python local-validation-scripts page (scripts/dev/validate_local.py) is removed. git-workflow.md now states that vrg-commit refuses deps/update-
by design, because vrg-update-deps commits there with git directly. Ref #3384 -
name the publish credentials the tools actually read (#3395) Rust now names CARGO_REGISTRY_TOKEN, which cargo publish reads and the registry-publish action sets, instead of CRATES_IO_TOKEN. Python names no credential (None), matching Go: it publishes through PyPI trusted publishing (OIDC), and nothing ever set PYPI_TOKEN. vrg-ecosystem-resolve output changes accordingly. Ref #3394.
Chores¶
- uv lock --upgrade (#3356)
-
drop AI co-author attribution and turn off Claude Code's trailer (#3365) AI co-author attribution is dropped. Claude Code's default attribution setting is what told agents to add a Co-Authored-By trailer, so it is now turned off in the checked-in .claude/settings.json with the empty-string form ("attribution": {"commit": "", "pr": ""}).
-
Add the attribution block to this repo's .claude/settings.json and to the repo-init template, so vrg-github-repo-init writes it for new repos.
- vrg-github-repo-config audits the attribution value. During the fleet rollout a missing or different value is a warning only, not a failure.
- Remove the dead VRG_CO_AUTHOR handling from vrg-commit and vrg-reword and the co_author parameter from build_commit_message.
- Drop the nonexistent "co-author format" check from vrg-repo-profile's help text.
- Fix stale co-author docs (vrg-commit reference, git workflow, getting started, consuming repo setup, CLI overview, identity architecture, CLAUDE.md, repository standards, hooks and validation).
-
Delete the stray tracked .commit-msg.tmp.
-
stop generating deprecated CI inputs (#3391) The generated ci.yml no longer declares or forwards run-release, no longer passes run-standards to ci-security.yml, and no longer passes container-suffix to the security job. vergil-actions marks all three as deprecated no-ops. This repo's own ci.yml drops them in the same change, and the stale standard-actions CI gates link in the Python overview now points at vergil-actions.
Documentation¶
- rewrite getting-started and consuming-repo-setup to match current tooling (#3381)
Rewrite the quickstart around vrg-github-repo-init (new repo or --adopt)
and verification with vrg-validate and vrg-github-repo-config audit,
dropping the hand-built settings.json, the docs/repository-standards.md
profile and the dogfooding
uv run vrg-repo-profilestep.
Consuming Repo Setup now describes what repo-init generates: the vergil.toml profile (keys and enums from lib/config.py), the claude_settings.json and hook-guard templates by link rather than copy, the attribution block (#3200), the marketplace ref main (#1974), the plugin's actual hooks, the generated CI/ops/epic-rollup/cd workflows, and the /plugin marketplace update refresh.
Also fix the live stale-token hits elsewhere in docs/site: the repo-profile reference, CLI tools overview, hook guard reference, validation matrix, git-workflow (old marketplace paths, closed plugin#46 notes, removed auto-merge and validate-on-edit entries), ci-architecture, index and repository-structure.
- finish the Go 1.25 retirement and drop Ruby from the supported languages (#3382)
-
fix the remaining stale CI, validation and git-workflow docs (#3385) Correct the remaining stale CI, validation and git-workflow docs found during #3362, each verified against the current code and the vergil-actions reusable workflows.
-
ci-architecture.md: Tier 1 is vrg-container-run -- vrg-validate (the scripts/dev/*.sh pattern is gone); vrg-commit does not run validation; Tier 2 lists the real ci.yml jobs; the security-and-standards and standards-compliance names are replaced by the current check names and the computed CI gates ruleset; the implementation guide now describes vrg-github-repo-init and vrg-github-repo-config; the wrong string-inputs warning, the nonexistent semgrep-language input and the docker-publish.yml filename are corrected.
- validation-matrix.md: rewritten. There is no pre-commit git hook; the page maps every check to vrg-git, vrg-commit, the hook guard, vrg-submit-pr, vrg-validate and the PR-CI jobs, local and CI.
- git-workflow.md: worktree, cleanup and agent-prompt examples use
vrg-git and
; branch creation goes through a worktree; the branch-name pattern matches lib/branch_names.py. - Delete docs/git-hooks-and-validation.md (it described the retired docs/repository-standards.md profile and duplicated the site pages) and repoint its inbound links.
- reference/index.md: the hook row no longer describes an env-var pre-commit gate.
- vrg-github-repo-init --vergil-version help states the real default.
Features¶
-
make the .claude/settings.json attribution audit strict (#3376) A missing or different attribution value in .claude/settings.json is now a local.claude_settings.attribution DiffItem instead of a warning. The expected value names the required key and #3200. There is no exemption for dormant repos: one whose nightly audit still runs fails until it adds the key. Ref #3361.
-
show every worktree in the repo, grouped by kind (#3390)
- feat(worktree-status): show every worktree in the repo, grouped by kind, and flag the main checkout
vrg-worktree-status now lists the main checkout and every linked worktree git knows about, in four sections: main checkout, development (feature/
- feat(worktree-status): count every issue-branch type as development
Per the approved design change, Development now holds any worktree on a feature/, bugfix/, hotfix/ or chore/ branch that carries an issue number, using branch_names.is_valid_issue_branch as the single source of truth. An issue prefix without a number, or an unknown prefix, stays in Other / unknown. Ref #3386.
- resolve CI versions from the published window with one resolver (#3393)
Add lib/versions: window.py loads the schema-1 window.json that vergil-containers publishes at the repo's [dependencies].vergil ref (VRG_VERSION_WINDOW=
overrides it; any fetch or parse failure raises WindowError naming the URL and the override, with no cached or built-in fallback), and resolve.py implements the spec 6.3 rules once: library vs app from repository-type, whole window vs newest when unpinned, pins must lie in the window, app multi-pins warn (STRICT_APP_PINS flips them fatal later), family-keyed languages must pin, and [ci].primary-version must name a resolved version. extensions/ holds the empty per-language registry.
Add vrg-ci-resolve (--format json|github-output) for derive.sh. [ci].versions becomes optional; _DEFAULT_VERSIONS, primary_ci_version, _default_ci_versions and the cpp/node tag parsers are removed. The dev container image, vrg-validate (a new config check), the integration-test gates and repo-init's release container now all resolve through the resolver, and new repos get no [ci].versions. Ref vergil-project/vergil-tooling#3367.
Refactoring¶
- remove Ruby support from the tooling (#3388) Ruby is dropped from the language lifecycle (epic vergil-project/.github#407, spec section 9) and its only consumer is archived, so its support is dead code. Remove it from the primary-language enum, the language registry, version detection and bumping, repo-init scaffolding and cd-release secrets, container image and Gemfile detection, cache and warmup files, semgrep rulesets, the CodeQL and action-pattern sets, vrg-generate-commands, and the gitignore fragment, together with the packaged license_finder config and the tests that covered them.
A vergil.toml that still declares primary-language = "ruby" now fails with a ConfigError naming the retirement, instead of the generic warn-and-treat-as-unset path that would have validated it silently as a language-less repo.
CI Evidence: All gates passed — full audit bundle available. Download →