Skip to content

docs: version bumps move out of feature PRs into dedicated release PRs - #648

Merged
padak merged 2 commits into
mainfrom
claude/auto-versioning-claude-md-c22527
Aug 23, 2026
Merged

docs: version bumps move out of feature PRs into dedicated release PRs#648
padak merged 2 commits into
mainfrom
claude/auto-versioning-claude-md-c22527

Conversation

@padak

@padak padak commented Aug 22, 2026

Copy link
Copy Markdown
Member

Why

Feature PRs are routinely developed in parallel (one AI session per GitHub issue). Today each of them bumps pyproject.toml and adds a changelog.py entry, so every merge is a version conflict, and merging all of them renumbers releases after the fact. The KNOWN_UNRELEASED list in scripts/generate_changelog.py -- 18 versions whose content shipped with no release notes -- is the accumulated damage of exactly that pattern.

What changes (docs/process only, no code)

Feature PRs no longer bump the version or touch changelog.py. A release becomes a dedicated release PR that batches everything merged since the last release: one bump, one changelog entry covering every merged PR (that entry is what scripts/gen_release_notes.py renders into the GitHub release notes), one tag.

  • CLAUDE.md > Versioning: new "Version bumps happen ONLY in a dedicated release PR" subsection describing the two-step flow.
  • CONTRIBUTING.md:
    • new commit convention: "No version bumps in feature PRs";
    • "Releasing a new version" rewritten around the release PR -- new step 1 (collect the PRs merged since the last tag; they are the exact scope of the changelog and release notes) and new step 4 (replace vNEXT placeholders, grep must come back empty);
    • per-command checklist + Plugin synchronization map updated accordingly;
    • beta releases documented as the one deliberate exception (the bump rides the feature branch because the pre-release tag is cut from it).

The vNEXT placeholder

A feature PR cannot tag version-gated docs (gotchas.md etc.) with a numeric future version: make version-gate-check runs in per-PR CI and rejects any (since vX.Y.Z) whose version has no changelog.py entry. Feature PRs therefore tag with the literal placeholder (since vNEXT) (invisible to the gate's numeric-only regex); the release PR rewrites every vNEXT to the released version, with an explicit must-be-empty grep step in the checklist.

Verified

  • make version-gate-check -- all 423 gates still resolve (no numeric gates added by this PR)
  • make command-sync-check -- green (the ## All CLI Commands section is untouched)
  • This PR itself follows the new rule: docs-only, no version bump, no changelog entry (the plugin/docs are served from the repo, so no release is needed).

Open in Devin Review

Bonus: the failure mode, caught live

Second commit resolves two stale (Release step: once this ships, tag this sentence (since vX.Y.Z)...) placeholders in gotchas.md -- exactly the leftover-placeholder failure this PR's release checklist step 4 guards against. Both referred to behavior merged after the v0.88.0 tag (table-detail human Description column #642, describe-batch shape rejection #645), so both are tagged (since v0.89.0) (main is already bumped to 0.89.0 and the changelog key exists, so make version-gate-check resolves them -- 425 gates green). If the 0.89.0 release ever gets renumbered, these two tags renumber with it.

…ted release PRs

Parallel feature PRs (one AI session per issue) each bumping pyproject.toml
collide on every merge and silently renumber releases -- the KNOWN_UNRELEASED
list in scripts/generate_changelog.py is the accumulated damage of that
pattern. Version bumps and changelog.py entries now happen ONLY in a
dedicated release PR that batches everything merged since the last release.

- CLAUDE.md Versioning: new 'Version bumps happen ONLY in a dedicated
  release PR' subsection with the two-step flow and the vNEXT placeholder
  convention for version-gated docs in feature PRs (version-gate-check
  rejects guessed numeric versions in per-PR CI, so the placeholder is the
  only workable tag before the release assigns a number).
- CONTRIBUTING.md: new 'No version bumps in feature PRs' commit convention;
  per-command gotchas checklist and sync map updated for vNEXT; 'Releasing
  a new version' rewritten around the release PR -- new step 1 (collect
  merged PRs since the last tag as the exact scope of the changelog and
  release notes) and step 4 (replace every vNEXT, grep must come back
  empty); beta releases documented as the one deliberate exception where
  the bump rides the feature branch.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no bugs or issues to report.

Open in Devin Review

…has.md

Both '(Release step: once this ships, tag this sentence (since vX.Y.Z)...)'
parentheticals in the storage-descriptions gotcha referred to behavior that
has since merged: the table-detail human-mode Description column (#642) and
the describe-batch --from-file shape rejection (#645). Neither commit is
contained in the v0.88.0 tag and main is bumped to 0.89.0, so both are
tagged (since v0.89.0) -- a version version-gate-check resolves via its
existing changelog entry. This is a live instance of the leftover-placeholder
failure mode this PR's release checklist step 4 now guards against.
@padak
padak merged commit 5313801 into main Aug 23, 2026
4 checks passed
@padak
padak deleted the claude/auto-versioning-claude-md-c22527 branch August 23, 2026 08:39
padak added a commit that referenced this pull request Aug 23, 2026
…XT gates

Rebased onto main, which added four more merged PRs to the release scope.

Changelog (0.89.0):

* Fix (#649): sync diff/push scoped to a single branch tree; cross-tree
  manifest entries are reported under the new `orphaned` bucket instead of
  being planned as creates (a production diff after a dev-branch pull was one
  push away from duplicating the whole project).
* Fix (#644): `config new --push --output-dir` stamps the created config's ID
  into the scaffold and writes it into the branch it was actually created in,
  so the next `sync push` adopts it instead of POSTing a duplicate.
* Fix (#650): the `keboola.flow` scaffold gains the `_keboola` footer and the
  push-compatible `version: 2` / `_configuration_extra` shape.
* Internal (#648): version bumps and changelog entries now happen only in a
  dedicated release PR; feature PRs tag version-gated docs with `vNEXT`.

vNEXT placeholders: 17 usages rewritten to the released version across
CLAUDE.md, keboola-expert.md, gotchas.md, commands-reference.md,
branch-workflow.md, scaffold-workflow.md, sync-workflow.md and
AGENT_CONTEXT (context.py). The only surviving `vNEXT` mentions are the three
CLAUDE.md lines that document the convention itself.

Rebase conflict: gotchas.md storage-descriptions bullet -- both sides kept
(main's reflow plus the release commit's added pre-0.89.0 sentence).

keboola-expert.md is 50 113 B, inside the 70 000 B budget. make check green
(6009 passed, 12 skipped); version-gate-check resolves all 450 markers across
72 versions.
padak added a commit that referenced this pull request Aug 23, 2026
…es (#651)

Release prep for 0.89.0: adds the changelog entries for everything merged since v0.88.0 (#620, #642, #643, #644, #645, #646, #647, #648, #649, #650, #517, #586, #641), resolves every vNEXT placeholder left by feature PRs to v0.89.0 per the new #648 release process, closes the 10 gaps a full doc-surface audit found across the kbagent plugin (SKILL.md triggers, commands-reference, gotchas, workflow files, keboola-expert.md, AGENT_CONTEXT, CLAUDE.md), and records the live e2e verification evidence. Version files were already at 0.89.0 (bumped by #643); make version-sync is a no-op.
claude Bot pushed a commit that referenced this pull request Aug 23, 2026
Resolves the sync-map conflict in CONTRIBUTING.md. main moved from 0.86.0
to 0.89.0 while this branch sat, and two adjacent table rows collided:

- `keboola-expert.md` row: keep main's "70 000 B prompt budget". v0.88.0
  raised the ceiling from 62 000 B, and tests/test_agent_prompt.py
  (test_documented_budget_matches_enforced_budget, added in #586) now
  gates CONTRIBUTING.md against PROMPT_BYTE_BUDGET, so this branch's
  stale "60 KB" would fail CI.
- `commands/*.md` row: keep this branch's widened row plus its
  follow-through list for adding a new slash-command file.

No version or changelog change: main's #648 moved version bumps into
dedicated release PRs, and this branch bumps nothing.
padak added a commit that referenced this pull request Aug 23, 2026
* fix(ci): stop the live vNEXT gate turning main and every PR red

`TestLiveRepositoryVnext::test_no_unresolved_placeholder_survives_a_release`
asserted that the live tree carries no `(since vNEXT)` placeholder. That
is not an invariant of this repo -- it is the opposite of the documented
process.

Since #648, a feature PR that documents version-gated behaviour writes
the literal `vNEXT` placeholder and only the release PR rewrites it.
CLAUDE.md says so directly ("Writing `vNEXT` in a feature PR is correct
and stays green"), and TestReleaseModeSelection, added by the same PR as
this assertion, explains that arming the gate outside a release PR
"would demand a contributor delete a placeholder the process requires
them to write".

So main legitimately carries placeholders for most of a release cycle.
The assertion was green only because #670 landed days after 0.90.0 had
just rewritten every one of them. #675 added the first placeholder of
the next cycle and the assertion went red -- on main, and on every open
PR, since a PR run tests the merge commit.

The release-time requirement itself is real and stays enforced where it
can see the base branch's version: the "Unresolved vNEXT placeholder
check" step in ci.yml (`--release-if-newer-than`) and its local twin
`make vnext-check`. A unit test cannot see that version, so it cannot
make this call.

What a test CAN assert is that the live scan works, and that replaces
it: every gate the scanner reports must point at a real line that really
contains the placeholder. Zero hits and ten hits are both valid answers
depending on where in the cycle the tree sits. The neighbouring
"guards the guard" test already covers the globs resolving at all.

* fix(test): anchor the live vNEXT scan on REPO_ROOT, not the cwd

`VnextResidue.path` is repo-root-relative -- find_vnext_residue stores
`path.relative_to(REPO_ROOT).as_posix()` -- so reading it back as a bare
`Path(gate.path)` resolves against the current working directory. The
loop body only executes when the tree actually carries a placeholder,
which is precisely the state main is in now, so running pytest from
anywhere but the repo root raised FileNotFoundError.

Reproduced from tests/ before the change and confirmed green after, from
both the repo root and a subdirectory.

`REPO_ROOT / gate.path` also covers the one fallback branch, where a path
outside the repo is stored absolute: joining an absolute right-hand side
discards the left, yielding that path unchanged.

Raised by Devin review on #678.
claude Bot pushed a commit that referenced this pull request Aug 24, 2026
…che dirs

Review found a real bug in the claude_plugin check, not just a gap in the tests.

`_check_claude_plugin` probed the two cache dirs in order and broke out of the
loop at the first one holding any version dir, so `latest` was the max WITHIN
that dir only. While ai-kit trails a cli release -- the exact state publishing
through ai-kit creates -- a user with both installs and a newer copy under the
legacy `keboola-agent-cli` dir was told the OLDER `keboola-claude-kit` version,
got no migration note, and got a drift hint aimed at a copy they were not
running. Reporting a stale version as current is worse than reporting nothing.

The probe now collects every version dir under every marketplace dir that
exists and picks the single newest, so version, path, marketplace name, drift
hint and migration note all describe the same copy:

- a newest-copy-under-the-shim install gets the migration note it was missing;
- the drift hint names the marketplace of the reported copy
  (`/plugin update kbagent@<marketplace>`), unambiguous when both are installed;
- the message and a new `plugin_marketplace` result key name where the copy
  came from;
- ties (same version cached under both) resolve to the current marketplace --
  same code, nothing to migrate off.

Ordering is PEP 440 via `packaging.version`, the idiom version_service already
uses, rather than dir-name string compare: a string sort puts "0.100.0" below
"0.90.0" and would report a stale copy as newest once the minor rolls past 99,
which this repo is ten releases from. Unparseable dir names sort below every
real version but stay eligible, so a hand-made dir never hides an install.
Single-cache-dir behaviour is unchanged; all 11 pre-existing tests pass as-is.

Also adds the sync job's missing automated test. `ai-kit-marketplace` is the
only job here that writes to another repo, and its entry shape is owned by
ai-kit, so the failure worth pinning is a shape change on the far side.
tests/test_release_kbagent_ai_kit_sync.py extracts the step's real `run:` block
from the workflow and executes it with bash against a throwaway git repo --
same "load the real artifact by path, then exercise it" approach as
test_sync_version_script.py -- covering the at-target no-op (byte-identical
file, changed=false), a genuine bump rewriting both `version` and `source.ref`
while leaving the git-subdir coordinates and sibling plugins alone, either field
stale alone still counting as a bump, a missing `source.ref` getting added, a
missing `kbagent` entry failing loudly, and a `source` that is a plain string
(the shape this repo's own deprecated marketplace.json still uses) aborting with
the file untouched instead of publishing an unpinned version.

No version bump and no changelog entry, per #648.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RiYtKRNF8XDx3dDZAAeBGV
padak added a commit that referenced this pull request Aug 25, 2026
…criptions (#695)

Closes #690. Adds the write path to the kbagent notification group (client POST/DELETE, service create/delete/replace-recipient, CLI commands with write/destructive permission gating, serve routes, docs across all agent surfaces tagged (since vNEXT)). replace-recipient is create-new-first-then-delete-old so a failed second step leaves a recoverable duplicate, never a lost alert. No version bump (feature PR per #648 process).
padak added a commit that referenced this pull request Aug 25, 2026
…operations (#693)

Closes #688.

`permissions set --allow/--deny` now validates every pattern before the
interactive confirmation: valid = a cli:* category (cli:read, cli:write,
cli:destructive, cli:admin), an exact known operation (OPERATION_REGISTRY
plus FLAG_ESCALATIONS strings), or a glob matching at least one of those.
Anything else fails fast with VALIDATION_ERROR, exit 2, listing every
offending pattern in error.details.invalid_patterns.

find_inert_patterns is generalized: permissions show and kbagent doctor now
flag ANY persisted pattern matching zero operations (typos included), not
only the retired tool: namespace; the MCP-migration hint appears only when a
tool:-prefixed pattern is present. doctor --json's details.inert_since is now
conditional on a tool: pattern being present. Runtime evaluation is
unchanged -- PermissionEngine stays lenient with pre-existing dead patterns.

Docs drift surfaces updated with (since vNEXT) tags; no version bump
(feature PR per #648 process). Includes a validator/engine parity test
guarding against reintroducing this bug class.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant