This is an automated email from the ASF dual-hosted git repository.

potiuk pushed a commit to branch v3-3-test
in repository https://gitbox.apache.org/repos/asf/airflow.git


The following commit(s) were added to refs/heads/v3-3-test by this push:
     new 500e5ac7da3 [v3-3-test] Add a command to take a prepared provider back 
out of a release (#71836) (#72728)
500e5ac7da3 is described below

commit 500e5ac7da3606958adbda3a4ce2078fb3dae1a6
Author: Jarek Potiuk <[email protected]>
AuthorDate: Tue Sep 8 19:19:36 2026 +0200

    [v3-3-test] Add a command to take a prepared provider back out of a release 
(#71836) (#72728)
    
    * Document dropping a prepared provider back to doc-only
    
    Release managers hit this when review concludes a prepared provider's 
changes
    are internal after all: the changelog entry can be corrected, but the 
version
    bump and changelog section stay behind and the provider is still built and
    uploaded. The sequence that actually removes it from the wave - and the 
marker
    file that records it - was described nowhere outside the breeze sources.
    
    The pre-merge sweep only ever looked for providers missing from a wave, so 
the
    opposite direction had nothing watching it in either the manual or the 
agentic
    flow.
    
    * Add a command to take a prepared provider back out of a release
    
    When review concludes that an already-prepared provider has no user-facing
    changes, correcting its changelog entry leaves the version bump and the
    changelog section behind, so the provider is still built and uploaded. 
Undoing
    that by hand is a restore-rerun-answer-N sequence that release managers
    repeatedly get wrong, and it is unavailable during an incremental update at 
all:
    that mode answers every question with yes, so the prompt that reclassifies a
    provider as doc-only never appears.
    
    * Say why a never-released provider cannot be dropped to doc-only
    
    Review pointed out that such a provider gets no doc-only marker. Writing one
    would not help: the marker is only read once the current version is tagged, 
so
    for a first release it is inert, and read literally it would suppress that
    release for good. What was wrong is the message, which claimed there were no
    changes when the real reason is that there is no earlier release to diff
    against.
    
    Marking the two functions that always raise as NoReturn also lets the 
compiler,
    rather than the reader, establish that the loop cannot continue past the
    doc-only branch.
    
    * Refresh the breeze command hash for prepare-provider-documentation
    
    The committed hash was computed against a stale cached breeze build, so CI's
    static checks regenerated it and failed the run.
    (cherry picked from commit 391578af62027fe8939ad4bd6188eabcc6707f92)
    
    
    Generated-by: Claude Code (Opus 5)
    Claude-Session: https://claude.ai/code/session_01XS3bodTDYYGrPmorhtLsjP
---
 .../prepare-providers-documentation/SKILL.md       | 470 +++++++++++++++++++--
 dev/README_RELEASE_PROVIDERS.md                    |  58 +++
 ...e-management_prepare-provider-documentation.svg |  78 ++--
 ...e-management_prepare-provider-documentation.txt |   2 +-
 .../commands/release_management_commands.py        |  23 +-
 .../commands/release_management_commands_config.py |   1 +
 .../prepare_providers/provider_documentation.py    |  45 +-
 dev/breeze/tests/test_provider_documentation.py    |  83 +++-
 8 files changed, 679 insertions(+), 81 deletions(-)

diff --git a/.agents/skills/prepare-providers-documentation/SKILL.md 
b/.agents/skills/prepare-providers-documentation/SKILL.md
index c4838af4df3..cfcfda85817 100644
--- a/.agents/skills/prepare-providers-documentation/SKILL.md
+++ b/.agents/skills/prepare-providers-documentation/SKILL.md
@@ -65,6 +65,19 @@ Two entry points:
   rebasing a release PR before merging). Skip ahead to the
   **Incremental Update** section after Phase 5.
 
+Either entry point runs in one of two **release shapes**. Establish which one
+applies before starting — the incremental flow behaves differently in each:
+
+- **Wave** (the default) — the regular cycle that releases *every* provider
+  with pending changes. The provider list is an **output** of the run, so it
+  may legitimately grow between the initial cut and the merge.
+- **Ad-hoc** — a release deliberately scoped to a fixed provider list (the
+  release manager named a subset, or set `DISTRIBUTIONS_LIST`). The provider
+  list is an **input** and must not grow on its own.
+
+Ask the release manager if it is not obvious, and record the answer —
+Incremental Phases 2 and 3.6 branch on it.
+
 Do **not** use this skill for:
 
 - `--only-min-version-update` runs (these don't need classification — just
@@ -163,6 +176,25 @@ How to read it:
 > back as `needs_llm`. The rules live in `classify_change_deterministically`
 > (`dev/breeze/src/airflow_breeze/prepare_providers/provider_documentation.py`).
 
+The range the classifier reports is not fixed for the whole run — it widens 
once
+a provider actually gets a version bump:
+
+> [!WARNING]
+> **A version bump supersedes the provider's doc-only marker — re-run discovery
+> after Phase 4a.** When `docs/.latest-doc-only-change.txt` is present the
+> classifier starts the range at that commit, so anything older (earlier 
doc-only
+> changes, tooling churn) is hidden for as long as the provider has no pending
+> release. That is correct while nothing ships — but the moment the provider 
gets
+> a real version bump the marker no longer applies, and those commits are part 
of
+> what the release publishes.
+>
+> Re-run `classify-provider-changes` **after** bumping versions and fold in 
every
+> commit that newly appears; otherwise the release silently drops doc-only
+> entries that were only ever suppressed by the marker. The tell is a provider
+> whose commit count grows between two runs without any new merges. Observed in
+> the 2026-08-01 wave: `cohere` gained #69649, `dbt.cloud`/`presto`/`trino` 
gained
+> #69478, and `papermill` gained #68322 — all invisible in the first pass.
+
 Then regenerate the auto-generated build files (this does **no** 
classification,
 so nothing random is produced):
 
@@ -245,6 +277,31 @@ ever need the min-Airflow-bump case (`v`), that one is 
still a `needs_llm`
 judgement: a sub-agent should flag it when a PR bumps the provider's minimum
 Airflow version.
 
+> [!NOTE]
+> A `needs_llm` commit can still be classified as `skip` by the LLM. The
+> deterministic classifier only catches test/example-only changes by looking
+> at which files were modified in the commit. PRs that change build tooling,
+> packaging infrastructure, or breeze templates (files under `dev/breeze/`,
+> `scripts/`, etc.) and only regenerate template-generated files in the
+> provider slice (e.g. `README.rst`, `index.rst`, `pyproject.toml`) are NOT
+> caught by the deterministic rules but should still be classified as `skip`
+> — they have zero user-facing impact on the provider package itself.
+
+That rule cuts one way only. Read the next one before applying it.
+
+> [!WARNING]
+> The converse trap: a PR is **not** `skip` merely because its subject
+> describes tooling. `provider.yaml` is a **source** file, never a regenerated
+> one — anything it declares (`connection-types`, `conn-fields`,
+> `ui-field-behaviour`, `extra-links`, `hook-class-names`, dependencies) ships
+> to users through `get_provider_info.py`, so a change to it is `misc` at
+> minimum. `get_provider_info.py` moving *because `provider.yaml` moved* is
+> therefore not "regenerated metadata" in the sense above. Worked example:
+> `Fix conn-fields check crash for nested provider packages (#70224)` fixes a
+> prek check under `scripts/ci/prek/`, and in the same commit declares a new
+> `Verify SSL` connection-form field for `atlassian.jira` — `misc`, not `skip`.
+> Classify from the provider-scoped diff, never from the subject.
+
 #### Classify the `needs_llm` commits — batched per provider, not one agent 
per PR
 
 Only the commits the classifier returned as `needs_llm` still need a sub-agent.
@@ -292,9 +349,24 @@ For EACH commit above:
    - feature:       adds new capability, parameter, operator, sensor, hook,
                     or extends an existing one in a backwards-compatible way
    - breaking:      see "Breaking-change checklist" below
-   - misc:          dependency bumps, internal refactors, packaging-only
-                    changes, type-hint cleanups, no user-visible behavior
-   - skip:          only tests/examples/CI for this provider's slice
+   - misc:          dependency bumps, internal refactors, type-hint
+                    cleanups, no user-visible behavior
+   - skip:          only tests/examples/CI for this provider's slice,
+                    OR changes that only touch build tooling, packaging
+                    infrastructure, or template-generated files (e.g.
+                    README.rst, index.rst, pyproject.toml regeneration,
+                    flit/sdist config, breeze templates) — even when
+                    those files live under the provider path. If the
+                    PR's actual code changes are entirely in dev/breeze/
+                    or similar tooling and the provider-scoped diff is
+                    limited to regenerated docs/metadata, classify as
+                    skip. NEVER skip a slice that touches
+                    provider.yaml — that is a source file whose
+                    contents ship in get_provider_info.py
+                    (connection-types, conn-fields,
+                    ui-field-behaviour, extra-links, dependencies),
+                    so it is misc at minimum even when the PR's
+                    headline change is tooling.
    - min_airflow_bump: explicitly bumps the minimum Airflow version pin
 4. Set BREAKING_RISK to "maybe" whenever the diff has any signal from the
    breaking-change checklist below, even if you think the author intended
@@ -305,8 +377,21 @@ Output one row per commit and nothing else, in this exact 
pipe format
 
    #<NNNN> | 
<documentation|bugfix|feature|breaking|misc|skip|min_airflow_bump> | 
<high|medium|low> | <none|maybe|yes> | <one-sentence justification>
 
+A change is only breaking if the thing it breaks was **released**. Removing,
+renaming, or altering a symbol/behavior that was *introduced in this same
+unreleased wave* (i.e. the feature was added in one pending commit and
+changed in another, both after the provider's last release tag) is NOT a
+breaking change — users never received the old form, so there is nothing to
+break. Before classifying any removal/rename as breaking, confirm the affected
+symbol existed at the last released version:
+`git show providers-<id>/<last-version>:providers/<path>/... | grep <symbol>`
+(or grep the last release tag). If it isn't there, treat the change as part of
+delivering the new feature (feature/misc), not breaking. A within-wave rename
+of a brand-new operator or plugin is feature-shaped, not a major bump.
+
 Breaking-change checklist (any of these → BREAKING_RISK >= maybe; usually
-breaking unless clearly behind a deprecation shim):
+breaking unless clearly behind a deprecation shim) — **each item assumes the
+affected symbol/behavior shipped in a released version, per the rule above**:
   * Public class/function/method removed or renamed
     in the **public interface** of the provider — i.e. files under
     `providers/<path>/src/**/{hooks,operators,sensors,triggers,
@@ -333,7 +418,9 @@ breaking unless clearly behind a deprecation shim):
 
 Do NOT trust the PR title alone — read the diff. A PR titled "Refactor X"
 that removes a public method is breaking. A PR titled "BREAKING: rename
-foo" that only renames a private symbol is not.
+foo" that only renames a private symbol is not. A PR that renames a public
+class introduced earlier *in this same unreleased wave* is not breaking
+either — the old name was never released (see the released-only rule above).
 ```
 
 Collect every sub-agent's rows (and any you classified inline) into one
@@ -477,7 +564,87 @@ Rules:
   indent, double backticks).
 - Subjects must be the original commit subject with backticks replaced by
   single quotes (matches `message_without_backticks`). Don't paraphrase.
-- Always keep the `(#NNNN)` PR suffix.
+- **Exception — rewrite subjects written in project-internal language.** The
+  don't-paraphrase rule keeps you honest about *what* shipped; it does not
+  oblige you to publish a subject the reader cannot act on. The changelog is
+  read by users, not by us. Rewrite the entry — keeping every `(#NNNN)` — when
+  the subject is only meaningful inside the project:
+  - **Spell out internal abbreviations.** `KPO`, `DFP`, `TI`, `RTIF`, `OL` and
+    friends are our shorthand. Write ``Add '--min-completed-minutes' to
+    'cleanup-pods' to prevent KubernetesPodOperator race condition (#70595)``,
+    not ``… to prevent KPO race condition (#70595)``.
+  - **Name what a grouped dependency bump actually changed.** Dependabot group
+    subjects such as ``Bump the fab-ui-package-updates group across 1 directory
+    with 3 updates (#70604)`` tell the reader nothing. Read the PR diff and 
list
+    the packages with their versions: ``Bump prettier to 3.9.6, stylelint to
+    17.14.1, webpack to 5.109.0 (#70604)``. A single-package bump still needs
+    its target version: ``Bump eslint to 10.8.0 (#70697)``.
+  - **Describe the user-visible effect, not the internal mechanic.** ``Remove
+    noqa:S101 from production code (#70378)`` names a lint directive; the 
reader
+    wants ``Mark asserts under 'TYPE_CHECKING' in 'DocumentLoaderOperator'
+    (#70378)``.
+  - **Drop our test vocabulary.** A system test is just an example Dag to the
+    user, so ``Remove hard-coded deferrable crawler run from example_glue 
system
+    test (#70206)`` becomes ``Remove hard-coded deferrable crawler run from
+    example_glue (#70206)``.
+
+  Rewrite the *wording*, never the *claim* — do not describe behaviour that did
+  not ship. When a subject is too vague to rewrite honestly, read the PR diff
+  before writing the entry.
+- **Exception — collapse within-wave "add then rename/rework" chains into one
+  net entry.** When several pending commits are steps toward *one* net change —
+  a feature added in one PR and renamed or reworked in a later PR, both since
+  the last release (the released-only situation from Phase 3) — do **not** list
+  the intermediate steps as separate entries. A reader who never saw the
+  released intermediate form gets no context from ``Add X listener (#a)`` under
+  Features plus ``Rename X to Y (#b)`` under Misc. Write a **single** entry 
that
+  describes the **net user-facing change** and references **all** related PRs,
+  placed in the section of the most-impactful step. Real example: #68082 added
+  a Kafka listener and #70014 renamed it to the Kafka Event Producer in the 
same
+  wave → ``Add Kafka Event Producer publishing DagRun and TaskInstance
+  state-change events (#68082, #70014)`` under Features (and *no* separate Misc
+  "Rename …" line). This is the changelog counterpart of the unreleased-feature
+  classification rule: classify the rename as non-breaking (Phase 3) **and**
+  describe only what shipped, naming every PR involved.
+- **Capitalize the first letter of every entry**, not only after stripping a
+  Conventional Commit prefix. Contributors sometimes write a lowercase subject
+  (`derive keycloak oauth redirect_uri …`) or a pseudo-scope
+  (`cncf-kubernetes: fix …`); the changelog convention is a leading capital, so
+  render them as ``Derive keycloak oauth redirect_uri …`` /
+  ``Cncf-kubernetes: fix …``.
+- **Strip Conventional Commit prefixes** before writing to the changelog.
+  If the subject starts with a prefix like `feat:`, `fix:`, `chore:`,
+  `docs:`, `refactor:`, `ci:`, `test:`, `perf:`, `build:`, or `style:`
+  (with or without a scope in parentheses, e.g. `fix(amazon):`), remove
+  the prefix and capitalize the first letter of the remaining text.
+  Example: `refactor: Fix _is_http_client_closed ...` →
+  `Fix _is_http_client_closed ...`. Airflow does not use Conventional
+  Commits and these prefixes should not appear in changelogs.
+- **Send no-PR release-tooling commits to the excluded block**, even when the
+  Phase 1 deterministic classifier labeled them `documentation`. Subjects like
+  ``Prepare … providers release/documentation …`` and ``Hide non-user-facing
+  entries from ad-hoc provider release notes`` (often with no `(#NNNN)` suffix
+  because they were committed directly) are release plumbing, not user-facing
+  changes — a `(#NNNN)`-less line in a visible section reads as a mistake. Put
+  them under the `.. Below changes are excluded …` block. breeze's 
deterministic
+  classification can even be inconsistent for the same commit across providers,
+  so normalize to excluded.
+- Always keep the `(#NNNN)` PR suffix (or, for a collapsed chain, the
+  comma-separated list of all involved PRs).
+- **Order entries within each section by merge order, newest first** — the 
exact
+  order `git log` printed them in Phase 1. `CHANGELOG_TEMPLATE.rst.jinja2`
+  iterates the changes without sorting, so that order *is* the format. It is
+  **not** descending PR number: a long-lived PR merged late carries a low 
number
+  and still belongs at the top (real example: `#64274` sits second in amazon
+  9.32.0's `Features`). Don't re-sort by PR number and don't group by theme.
+  The excluded block follows the same order. A collapsed chain — one entry
+  naming several PRs — sits at the position of its **first** commit, which is
+  when the change became relevant, not at the position of the later rework.
+- **Never adopt an entry a contributor pre-wrote at the top of
+  `changelog.rst`** — above the first version header — without checking its PR
+  number against `git log`. Those blocks are written before the PR merges, so
+  the number in them is a guess and is often wrong or nonexistent. Keep the
+  prose, replace the reference with the real merge commit's `(#NNNN)`.
 
 #### 4c. Regenerate templates with breeze
 
@@ -525,6 +692,19 @@ version of the referenced provider and removes the comment.
 > doc preparation and PR creation, so it is easy to forget when the skill
 > hands back to the regular release workflow.
 
+**Provider dependency-bump CI guard.** Every `>=` bump this produces (and any
+inter-provider `>=` bump made during the wave, e.g. a `breaking` provider that
+dependents must now require) trips the `check_provider_dependency_bumps`
+selective-check (`dev/breeze/src/airflow_breeze/utils/selective_checks.py`),
+which fails CI with *"Provider dependency version bumps detected that should
+only be performed by Release Managers!"*. That guard exists to stop
+**contributors** from silently changing inter-provider `>=` floors; for a
+release wave the bumps are legitimate. The release PR **must carry the
+`allow provider dependency bump` label** to bypass it — every prior "Prepare
+providers release …" PR carries this label. Tell the release manager to add
+the label to the PR (it re-triggers the check via the `labeled` event); the
+bumps are not a mistake to revert.
+
 ### Phase 5 — Validate
 
 Run the same checks the release manager would run:
@@ -544,14 +724,81 @@ provider-by-provider:
 
 - Confirm the version in `provider.yaml` matches the bump rule.
 - Confirm `changelog.rst` has the right sections populated.
+- **Check for misplaced top-level note blocks.** Each provider's
+  `changelog.rst` has a standing `.. NOTE TO CONTRIBUTORS:` RST comment
+  near the top (above all version sections). If you detect any `.. note::`
+  directive that is NOT nested under a specific version section (i.e. it
+  appears before the first version header, or between the `Changelog`
+  heading and the first version), notify the release manager immediately —
+  it likely means a breaking-change or min-version note was accidentally
+  written at the wrong indentation level or position.
+
+  Two variants to check for, both seen in the 2026-08-01 wave:
+  - **Already misplaced on the base branch.** A contributor adds a note for
+    their own change directly under the `Changelog` header instead of inside
+    the version section it belongs to, so it renders page-wide. Move it into
+    the section that ships the change (`google` #70869).
+  - **Pushed out of place by your own prepend.** When a note was sitting above
+    the first version header and you prepend a new section, the note ends up
+    *between* your new excluded block and the previous version — still wrong,
+    but no longer above the first header, so a scan that only looks at the top
+    of the file misses it (`openai` #69506). Check **inside every section you
+    touched** that no `.. note::` appears after the
+    `.. Below changes are excluded …` marker; a note belongs directly under the
+    version underline, before the first `~~~` header.
+
+  The same applies to a bare `Breaking changes` / `Features` / … heading 
sitting
+  above the first version header: a contributor pre-wrote it, and it must be
+  folded into the new version section with its PR reference corrected (Phase 
4b).
 - Confirm Phase 4d ran: no `# use next version` comment remains where the
   referenced provider was bumped in this wave.
+- **If any inter-provider `>=` floor changed** (Phase 4d resolved a pin, or a
+  `breaking` provider forced a dependent to require its new major), tell the
+  release manager the PR needs the `allow provider dependency bump` label —
+  otherwise the `check_provider_dependency_bumps` CI check fails with
+  *"Provider dependency version bumps detected that should only be performed
+  by Release Managers!"*. `git diff` the changed `pyproject.toml` files for
+  `apache-airflow-providers-*` `>=` changes and list them for the RM.
+- **Reconcile every new section against `git log` — this gate is mandatory.** 
Run
+
+  ```bash
+  python3 dev/check_changelog_entries.py --fix
+  ```
+
+  It compares each provider's newest section against the commits actually being
+  released and exits non-zero on four defects that eyeballing the diff misses:
+
+  | Code | Meaning | Action |
+  | --- | --- | --- |
+  | `MISSING` | a released commit has no entry | classify and add it (Phase 3 
+ 4b) |
+  | `UNKNOWN` | an entry cites a PR outside the release range | replace with 
the real `(#NNNN)` |
+  | `SECTION` | heading is not one of the template's five | move the entry 
under a template heading |
+  | `ORDER` | entries are off merge order | repaired by `--fix` |
+
+  Re-run it after **any** rebase of the release branch. A rebase silently pulls
+  new provider commits into the release range without touching `changelog.rst`,
+  and that is exactly how a shipped change ends up undocumented. Only `ORDER`
+  is auto-repairable — resolve every other code by hand before handing off.
+- **Scan the new changelog sections for these entry defects** — grep the lines
+  you added: (1) a bullet whose text starts with a lowercase letter → 
capitalize
+  it (Phase 4b); (2) a bullet in a *visible* section (Features / Bug Fixes /
+  Misc / Doc-only) with no `(#NNNN)` suffix → usually no-PR release-tooling 
that
+  belongs in the excluded block (Phase 4b); (3) an "add then rename" pair for
+  the same feature left as two separate entries → collapse into one net entry
+  naming both PRs (Phase 4b); (4) an internal abbreviation (`KPO`, `DFP`, `TI`,
+  `RTIF`, `OL`) or the phrase "system test" → rewrite in user-facing language
+  (Phase 4b); (5) a dependency bump that names no version, or a Dependabot 
group
+  subject of the form "… group … with N updates" → replace with the actual
+  packages and versions from the PR diff (Phase 4b). Reviewers reliably catch
+  all of these, so fix them before handing off.
 - Flag anything where Phase 3.5 had to escalate, so the RM can double-check.
 
 Stop here. Do not commit, do not push — the release manager opens the PR
 themselves following the regular release workflow in
 `dev/README_RELEASE_PROVIDERS.md`. Make sure Phase 4d
-(`update-providers-next-version`) has been run before that PR is opened.
+(`update-providers-next-version`) has been run before that PR is opened, and
+that the PR carries the `allow provider dependency bump` label whenever any
+inter-provider `>=` floor changed (see Phase 4d).
 
 ---
 
@@ -564,6 +811,11 @@ This is the equivalent of `breeze release-management
 prepare-provider-documentation --incremental-update`, but driven by the
 same AI classification logic as the initial run.
 
+On a **wave**, "extend" is not only about the providers already in the PR: a
+provider that had nothing pending when the wave was cut can pick up a
+user-facing change before the PR merges, and the flow below is responsible for
+surfacing it rather than letting the release ship without it.
+
 > [!IMPORTANT]
 > Run on the **release PR branch** *after* rebasing onto the latest base
 > branch. Do not start the incremental flow on a clean checkout — it needs
@@ -583,49 +835,111 @@ the auto-generated build files for every provider — 
picking up any
 upstream template changes that landed since the original PR was opened.
 It does **not** touch `provider.yaml` or `changelog.rst`.
 
-### Incremental Phase 2 — Detect new commits per provider
+### Incremental Phase 2 — Detect unrecorded commits across **all** providers
+
+> [!IMPORTANT]
+> On a **wave**, sweep **every** provider — not just the ones already in the
+> release PR. A provider that had nothing pending when the wave was cut can
+> acquire its first user-facing change hours later, and iterating only over
+> providers that already have a new version section can never discover it: it
+> has no section to extend. That provider then stays invisible for the rest of
+> the release. This is an observed miss, not a hypothetical one — see the
+> worked example at the end of this phase.
 
-For each provider that already has a new version section in its
-`changelog.rst` (the providers in the release PR), get the current commit
-list the same way as Phase 2 of the initial run:
+Re-run the deterministic classifier over the full provider set — the same
+command as Phase 1 of the initial run, with **no** provider ids appended:
 
 ```bash
-PROVIDER_ID=<dotted.id>
-PROVIDER_PATH=$(echo "$PROVIDER_ID" | tr '.' '/')   # folder path (slashes)
-PROVIDER_TAG=$(echo "$PROVIDER_ID" | tr '.' '-')    # tag segment (hyphens)
-# Same tag-selection rules as Phase 2: hyphenated tag segment, and skip 
sentinel
-# (99.98.0/99.99.0) and rc tags so we compare against the last *final* release.
-LAST_TAG=$(git tag --list "providers-${PROVIDER_TAG}/*" --sort=-v:refname \
-    | grep -vE '/99\.9[0-9]\.' | grep -vE 'rc[0-9]+$' | head -n1)
-git log --pretty=format:'%H %h %cd %s' --date=short \
-    "${LAST_TAG}..apache-https-for-providers/main" \
-    -- "providers/${PROVIDER_PATH}/"
+breeze release-management classify-provider-changes \
+    --base-branch main \
+    --output-file /tmp/provider-changes.json
 ```
 
-Then identify **new** commits by comparing PR numbers to the existing
-changelog. A commit is "new" if its `(#NNNN)` PR suffix is **not** already
-present anywhere in `providers/${PROVIDER_PATH}/docs/changelog.rst`. This
-is exactly the same predicate breeze uses internally (see
-`_generate_new_changelog` append branch in
-`dev/breeze/src/airflow_breeze/prepare_providers/provider_documentation.py`).
+Then reduce its output to commits **not yet recorded** in the matching
+provider's changelog. A commit is unrecorded when its `#NNNN` PR number
+appears nowhere in `providers/<provider-path>/docs/changelog.rst` — the same
+predicate breeze uses internally (see the `_generate_new_changelog` append
+branch in
+`dev/breeze/src/airflow_breeze/prepare_providers/provider_documentation.py`):
 
 ```bash
-CHANGELOG="providers/${PROVIDER_PATH}/docs/changelog.rst"
-# pseudo: emit only commits whose #NNNN is NOT in the changelog
-git log --pretty=format:'%H %h %cd %s' --date=short \
-    "${LAST_TAG}..apache-https-for-providers/main" \
-    -- "providers/${PROVIDER_PATH}/" \
-  | python3 -c "
-import re, sys
-seen = open('${CHANGELOG}').read()
-for line in sys.stdin:
-    m = re.search(r'\(#(\d+)\)', line)
-    if not m or f'(#{m.group(1)})' not in seen:
-        print(line, end='')
-"
+python3 - <<'EOF'
+import json, pathlib
+
+data = json.loads(pathlib.Path("/tmp/provider-changes.json").read_text())
+for provider_id, info in sorted(data["providers"].items()):
+    base = pathlib.Path("providers") / provider_id.replace(".", "/")
+    changelog = base / "docs" / "changelog.rst"
+    seen = changelog.read_text() if changelog.exists() else ""
+    doc_only = base / "docs" / ".latest-doc-only-change.txt"
+    doc_hash = doc_only.read_text().strip() if doc_only.exists() else ""
+    for commit in info.get("commits", []):
+        pr = commit.get("pr")
+        # Substring match, NOT "(#NNNN)": a collapsed within-wave entry reads
+        # "(#68082, #70014)", which an exact-suffix match would report as new.
+        if pr and f"#{pr}" in seen:
+            continue
+        if not pr and commit["subject"].replace("`", "'") in seen:
+            continue
+        if doc_hash and commit["hash"].startswith(doc_hash[:10]):
+            continue
+        print(f"{provider_id}\t{commit['hash'][:10]}\t#{pr}\t"
+              f"{commit['classification']}\t{commit['subject']}")
+EOF
 ```
 
-If there are zero new commits for a provider, skip it.
+Split the result into two buckets. A provider is **already in the wave** iff
+its `provider.yaml` changed on this branch:
+
+```bash
+git diff --name-only <base-branch>..HEAD -- '**/provider.yaml' \
+  | sed 's|providers/||; s|/provider.yaml||' | tr '/' '.' | sort
+```
+
+- **Bucket A — already in the wave.** Fold the unrecorded commits into the
+  existing version section: continue through Incremental Phases 3 → 3.5 → 4a.
+- **Bucket B — not in the wave.** The provider has unrecorded commits but no
+  new version section, so it is a candidate to *join*. Classify it
+  (Incremental Phase 3), then take it to **Incremental Phase 3.6**.
+- **Bucket C — in the wave but no longer warranting a release.** The sweep
+  above only finds commits *missing* from a wave; this bucket is the opposite
+  direction, and nothing else in the flow looks for it. A provider that review
+  has since concluded is internal-only or documentation-only still carries the
+  version bump and changelog section written by the initial run, so it would
+  still be built and uploaded to PyPI. Find these by re-reading the entries of
+  each in-wave provider's newest changelog section: if every entry is
+  `Doc-only`, or review reclassified the last remaining non-doc entry as
+  documentation, the provider should leave the wave.
+
+  Drop it back with the dedicated command rather than editing the files by
+  hand — it restores `provider.yaml` and `changelog.rst` to their released
+  state and writes the marker in one step:
+
+  ```bash
+  breeze release-management prepare-provider-documentation --mark-doc-only 
<provider-id>
+  ```
+
+  Then commit `providers/<provider-path>/docs/.latest-doc-only-change.txt`.
+  **Ask the release manager before doing it** — taking a provider out of a wave
+  is their decision, and a `Misc` entry that merely *looks* internal may still
+  be something they want released.
+
+Most Bucket B rows are ordinary noise — repo-wide tooling and test commits
+that correctly keep a provider out of the release. A Bucket B provider whose
+unrecorded commits are **all** `skip` stays out silently; escalate only when
+at least one classifies as something other than `skip`.
+
+If a provider has zero unrecorded commits, skip it.
+
+> [!NOTE]
+> **Worked example — the miss this phase exists to prevent.** In the
+> 2026-07-22 wave, `atlassian.jira` had nothing pending when the wave was cut
+> at 22:15. PR #70224 merged at 03:41 the next morning, adding a `Verify SSL`
+> conn-field to `providers/atlassian/jira/provider.yaml`. The branch was
+> rebased past that commit and an incremental fold-in ran — but because
+> `atlassian.jira` had no version section, the old per-wave-provider loop
+> never looked at it, and the provider was still missing from the release PR
+> a day later. The full sweep above surfaces it; Phase 3.6 asks about it.
 
 ### Incremental Phase 3 — Classify the new commits
 
@@ -659,8 +973,38 @@ update the version header in `changelog.rst`'s new section 
to match.
 the old version, the new version, and which incoming commit forced the
 escalation. Don't silently re-bump.
 
+### Incremental Phase 3.6 — Ask before adding a provider to the wave
+
+Every Bucket B provider (Incremental Phase 2) with at least one unrecorded
+commit classified as something other than `skip` is a provider the release is
+currently missing. **Never add one silently, and never drop one silently —
+always ask.** The release manager owns the scope of the release; your job is
+to make sure the choice is made deliberately rather than by omission.
+
+On an **ad-hoc** release the answer is usually "leave it out" — the provider
+list is a fixed input — but still surface it, so the release manager knows the
+change exists and needs a later release.
+
+Ask once per provider. State what landed, why it is user-facing, when it
+landed relative to the cut, and the version consequence of each option:
+
+> Provider `atlassian.jira` is **not** in this wave, but PR #70224 ("Fix
+> conn-fields check crash for nested provider packages", merged 2026-07-23
+> 03:41 — about 5h after the wave was cut) added a `Verify SSL` conn-field and
+> `ui-field-behaviour` to its `provider.yaml`. That is shipped metadata: it
+> changes the Jira connection form. Its other pending commits (#67978, #68991)
+> are test/template-only.
+> **Add it to the wave** (3.3.4 → 3.3.5, most-impactful `misc`), or **leave it
+> out** and let the change ride the next release?
+
+Record the answer. If the release manager says **add**, the provider follows
+the *initial-run* application path rather than the append path — see
+Incremental Phase 4b.
+
 ### Incremental Phase 4 — Apply the new entries
 
+#### 4a. Providers already in the wave — append to the existing section
+
 For each new commit, insert into the existing latest-version section of
 `changelog.rst` under the right header:
 
@@ -680,13 +1024,39 @@ above the next existing section, matching the order in
 `CHANGELOG_TEMPLATE.rst.jinja2`:
 `Breaking changes` → `Features` → `Bug Fixes` → `Misc` → `Doc-only`.
 
+Insert each entry at its **merge-order position** within the section — new
+commits are newer than everything already there, so they go at the *top*, not
+appended at the bottom. Appending is what drifts incremental providers off the
+format; `check_changelog_entries.py --fix` repairs it either way, so run it
+after this phase.
+
 If you re-bumped the version in Incremental Phase 3.5, also add or remove the
 `.. note::` block about the Airflow min version requirement to match the
 new bump kind.
 
 If a new commit is classified `breaking`, add (or extend) a `.. note::` at the
 top of the version section explaining what breaks and how users should adapt,
-exactly as in the breaking-change note rule in Phase 4b.
+exactly as in the breaking-change note rule in the initial run's Phase 4b.
+
+#### 4b. Providers joining the wave — apply the initial-run path
+
+A provider the release manager confirmed in Incremental Phase 3.6 has no new
+version section yet, so there is nothing to append to. Run the steps of the
+**initial run's Phase 4** for that provider only:
+
+- **initial-run 4a** — prepend the new version to `provider.yaml` and refresh
+  `source-date-epoch`. Reuse the epoch the rest of the wave already carries
+  (`grep -h source-date-epoch` across the providers this branch bumped) so the
+  release stays on a single value rather than gaining a stray third one.
+- **initial-run 4b** — write a complete new version section in
+  `changelog.rst`: the classified commits under their headers, **every**
+  `skip` commit in the `.. Below changes are excluded …` block, and a
+  `.. note::` if the bump is breaking or a min-Airflow bump.
+- **initial-run 4c** — re-run `--reapply-templates-only` so the joining
+  provider's `__init__.py`, `README.rst`, `pyproject.toml`, `index.rst` pick
+  up the new version. Expect a diff for exactly that provider and no other.
+- **initial-run 4d** — re-run `update-providers-next-version`: a `# use next
+  version` pin pointing at the joining provider must now resolve.
 
 ### Incremental Phase 5 — Validate
 
@@ -697,10 +1067,17 @@ no leftover "Please review …" markers from a prior 
interactive
 incremental flow before invoking this skill), remove them as part of the
 final pass. Then walk the diff with the release manager.
 
+Also confirm that **every Bucket B provider from Incremental Phase 2 was
+either added or explicitly declined** by the release manager — none dropped
+by omission. Re-run the Phase 2 sweep after applying; the only providers it
+should still report are ones whose unrecorded commits are all `skip`, plus any
+the release manager deliberately left out.
+
 If the incremental run bumped a provider to a *new* version (Incremental
-Phase 3.5), re-run Phase 4d (`update-providers-next-version`) as well — a
-`# use next version` pin on that provider must resolve to the freshly
-bumped version before the rebased PR is pushed.
+Phase 3.5) or added one to the wave (Incremental Phase 3.6), re-run Phase 4d
+(`update-providers-next-version`) as well — a `# use next version` pin on that
+provider must resolve to the freshly bumped version before the rebased PR is
+pushed.
 
 ---
 
@@ -739,6 +1116,9 @@ two alternatives with the version-bump consequence.
 ### Things you must NOT do silently
 
 - Bump major version without explicit confirmation from the release manager.
+- Add a provider to the wave — or leave one out — without asking
+  (Incremental Phase 3.6). Scope is the release manager's call, and a
+  provider dropped by omission is as much a silent decision as one added.
 - Reclassify a commit the RM already confirmed.
 - Skip commits that don't fit a category — flag them as `?` and ask.
 - Edit `commits.rst`, `index.rst`, `__init__.py`, `README.rst`,
diff --git a/dev/README_RELEASE_PROVIDERS.md b/dev/README_RELEASE_PROVIDERS.md
index 34c2132bf0f..eedaa88cbd8 100644
--- a/dev/README_RELEASE_PROVIDERS.md
+++ b/dev/README_RELEASE_PROVIDERS.md
@@ -378,6 +378,56 @@ In case you want to also release a pre-installed provider 
that is in ``not-ready
 you want to release it before you switch their state to ``ready``), pass
 ``--include-not-ready-providers``.
 
+### Dropping a prepared provider back to doc-only (no PyPI artifact)
+
+Two different outcomes are both called "doc-only", and the difference decides 
whether the provider
+gets a PyPI release at all:
+
+| | What it means | PyPI artifact |
+|---|---|---|
+| A `doc-only` entry in the changelog | The provider *is* released; one of the 
entries in the release happens to be documentation | **Yes** |
+| The `.latest-doc-only-change.txt` marker | The provider is *not* released at 
all; only its documentation is republished | **No** |
+
+The second case comes up when a provider was already prepared with, say, a 
`Misc` entry, and review
+then concludes the change is internal or documentation only, so there is 
nothing for users to install.
+Changing the changelog entry is not enough — the version bump and the 
changelog stay prepared, and the
+provider would still be built and uploaded. Drop the provider back to doc-only 
with:
+
+```shell script
+breeze release-management prepare-provider-documentation --mark-doc-only 
PROVIDER [MORE PROVIDERS]
+```
+
+This restores the provider's `provider.yaml` and `changelog.rst` to their 
released state, then writes
+`providers/PROVIDER/docs/.latest-doc-only-change.txt`. No version bump, no 
changelog section, no
+distribution. It needs an explicit list of providers — it takes them out of 
the release, so it will
+not default to every provider.
+
+Commit the marker file afterwards. It is the only artifact of the whole 
sequence, and it must be
+committed or the next release will prepare the provider again:
+
+```shell script
+git add providers/PROVIDER/docs/.latest-doc-only-change.txt
+```
+
+Doing it by hand is the same three steps: restore those two files, re-run
+`prepare-provider-documentation PROVIDER`, and answer **`N`** to
+`Does the provider: PROVIDER have any changes apart from 'doc-only'?`. Note 
that the interactive
+prompt is not reachable during `--incremental-update`, which answers every 
question with "yes" —
+that is what `--mark-doc-only` is for.
+
+The marker holds the full commit hash of the latest change that was declared 
doc-only. On the next
+release, the tooling counts commits since that hash rather than since the last 
release tag, so:
+
+* if nothing landed since the marker, the provider is skipped with
+  `The provider has doc-only changes since the last release. Skipping`;
+* if something did land, only the commits after the marker are classified, so 
the changes already
+  declared doc-only are not offered for classification a second time.
+
+> [!NOTE]
+> The same applies when using the `prepare-providers-documentation` skill — it 
classifies commits,
+> but the decision that a prepared provider should not be released at all is 
still made by the
+> release manager, and is still recorded by this marker file.
+
 ## Update versions of dependent providers to the next version
 
 Sometimes when contributors want to use next version of a dependent provider, 
instead of
@@ -458,6 +508,14 @@ following labels to the PR (if they aren't already set 
from the original PR):
 * `skip common compat check`
 * `allow provider dependency bump`
 
+The rebase before merging is also the point to check the wave in the other 
direction. The incremental
+flow looks for commits that are *missing* from the release; it does not look 
for providers that are in
+the release but should no longer be there. If review concluded that a prepared 
provider's only changes
+are internal or documentation, that provider still carries its version bump 
and changelog section, and
+it would still be built and uploaded. Drop it back with [Dropping a prepared 
provider back to
+doc-only](#dropping-a-prepared-provider-back-to-doc-only-no-pypi-artifact) 
before merging, so the
+decision made in review is actually reflected in what gets released.
+
 Once approved, merge it - be careful to do it quickly so that no new PRs are 
merged for
 providers in the meantime; if they are, you'd miss them in the changelog.
 
diff --git 
a/dev/breeze/doc/images/output_release-management_prepare-provider-documentation.svg
 
b/dev/breeze/doc/images/output_release-management_prepare-provider-documentation.svg
index 571cc1a3c80..63e6fbb06f0 100644
--- 
a/dev/breeze/doc/images/output_release-management_prepare-provider-documentation.svg
+++ 
b/dev/breeze/doc/images/output_release-management_prepare-provider-documentation.svg
@@ -1,4 +1,4 @@
-<svg class="rich-terminal" viewBox="0 0 1482 1294.3999999999999" 
xmlns="http://www.w3.org/2000/svg";>
+<svg class="rich-terminal" viewBox="0 0 1482 1392.0" 
xmlns="http://www.w3.org/2000/svg";>
     <!-- Generated with Rich https://www.textualize.io -->
     <style>
 
@@ -43,7 +43,7 @@
 
     <defs>
     <clipPath 
id="breeze-release-management-prepare-provider-documentation-clip-terminal">
-      <rect x="0" y="0" width="1463.0" height="1243.3999999999999" />
+      <rect x="0" y="0" width="1463.0" height="1341.0" />
     </clipPath>
     <clipPath 
id="breeze-release-management-prepare-provider-documentation-line-0">
     <rect x="0" y="1.5" width="1464" height="24.65"/>
@@ -195,9 +195,21 @@
 <clipPath 
id="breeze-release-management-prepare-provider-documentation-line-49">
     <rect x="0" y="1197.1" width="1464" height="24.65"/>
             </clipPath>
+<clipPath 
id="breeze-release-management-prepare-provider-documentation-line-50">
+    <rect x="0" y="1221.5" width="1464" height="24.65"/>
+            </clipPath>
+<clipPath 
id="breeze-release-management-prepare-provider-documentation-line-51">
+    <rect x="0" y="1245.9" width="1464" height="24.65"/>
+            </clipPath>
+<clipPath 
id="breeze-release-management-prepare-provider-documentation-line-52">
+    <rect x="0" y="1270.3" width="1464" height="24.65"/>
+            </clipPath>
+<clipPath 
id="breeze-release-management-prepare-provider-documentation-line-53">
+    <rect x="0" y="1294.7" width="1464" height="24.65"/>
+            </clipPath>
     </defs>
 
-    <rect fill="#292929" stroke="rgba(255,255,255,0.35)" stroke-width="1" 
x="1" y="1" width="1480" height="1292.4" rx="8"/><text 
class="breeze-release-management-prepare-provider-documentation-title" 
fill="#c5c8c6" text-anchor="middle" x="740" 
y="27">Command:&#160;release-management&#160;prepare-provider-documentation</text>
+    <rect fill="#292929" stroke="rgba(255,255,255,0.35)" stroke-width="1" 
x="1" y="1" width="1480" height="1390" rx="8"/><text 
class="breeze-release-management-prepare-provider-documentation-title" 
fill="#c5c8c6" text-anchor="middle" x="740" 
y="27">Command:&#160;release-management&#160;prepare-provider-documentation</text>
             <g transform="translate(26,22)">
             <circle cx="0" cy="0" r="7" fill="#ff5f57"/>
             <circle cx="22" cy="0" r="7" fill="#febc2e"/>
@@ -229,35 +241,39 @@
 </text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="483.6" textLength="12.2" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-19)">│</text><text
 class="breeze-release-management-prepare-provider-documentation-r1" x="353.8" 
y="483.6" textLength="366" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-19)">2025-11-16&#160;or&#160;2025-11-16_01).&#160;</text><text
 class="breeze-release-management-p [...]
 </text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="508" textLength="12.2" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-20)">│</text><text
 class="breeze-release-management-prepare-provider-documentation-r4" x="24.4" 
y="508" textLength="305" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-20)">--incremental-update&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-release-management-p [...]
 </text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="532.4" textLength="12.2" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-21)">│</text><text
 class="breeze-release-management-prepare-provider-documentation-r1" x="353.8" 
y="532.4" textLength="1085.8" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-21)">changes.&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#1
 [...]
-</text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="556.8" textLength="12.2" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-22)">│</text><text
 class="breeze-release-management-prepare-provider-documentation-r4" x="24.4" 
y="556.8" textLength="305" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-22)">--only-min-version-update</text><text
 class="breeze-release-management-prepare-provider-docum [...]
-</text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="581.2" textLength="12.2" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-23)">│</text><text
 class="breeze-release-management-prepare-provider-documentation-r1" x="353.8" 
y="581.2" textLength="1085.8" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-23)">documentation&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#16
 [...]
-</text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="605.6" textLength="12.2" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-24)">│</text><text
 class="breeze-release-management-prepare-provider-documentation-r4" x="24.4" 
y="605.6" textLength="305" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-24)">--reapply-templates-only&#160;</text><text
 class="breeze-release-management-prepare-provider- [...]
-</text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="630" textLength="12.2" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-25)">│</text><text
 class="breeze-release-management-prepare-provider-documentation-r1" x="353.8" 
y="630" textLength="1085.8" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-25)">to&#160;regenerate&#160;documentation.&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&
 [...]
-</text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="654.4" textLength="12.2" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-26)">│</text><text
 class="breeze-release-management-prepare-provider-documentation-r4" x="24.4" 
y="654.4" textLength="305" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-26)">--non-interactive&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-r [...]
-</text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="678.8" textLength="12.2" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-27)">│</text><text
 class="breeze-release-management-prepare-provider-documentation-r1" x="353.8" 
y="678.8" textLength="1085.8" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-27)">releasefor&#160;providers&#160;prepared&#160;for&#160;release&#160;-&#160;useful&#160;to&
 [...]
-</text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="703.2" textLength="12.2" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-28)">│</text><text
 class="breeze-release-management-prepare-provider-documentation-r1" x="353.8" 
y="703.2" textLength="1085.8" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-28)">mode&#160;in&#160;CI.&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#
 [...]
-</text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="727.6" textLength="1464" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-29)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-release-management-prepare-provider-documentation-r1" x="1464" 
y="727.6" textLength="12.2" 
clip-path="url(#breeze-release-management-prepare-provid [...]
-</text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="752" textLength="24.4" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-30)">╭─</text><text
 class="breeze-release-management-prepare-provider-documentation-r5" x="24.4" 
y="752" textLength="366" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-30)">&#160;Select&#160;non-regular&#160;providers&#160;</text><text
 class="breeze-release-management- [...]
-</text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="776.4" textLength="12.2" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-31)">│</text><text
 class="breeze-release-management-prepare-provider-documentation-r4" x="24.4" 
y="776.4" textLength="353.8" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-31)">--include-not-ready-providers</text><text
 class="breeze-release-management-prepare-provider [...]
-</text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="800.8" textLength="12.2" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-32)">│</text><text
 class="breeze-release-management-prepare-provider-documentation-r4" x="24.4" 
y="800.8" textLength="353.8" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-32)">--include-removed-providers&#160;&#160;</text><text
 class="breeze-release-management-prepar [...]
+</text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="556.8" textLength="12.2" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-22)">│</text><text
 class="breeze-release-management-prepare-provider-documentation-r4" x="24.4" 
y="556.8" textLength="305" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-22)">--mark-doc-only&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class [...]
+</text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="581.2" textLength="12.2" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-23)">│</text><text
 class="breeze-release-management-prepare-provider-documentation-r1" x="353.8" 
y="581.2" textLength="1085.8" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-23)">the&#160;released&#160;state&#160;and&#160;record&#160;the&#160;doc-only&#160;marker&#160
 [...]
+</text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="605.6" textLength="12.2" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-24)">│</text><text
 class="breeze-release-management-prepare-provider-documentation-r1" x="353.8" 
y="605.6" textLength="1085.8" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-24)">that&#160;an&#160;already-prepared&#160;provider&#160;has&#160;no&#160;user-facing&#160;c
 [...]
+</text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="630" textLength="12.2" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-25)">│</text><text
 class="breeze-release-management-prepare-provider-documentation-r1" x="353.8" 
y="630" textLength="1085.8" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-25)">of&#160;providers.&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#1
 [...]
+</text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="654.4" textLength="12.2" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-26)">│</text><text
 class="breeze-release-management-prepare-provider-documentation-r4" x="24.4" 
y="654.4" textLength="305" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-26)">--only-min-version-update</text><text
 class="breeze-release-management-prepare-provider-docum [...]
+</text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="678.8" textLength="12.2" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-27)">│</text><text
 class="breeze-release-management-prepare-provider-documentation-r1" x="353.8" 
y="678.8" textLength="1085.8" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-27)">documentation&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#16
 [...]
+</text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="703.2" textLength="12.2" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-28)">│</text><text
 class="breeze-release-management-prepare-provider-documentation-r4" x="24.4" 
y="703.2" textLength="305" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-28)">--reapply-templates-only&#160;</text><text
 class="breeze-release-management-prepare-provider- [...]
+</text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="727.6" textLength="12.2" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-29)">│</text><text
 class="breeze-release-management-prepare-provider-documentation-r1" x="353.8" 
y="727.6" textLength="1085.8" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-29)">to&#160;regenerate&#160;documentation.&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#1
 [...]
+</text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="752" textLength="12.2" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-30)">│</text><text
 class="breeze-release-management-prepare-provider-documentation-r4" x="24.4" 
y="752" textLength="305" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-30)">--non-interactive&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-relea [...]
+</text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="776.4" textLength="12.2" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-31)">│</text><text
 class="breeze-release-management-prepare-provider-documentation-r1" x="353.8" 
y="776.4" textLength="1085.8" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-31)">releasefor&#160;providers&#160;prepared&#160;for&#160;release&#160;-&#160;useful&#160;to&
 [...]
+</text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="800.8" textLength="12.2" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-32)">│</text><text
 class="breeze-release-management-prepare-provider-documentation-r1" x="353.8" 
y="800.8" textLength="1085.8" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-32)">mode&#160;in&#160;CI.&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#
 [...]
 </text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="825.2" textLength="1464" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-33)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-release-management-prepare-provider-documentation-r1" x="1464" 
y="825.2" textLength="12.2" 
clip-path="url(#breeze-release-management-prepare-provid [...]
-</text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="849.6" textLength="24.4" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-34)">╭─</text><text
 class="breeze-release-management-prepare-provider-documentation-r5" x="24.4" 
y="849.6" textLength="146.4" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-34)">&#160;Skip&#160;steps&#160;</text><text
 class="breeze-release-management-prepare-provider- [...]
-</text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="874" textLength="12.2" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-35)">│</text><text
 class="breeze-release-management-prepare-provider-documentation-r4" x="24.4" 
y="874" textLength="195.2" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-35)">--skip-git-fetch</text><text
 class="breeze-release-management-prepare-provider-documentation-r1 [...]
-</text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="898.4" textLength="12.2" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-36)">│</text><text
 class="breeze-release-management-prepare-provider-documentation-r1" x="244" 
y="898.4" textLength="1195.6" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-36)">is&#160;recreated&#160;and&#160;fetched&#160;to&#160;make&#160;sure&#160;that&#160;it&#x27;
 [...]
-</text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="922.8" textLength="12.2" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-37)">│</text><text
 class="breeze-release-management-prepare-provider-documentation-r4" x="24.4" 
y="922.8" textLength="195.2" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-37)">--skip-changelog</text><text
 class="breeze-release-management-prepare-provider-documentatio [...]
-</text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="947.2" textLength="12.2" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-38)">│</text><text
 class="breeze-release-management-prepare-provider-documentation-r4" x="24.4" 
y="947.2" textLength="195.2" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-38)">--skip-readme&#160;&#160;&#160;</text><text
 class="breeze-release-management-prepare-provid [...]
-</text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="971.6" textLength="1464" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-39)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-release-management-prepare-provider-documentation-r1" x="1464" 
y="971.6" textLength="12.2" 
clip-path="url(#breeze-release-management-prepare-provid [...]
-</text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="996" textLength="24.4" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-40)">╭─</text><text
 class="breeze-release-management-prepare-provider-documentation-r5" x="24.4" 
y="996" textLength="219.6" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-40)">&#160;Advanced&#160;options&#160;</text><text
 class="breeze-release-management-prepare-provide [...]
-</text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="1020.4" textLength="12.2" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-41)">│</text><text
 class="breeze-release-management-prepare-provider-documentation-r4" x="24.4" 
y="1020.4" textLength="231.8" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-41)">--base-branch&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-release-manag [...]
-</text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="1044.8" textLength="12.2" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-42)">│</text><text
 class="breeze-release-management-prepare-provider-documentation-r1" x="329.4" 
y="1044.8" textLength="97.6" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-42)">branch)&#160;</text><text
 class="breeze-release-management-prepare-provider-documentation [...]
-</text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="1069.2" textLength="12.2" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-43)">│</text><text
 class="breeze-release-management-prepare-provider-documentation-r4" x="24.4" 
y="1069.2" textLength="231.8" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-43)">--github-repository</text><text
 class="breeze-release-management-prepare-provider-documen [...]
-</text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="1093.6" textLength="1464" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-44)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-release-management-prepare-provider-documentation-r1" x="1464" 
y="1093.6" textLength="12.2" 
clip-path="url(#breeze-release-management-prepare-prov [...]
-</text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="1118" textLength="24.4" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-45)">╭─</text><text
 class="breeze-release-management-prepare-provider-documentation-r5" x="24.4" 
y="1118" textLength="195.2" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-45)">&#160;Common&#160;options&#160;</text><text
 class="breeze-release-management-prepare-provide [...]
-</text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="1142.4" textLength="12.2" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-46)">│</text><text
 class="breeze-release-management-prepare-provider-documentation-r4" x="24.4" 
y="1142.4" textLength="109.8" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-46)">--verbose</text><text
 class="breeze-release-management-prepare-provider-documentation-r7" [...]
-</text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="1166.8" textLength="12.2" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-47)">│</text><text
 class="breeze-release-management-prepare-provider-documentation-r4" x="24.4" 
y="1166.8" textLength="109.8" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-47)">--answer&#160;</text><text
 class="breeze-release-management-prepare-provider-documentatio [...]
-</text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="1191.2" textLength="12.2" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-48)">│</text><text
 class="breeze-release-management-prepare-provider-documentation-r4" x="24.4" 
y="1191.2" textLength="109.8" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-48)">--dry-run</text><text
 class="breeze-release-management-prepare-provider-documentation-r7" [...]
-</text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="1215.6" textLength="12.2" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-49)">│</text><text
 class="breeze-release-management-prepare-provider-documentation-r4" x="24.4" 
y="1215.6" textLength="109.8" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-49)">--help&#160;&#160;&#160;</text><text
 class="breeze-release-management-prepare-provider-do [...]
-</text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="1240" textLength="1464" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-50)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-release-management-prepare-provider-documentation-r1" x="1464" 
y="1240" textLength="12.2" 
clip-path="url(#breeze-release-management-prepare-provider [...]
+</text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="849.6" textLength="24.4" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-34)">╭─</text><text
 class="breeze-release-management-prepare-provider-documentation-r5" x="24.4" 
y="849.6" textLength="366" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-34)">&#160;Select&#160;non-regular&#160;providers&#160;</text><text
 class="breeze-release-managem [...]
+</text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="874" textLength="12.2" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-35)">│</text><text
 class="breeze-release-management-prepare-provider-documentation-r4" x="24.4" 
y="874" textLength="353.8" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-35)">--include-not-ready-providers</text><text
 class="breeze-release-management-prepare-provider-doc [...]
+</text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="898.4" textLength="12.2" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-36)">│</text><text
 class="breeze-release-management-prepare-provider-documentation-r4" x="24.4" 
y="898.4" textLength="353.8" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-36)">--include-removed-providers&#160;&#160;</text><text
 class="breeze-release-management-prepar [...]
+</text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="922.8" textLength="1464" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-37)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-release-management-prepare-provider-documentation-r1" x="1464" 
y="922.8" textLength="12.2" 
clip-path="url(#breeze-release-management-prepare-provid [...]
+</text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="947.2" textLength="24.4" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-38)">╭─</text><text
 class="breeze-release-management-prepare-provider-documentation-r5" x="24.4" 
y="947.2" textLength="146.4" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-38)">&#160;Skip&#160;steps&#160;</text><text
 class="breeze-release-management-prepare-provider- [...]
+</text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="971.6" textLength="12.2" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-39)">│</text><text
 class="breeze-release-management-prepare-provider-documentation-r4" x="24.4" 
y="971.6" textLength="195.2" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-39)">--skip-git-fetch</text><text
 class="breeze-release-management-prepare-provider-documentatio [...]
+</text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="996" textLength="12.2" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-40)">│</text><text
 class="breeze-release-management-prepare-provider-documentation-r1" x="244" 
y="996" textLength="1195.6" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-40)">is&#160;recreated&#160;and&#160;fetched&#160;to&#160;make&#160;sure&#160;that&#160;it&#x27;s&#1
 [...]
+</text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="1020.4" textLength="12.2" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-41)">│</text><text
 class="breeze-release-management-prepare-provider-documentation-r4" x="24.4" 
y="1020.4" textLength="195.2" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-41)">--skip-changelog</text><text
 class="breeze-release-management-prepare-provider-documentat [...]
+</text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="1044.8" textLength="12.2" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-42)">│</text><text
 class="breeze-release-management-prepare-provider-documentation-r4" x="24.4" 
y="1044.8" textLength="195.2" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-42)">--skip-readme&#160;&#160;&#160;</text><text
 class="breeze-release-management-prepare-prov [...]
+</text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="1069.2" textLength="1464" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-43)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-release-management-prepare-provider-documentation-r1" x="1464" 
y="1069.2" textLength="12.2" 
clip-path="url(#breeze-release-management-prepare-prov [...]
+</text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="1093.6" textLength="24.4" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-44)">╭─</text><text
 class="breeze-release-management-prepare-provider-documentation-r5" x="24.4" 
y="1093.6" textLength="219.6" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-44)">&#160;Advanced&#160;options&#160;</text><text
 class="breeze-release-management-prepare-p [...]
+</text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="1118" textLength="12.2" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-45)">│</text><text
 class="breeze-release-management-prepare-provider-documentation-r4" x="24.4" 
y="1118" textLength="231.8" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-45)">--base-branch&#160;&#160;&#160;&#160;&#160;&#160;</text><text
 class="breeze-release-managemen [...]
+</text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="1142.4" textLength="12.2" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-46)">│</text><text
 class="breeze-release-management-prepare-provider-documentation-r1" x="329.4" 
y="1142.4" textLength="97.6" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-46)">branch)&#160;</text><text
 class="breeze-release-management-prepare-provider-documentation [...]
+</text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="1166.8" textLength="12.2" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-47)">│</text><text
 class="breeze-release-management-prepare-provider-documentation-r4" x="24.4" 
y="1166.8" textLength="231.8" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-47)">--github-repository</text><text
 class="breeze-release-management-prepare-provider-documen [...]
+</text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="1191.2" textLength="1464" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-48)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-release-management-prepare-provider-documentation-r1" x="1464" 
y="1191.2" textLength="12.2" 
clip-path="url(#breeze-release-management-prepare-prov [...]
+</text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="1215.6" textLength="24.4" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-49)">╭─</text><text
 class="breeze-release-management-prepare-provider-documentation-r5" x="24.4" 
y="1215.6" textLength="195.2" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-49)">&#160;Common&#160;options&#160;</text><text
 class="breeze-release-management-prepare-pro [...]
+</text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="1240" textLength="12.2" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-50)">│</text><text
 class="breeze-release-management-prepare-provider-documentation-r4" x="24.4" 
y="1240" textLength="109.8" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-50)">--verbose</text><text
 class="breeze-release-management-prepare-provider-documentation-r7" x=" [...]
+</text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="1264.4" textLength="12.2" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-51)">│</text><text
 class="breeze-release-management-prepare-provider-documentation-r4" x="24.4" 
y="1264.4" textLength="109.8" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-51)">--answer&#160;</text><text
 class="breeze-release-management-prepare-provider-documentatio [...]
+</text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="1288.8" textLength="12.2" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-52)">│</text><text
 class="breeze-release-management-prepare-provider-documentation-r4" x="24.4" 
y="1288.8" textLength="109.8" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-52)">--dry-run</text><text
 class="breeze-release-management-prepare-provider-documentation-r7" [...]
+</text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="1313.2" textLength="12.2" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-53)">│</text><text
 class="breeze-release-management-prepare-provider-documentation-r4" x="24.4" 
y="1313.2" textLength="109.8" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-53)">--help&#160;&#160;&#160;</text><text
 class="breeze-release-management-prepare-provider-do [...]
+</text><text 
class="breeze-release-management-prepare-provider-documentation-r5" x="0" 
y="1337.6" textLength="1464" 
clip-path="url(#breeze-release-management-prepare-provider-documentation-line-54)">╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</text><text
 class="breeze-release-management-prepare-provider-documentation-r1" x="1464" 
y="1337.6" textLength="12.2" 
clip-path="url(#breeze-release-management-prepare-prov [...]
 </text>
     </g>
     </g>
diff --git 
a/dev/breeze/doc/images/output_release-management_prepare-provider-documentation.txt
 
b/dev/breeze/doc/images/output_release-management_prepare-provider-documentation.txt
index 3c752d93ba4..7480839de29 100644
--- 
a/dev/breeze/doc/images/output_release-management_prepare-provider-documentation.txt
+++ 
b/dev/breeze/doc/images/output_release-management_prepare-provider-documentation.txt
@@ -1 +1 @@
-6ba260deb12239cb8c3cdbc9b8bbe2f4
+69c552f639d08574fcb38c56f19b73a7
diff --git 
a/dev/breeze/src/airflow_breeze/commands/release_management_commands.py 
b/dev/breeze/src/airflow_breeze/commands/release_management_commands.py
index 2f688ca4b58..30afff1806b 100644
--- a/dev/breeze/src/airflow_breeze/commands/release_management_commands.py
+++ b/dev/breeze/src/airflow_breeze/commands/release_management_commands.py
@@ -977,6 +977,13 @@ def classify_provider_changes(
     is_flag=True,
     help="Runs incremental update only after rebase of earlier branch to check 
if there are no changes.",
 )
[email protected](
+    "--mark-doc-only",
+    is_flag=True,
+    help="Take the named providers back out of the release: restore their 
version and changelog to the "
+    "released state and record the doc-only marker to commit. Use when review 
concludes that an "
+    "already-prepared provider has no user-facing changes. Requires an 
explicit list of providers.",
+)
 @click.option(
     "--skip-readme",
     is_flag=True,
@@ -1007,6 +1014,7 @@ def prepare_provider_documentation(
     skip_changelog: bool,
     skip_readme: bool,
     incremental_update: bool,
+    mark_doc_only: bool,
     release_date: str | None,
 ):
     from airflow_breeze.prepare_providers.provider_documentation import (
@@ -1015,6 +1023,7 @@ def prepare_provider_documentation(
         PrepareReleaseDocsNoChangesException,
         PrepareReleaseDocsUserQuitException,
         PrepareReleaseDocsUserSkippedException,
+        drop_provider_to_doc_only,
         update_changelog,
         update_index_rst,
         update_min_airflow_version_and_build_files,
@@ -1025,10 +1034,19 @@ def prepare_provider_documentation(
         console_print("[error]Release date is required unless 
--only-min-version-update is used![/]")
         sys.exit(1)
 
+    if mark_doc_only and not provider_distributions:
+        console_print(
+            "[error]--mark-doc-only takes the named providers out of the 
release, so it needs an "
+            "explicit list of providers rather than defaulting to all of 
them![/]"
+        )
+        sys.exit(1)
+
     perform_environment_checks()
     fix_ownership_using_docker()
     cleanup_python_generated_files()
-    if incremental_update:
+    # Forcing "yes" keeps the incremental pass from re-asking about every 
provider, which also puts
+    # the reclassify-to-doc-only prompt out of reach - --mark-doc-only is how 
that decision is applied.
+    if incremental_update and not mark_doc_only:
         set_forced_answer("yes")
     if not provider_distributions:
         provider_distributions = get_available_distributions(
@@ -1048,6 +1066,9 @@ def prepare_provider_documentation(
     for provider_id in provider_distributions:
         try:
             provider_metadata = basic_provider_checks(provider_id)
+            if mark_doc_only:
+                with ci_group(f"Marking '{provider_id}' as doc-only"):
+                    drop_provider_to_doc_only(provider_id, 
base_branch=base_branch)
             if os.environ.get("GITHUB_ACTIONS", "false") != "true":
                 if not only_min_version_update:
                     console_print("-" * get_console().width)
diff --git 
a/dev/breeze/src/airflow_breeze/commands/release_management_commands_config.py 
b/dev/breeze/src/airflow_breeze/commands/release_management_commands_config.py
index 5f6c1589642..4ef3f766361 100644
--- 
a/dev/breeze/src/airflow_breeze/commands/release_management_commands_config.py
+++ 
b/dev/breeze/src/airflow_breeze/commands/release_management_commands_config.py
@@ -291,6 +291,7 @@ RELEASE_MANAGEMENT_PARAMETERS: dict[str, list[dict[str, str 
| list[str]]]] = {
             "options": [
                 "--release-date",
                 "--incremental-update",
+                "--mark-doc-only",
                 "--only-min-version-update",
                 "--reapply-templates-only",
                 "--non-interactive",
diff --git 
a/dev/breeze/src/airflow_breeze/prepare_providers/provider_documentation.py 
b/dev/breeze/src/airflow_breeze/prepare_providers/provider_documentation.py
index 5f0fa711df7..d7023a977ac 100644
--- a/dev/breeze/src/airflow_breeze/prepare_providers/provider_documentation.py
+++ b/dev/breeze/src/airflow_breeze/prepare_providers/provider_documentation.py
@@ -30,7 +30,7 @@ from enum import Enum
 from pathlib import Path
 from shutil import copyfile
 from time import time
-from typing import Any, NamedTuple
+from typing import Any, NamedTuple, NoReturn
 
 from packaging.version import Version, parse
 from rich.syntax import Syntax
@@ -575,7 +575,7 @@ def _ask_the_user_for_the_type_of_changes(non_interactive: 
bool) -> TypeOfChange
 
 def _mark_latest_changes_as_documentation_only(
     provider_id: str, list_of_list_of_latest_changes: list[list[Change]]
-):
+) -> NoReturn:
     latest_change = list_of_list_of_latest_changes[0][0]
     provider_details = get_provider_details(provider_id=provider_id)
     console_print(
@@ -588,6 +588,47 @@ def _mark_latest_changes_as_documentation_only(
     raise PrepareReleaseDocsChangesOnlyException()
 
 
+def drop_provider_to_doc_only(provider_id: str, base_branch: str) -> NoReturn:
+    """Take a provider that is already prepared for release back out of the 
wave.
+
+    Review can conclude that a prepared provider's changes are internal after 
all. Correcting the
+    changelog entry is not enough: the version bump and the changelog section 
are already written,
+    so the provider would still be built and uploaded. Restoring both files to 
their released state
+    and recording the doc-only marker is what actually removes it from the 
release.
+    """
+    provider_details = get_provider_details(provider_id=provider_id)
+    provider_yaml_path = get_provider_yaml(provider_id)
+    changelog_path = provider_details.root_provider_path / "docs" / 
"changelog.rst"
+    restore_paths = [str(path) for path in (provider_yaml_path, 
changelog_path) if path.exists()]
+    console_print(f"[info]Restoring {provider_id} to its released state before 
marking it doc-only.[/]")
+    run_command(
+        ["git", "checkout", f"{HTTPS_REMOTE}/{base_branch}", "--", 
*restore_paths],
+        cwd=AIRFLOW_ROOT_PATH,
+        check=True,
+    )
+    clear_cache_for_provider_metadata(provider_yaml_path=provider_yaml_path)
+    marked_for_release, list_of_list_of_changes, _ = 
_get_all_changes_for_package(
+        provider_id=provider_id,
+        base_branch=base_branch,
+        reapply_templates_only=False,
+        only_min_version_update=False,
+    )
+    if not list_of_list_of_changes or not list_of_list_of_changes[0]:
+        if marked_for_release:
+            # Restored to the released state and still up for release with no 
earlier version to diff
+            # against: the provider has never been released. The marker means 
"everything after this
+            # commit is documentation" and is only read once the current 
version is tagged, so writing
+            # one here would be inert - and taken literally, would suppress 
the first release for good.
+            console_print(
+                f"[warning]{provider_id} has never been released, so there is 
no release to take it "
+                f"out of. Its prepared files were restored - drop it from the 
wave instead.[/]"
+            )
+        else:
+            console_print(f"[warning]No changes found for {provider_id} - 
nothing to mark as doc-only.[/]")
+        raise PrepareReleaseDocsNoChangesException()
+    _mark_latest_changes_as_documentation_only(provider_id, 
list_of_list_of_changes)
+
+
 VERSION_MAJOR_INDEX = 0
 VERSION_MINOR_INDEX = 1
 VERSION_PATCHLEVEL_INDEX = 2
diff --git a/dev/breeze/tests/test_provider_documentation.py 
b/dev/breeze/tests/test_provider_documentation.py
index 3d357304d03..a6d8e92633e 100644
--- a/dev/breeze/tests/test_provider_documentation.py
+++ b/dev/breeze/tests/test_provider_documentation.py
@@ -30,6 +30,7 @@ from airflow_breeze.prepare_providers.provider_documentation 
import (
     VERSION_PATCHLEVEL_INDEX,
     Change,
     PrepareReleaseDocsChangesOnlyException,
+    PrepareReleaseDocsNoChangesException,
     TypeOfChange,
     _convert_git_changes_to_table,
     _find_insertion_index_for_version,
@@ -38,12 +39,13 @@ from 
airflow_breeze.prepare_providers.provider_documentation import (
     _get_git_log_command,
     classification_result,
     classify_change_deterministically,
+    drop_provider_to_doc_only,
     get_most_impactful_change,
     get_version_tag,
     update_release_notes,
 )
 from airflow_breeze.utils.confirm import Answer
-from airflow_breeze.utils.packages import ProviderPackageDetails
+from airflow_breeze.utils.packages import HTTPS_REMOTE, ProviderPackageDetails
 
 PROVIDER_DOCUMENTATION = 
"airflow_breeze.prepare_providers.provider_documentation"
 
@@ -570,3 +572,82 @@ def 
test_doc_only_marker_written_when_classification_overrides_user_answer(
         )
 
     assert marker_file.read_text().strip() == change.full_hash
+
+
+def _make_doc_only_change(full_hash: str = "a" * 40) -> Change:
+    return Change(
+        full_hash=full_hash,
+        short_hash=full_hash[:7],
+        date="2026-06-08",
+        version="1.0.0",
+        message="Fix a typo",
+        message_without_backticks="Fix a typo",
+        pr="123",
+    )
+
+
[email protected]("airflow_breeze.prepare_providers.provider_documentation.run_command")
[email protected]("airflow_breeze.prepare_providers.provider_documentation._get_all_changes_for_package")
[email protected]("airflow_breeze.prepare_providers.provider_documentation.clear_cache_for_provider_metadata")
[email protected]("airflow_breeze.prepare_providers.provider_documentation.get_provider_yaml")
[email protected]("airflow_breeze.prepare_providers.provider_documentation.get_provider_details")
+def 
test_drop_provider_to_doc_only_restores_the_release_state_and_records_the_marker(
+    mock_details, mock_yaml, mock_clear_cache, mock_changes, mock_run, tmp_path
+):
+    """Correcting the changelog is not enough - the prepared bump would still 
be released."""
+    docs = tmp_path / "docs"
+    docs.mkdir()
+    changelog = docs / "changelog.rst"
+    changelog.write_text("changelog")
+    provider_yaml = tmp_path / "provider.yaml"
+    provider_yaml.write_text("versions: [1.0.0]")
+    mock_details.return_value = mock.MagicMock(root_provider_path=tmp_path)
+    mock_yaml.return_value = provider_yaml
+    mock_changes.return_value = (True, [[_make_doc_only_change()]], "table")
+
+    with pytest.raises(PrepareReleaseDocsChangesOnlyException):
+        drop_provider_to_doc_only("amazon", base_branch="main")
+
+    restored = mock_run.call_args.args[0]
+    assert restored[:4] == ["git", "checkout", f"{HTTPS_REMOTE}/main", "--"]
+    assert str(provider_yaml) in restored
+    assert str(changelog) in restored
+    assert (docs / ".latest-doc-only-change.txt").read_text() == "a" * 40 + 
"\n"
+
+
[email protected](
+    ("marked_for_release", "expected_reason"),
+    [
+        pytest.param(True, "has never been released", id="never-released"),
+        pytest.param(False, "No changes found", 
id="nothing-since-last-release"),
+    ],
+)
[email protected]("airflow_breeze.prepare_providers.provider_documentation.run_command")
[email protected]("airflow_breeze.prepare_providers.provider_documentation._get_all_changes_for_package")
[email protected]("airflow_breeze.prepare_providers.provider_documentation.clear_cache_for_provider_metadata")
[email protected]("airflow_breeze.prepare_providers.provider_documentation.get_provider_yaml")
[email protected]("airflow_breeze.prepare_providers.provider_documentation.get_provider_details")
+def 
test_drop_provider_to_doc_only_writes_no_marker_when_there_is_nothing_to_mark(
+    mock_details,
+    mock_yaml,
+    mock_clear_cache,
+    mock_changes,
+    mock_run,
+    tmp_path,
+    capsys,
+    marked_for_release,
+    expected_reason,
+):
+    """An empty marker would silence the provider's next release entirely, and 
a provider without a
+    release has nothing for the marker to point at."""
+    docs = tmp_path / "docs"
+    docs.mkdir()
+    mock_details.return_value = mock.MagicMock(root_provider_path=tmp_path)
+    mock_yaml.return_value = tmp_path / "provider.yaml"
+    mock_changes.return_value = (marked_for_release, [], "")
+
+    with pytest.raises(PrepareReleaseDocsNoChangesException):
+        drop_provider_to_doc_only("amazon", base_branch="main")
+
+    assert not (docs / ".latest-doc-only-change.txt").exists()
+    assert expected_reason in capsys.readouterr().out

Reply via email to