You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@paimon.apache.org by ho...@apache.org on 2026/09/20 03:23:53 UTC
(paimon) 18/20: [docs] Reorganize project guides and add SVG diagrams (#9734)
This is an automated email from the ASF dual-hosted git repository.
XiaoHongbo-Hope pushed a commit to branch release-2.1
in repository https://gitbox.apache.org/repos/asf/paimon.git
commit da772c42474259b610564d66abf4505f8f6aaa5a
Author: Jingsong Lee <ji...@gmail.com>
AuthorDate: Fri Sep 11 14:17:39 2026 +0800
[docs] Reorganize project guides and add SVG diagrams (#9734)
---
docs/docs/project/committer.md | 24 +-
docs/docs/project/contributing.md | 283 ++++++++-------------
docs/docs/project/creating-a-release.md | 166 ++----------
docs/docs/project/download.mdx | 85 ++++---
docs/docs/project/index.md | 35 +++
docs/docs/project/publishing-a-release.md | 156 ++++++++++++
docs/docs/project/releases.md | 159 ++++++++++++
docs/docs/project/security.md | 12 +-
docs/docs/project/verifying-a-release-candidate.md | 28 +-
docs/sidebars.js | 24 +-
docs/static/img/project/contribution-workflow.svg | 55 ++++
docs/static/img/project/release-artifacts.svg | 83 ++++++
docs/static/img/project/release-lifecycle.svg | 55 ++++
13 files changed, 797 insertions(+), 368 deletions(-)
diff --git a/docs/docs/project/committer.md b/docs/docs/project/committer.md
index bcf8ec9377..d4899305b8 100644
--- a/docs/docs/project/committer.md
+++ b/docs/docs/project/committer.md
@@ -24,16 +24,20 @@ under the License.
# Committer
+Committers help maintain Paimon's code and community. This guide explains how
+contributors are nominated and the judgment expected when using repository
+write access. Start with [Contributing](./contributing.md) for ways to participate.
+
## Become a Committer
-#### How to become a committer
+### How nominations work
There is no strict protocol for becoming a committer. Candidates for new committers are typically people that are
active contributors and community members. Candidates are suggested by current committers or PMC members, and
voted upon by the PMC.
-If you would like to become a committer, you should engage with the community and start contributing to Apache Paimon in
-any of the above ways. You might also want to talk to other committers and ask for their advice and guidance.
+If you would like to become a committer, you should engage with the community and start contributing to Apache Paimon through
+code or community work. You might also want to talk to other committers and ask for their advice and guidance.
- Community contributions include helping to answer user questions on the mailing list, verifying release candidates,
giving talks, organizing community events, and other forms of evangelism and community building. The "Apache Way" has
@@ -44,7 +48,7 @@ any of the above ways. You might also want to talk to other committers and ask f
and other help in identifying and fixing bugs. Especially constructive and high quality design discussions, as well
as helping other contributors, are strong indicators.
-#### Identify promising candidates
+### Qualities of a committer
While the prior points give ways to identify promising candidates, the following are "must haves" for any committer candidate:
@@ -57,9 +61,19 @@ While the prior points give ways to identify promising candidates, the following
- They have shown to be respectful towards other community members and constructive in discussions.
+## Working as a committer
+
+Use the [code review guide](./contributing.md#code-review-guide) when evaluating
+contributions, and ask another reviewer when a change reaches beyond your
+expertise. Help contributors understand review feedback and reach agreement on
+the approach.
+
+Committers can also help [verify release candidates](./verifying-a-release-candidate.md).
+The [release overview](./releases.md) explains the RM and voter responsibilities.
+
## Committer Rights
JetBrains provides a free license to Apache Committers, allowing them to access all JetBrains IDEs, such as
IntelliJ IDEA, PyCharm, and other desktop tools.
-Please use your @apache.org email address to [All Products Packs for Apache committers](https://www.jetbrains.com/shop/eform/apache?product=ALL).
+Use your `@apache.org` email address to apply through [All Products Packs for Apache committers](https://www.jetbrains.com/shop/eform/apache?product=ALL).
diff --git a/docs/docs/project/contributing.md b/docs/docs/project/contributing.md
index 99920ab95f..7471e180d4 100644
--- a/docs/docs/project/contributing.md
+++ b/docs/docs/project/contributing.md
@@ -24,200 +24,131 @@ under the License.
# Contributing
-Apache Paimon is developed by an open and friendly community. Everybody is cordially welcome to join
-the community and contribute to Apache Paimon. There are several ways to interact with the community and contribute
-to Paimon including asking questions, filing bug reports, proposing new features, joining discussions on the mailing
-lists, contributing code or documentation, improving website, testing release candidates and writing corresponding blog etc.
+Apache Paimon welcomes contributions of code, documentation, testing, reviews,
+and community support. Start with a task below, and discuss questions in the
+relevant issue or on the [mailing lists](https://github.com/apache/paimon#mailing-lists).
## What do you want to do?
-Contributing to Apache Paimon goes beyond writing code for the project. Below, we list different opportunities to help the project:
-
-<table class="table table-bordered">
- <thead>
- <tr>
- <th>Area</th>
- <th>Further information</th>
- </tr>
- </thead>
- <tbody>
- <tr>
- <td><span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span> Report Bug</td>
- <td>To report a problem with Paimon, open <a href="https://github.com/apache/paimon/issues">Paimon's issues</a>. <br/>
- Please give detailed information about the problem you encountered and, if possible, add a description that helps to reproduce the problem.</td>
- </tr>
- <tr>
- <td><span class="glyphicon glyphicon-console" aria-hidden="true"></span> Contribute Code</td>
- <td>Read the <a href="#code-contribution-guide">Code Contribution Guide</a></td>
- </tr>
- <tr>
- <td><span class="glyphicon glyphicon-ok" aria-hidden="true"></span> Code Reviews</td>
- <td>Read the <a href="#code-review-guide">Code Review Guide</a></td>
- </tr>
- <tr>
- <td><span class="glyphicon glyphicon-thumbs-up" aria-hidden="true"></span> Release Version</td>
- <td>Releasing a new Paimon version.</td>
- </tr>
- <tr>
- <td><span class="glyphicon glyphicon-user" aria-hidden="true"></span> Support Users</td>
- <td>Reply to questions on the <a href="https://github.com/apache/paimon#mailing-lists">user mailing list</a>,
- check the latest issues in <a href="https://github.com/apache/paimon/issues">Issues</a> for tickets which are actually user questions.
- </td>
- </tr>
- <tr>
- <td><span class="glyphicon glyphicon-volume-up" aria-hidden="true"></span> Spread the Word About Paimon</td>
- <td>Organize or attend a Paimon Meetup, contribute to the Paimon blog, share your conference, meetup or blog
- post on the <a href="https://github.com/apache/paimon#mailing-lists">dev@paimon.apache.org mailing list</a>.
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <span class="glyphicon glyphicon-question-sign" aria-hidden="true"></span> Any other question? Reach out to the
- <a href="https://github.com/apache/paimon#mailing-lists">dev@paimon.apache.org mailing list</a> to get help!
- </td>
- </tr>
- </tbody>
-</table>
+
+| Contribution | How to start |
+| --- | --- |
+| Ask or answer a question | Use the [user mailing list](https://github.com/apache/paimon#mailing-lists), or help users in existing issues. |
+| Report a bug | Open a [GitHub issue](https://github.com/apache/paimon/issues) with the Paimon and engine versions, expected and actual behavior, and a minimal reproduction. Remove credentials from logs and configuration. |
+| Report a possible vulnerability | Follow the private [security reporting process](./security.md#reporting-security-issues). |
+| Propose a feature | Explain the use case and design in an issue or on `dev@paimon.apache.org` before implementation. |
+| Contribute code | Follow the [code contribution guide](#code-contribution-guide). |
+| Improve documentation | Describe what readers need, update the relevant page, and [build the documentation](#documentation-changes). |
+| Review code | Use the [code review guide](#code-review-guide). |
+| Test a release candidate | Follow the [verification guide](./verifying-a-release-candidate.md) and report the checks you completed. |
+| Help the community grow | Write about Paimon, organize or attend a meetup, and share useful material on `dev@paimon.apache.org`. |
## Code Contribution Guide
-Apache Paimon is maintained, improved, and extended by code contributions of volunteers. We welcome contributions to Paimon.
-
-Please feel free to ask questions at any time. Either send a mail to the Dev mailing list or comment on the issue you are working on.
-
-<style>
-.contribute-grid {
- margin-bottom: 10px;
- display: flex;
- flex-direction: column;
- margin-left: -2px;
- margin-right: -2px;
-}
-
-.contribute-grid .column {
- margin-top: 4px;
- padding: 0 2px;
-}
-
-@media only screen and (min-width: 480px) {
- .contribute-grid {
- flex-direction: row;
- flex-wrap: wrap;
- }
-
- .contribute-grid .column {
- flex: 0 0 50%;
- }
-
- .contribute-grid .column {
- margin-top: 4px;
- }
-}
-
-@media only screen and (min-width: 960px) {
- .contribute-grid {
- flex-wrap: nowrap;
- }
-
- .contribute-grid .column {
- flex: 0 0 25%;
- }
-}
-
-.contribute-grid .panel {
- height: 100%;
- margin: 0;
-}
-
-.contribute-grid .panel-body {
- padding: 10px;
-}
-
-.contribute-grid h2 {
- margin: 0 0 10px 0;
- padding: 0;
- display: flex;
- align-items: flex-start;
-}
-
-.contribute-grid .number {
- margin-right: 0.25em;
- font-size: 1.5em;
- line-height: 0.9;
-}
-</style>
-
-<div class="contribute-grid">
- <div class="column">
- <div class="panel panel-default">
- <div class="panel-body">
- <h2 id="consensus"><span class="number">1</span><a href="#consensus">Discuss</a></h2>
- <p>Create an Issue or mailing list discussion and reach consensus</p>
- <p><b>To request an issue, please note that it is not just a "please assign it to me", you need to explain your understanding of the issue, and your design, and if possible, you need to provide your POC code.</b></p>
- </div>
- </div>
- </div>
- <div class="column">
- <div class="panel panel-default">
- <div class="panel-body">
- <h2 id="implement"><span class="number">2</span><a href="#implement">Implement</a></h2>
- <p>Create the Pull Request and the approach agreed upon in the issue.</p>
- <p><b>1.Only create the PR if you are assigned to the issue. 2.Please associate an issue (if any), e.g. fix #123. 3.Please enable the actions of your own clone project.</b></p>
- </div>
- </div>
- </div>
- <div class="column">
- <div class="panel panel-default">
- <div class="panel-body">
- <h2 id="review"><span class="number">3</span><a href="#review">Review</a></h2>
- <p>Work with the reviewer.</p><br />
- <p><b>1.Make sure no unrelated or unnecessary reformatting changes are included. 2.Please ensure that the test passing. 3.Please don't resolve conversation.</b></p>
- </div>
- </div>
- </div>
- <div class="column">
- <div class="panel panel-default">
- <div class="panel-body">
- <h2 id="merge"><span class="number">4</span><a href="#merge">Merge</a></h2>
- <p>A committer of Paimon checks if the contribution fulfills the requirements and merges the code to the codebase.</p>
- </div>
- </div>
- </div>
-</div>
+
-## Code Review Guide
+[Open the contribution diagram at full size](/img/project/contribution-workflow.svg).
+
+### Discuss {#consensus}
+
+Create an issue or mailing-list discussion that explains the problem and your
+proposed approach. Reach agreement before making a substantial change.
+
+When requesting assignment to an issue, explain your understanding, design,
+and, where useful, a proof of concept. An assignment request alone does not
+provide enough information. If you are working on an issue, wait until it is
+assigned to you before opening the pull request.
+
+### Implement {#implement}
+
+1. Implement the approach agreed in the discussion. Keep the change focused and
+ avoid unrelated refactoring or formatting.
+2. Add tests that exercise the changed behavior, including a regression test
+ for a bug fix. Update documentation for user-visible behavior.
+3. Follow the repository's [build instructions](https://github.com/apache/paimon#building).
+ Run the relevant tests and formatting checks, and enable GitHub Actions in
+ your fork.
+4. Open a pull request describing the problem, resulting behavior, and
+ validation. Link the issue, if there is one; use `Fixes #123` when the pull
+ request resolves it.
+
+### Review {#review}
+
+Work with reviewers and explain how each concern was addressed. Keep tests
+passing as the change evolves. Leave review conversations open for reviewers
+to resolve after they check your response.
-Every review needs to check the following six aspects. **We encourage to check these aspects in order, to avoid
-spending time on detailed code quality reviews when formal requirements are not met or there is no consensus in
-the community to accept the change.**
+If implementation reveals a need to change the agreed approach, explain the
+new design before expanding the pull request.
-#### 1. Is the Contribution Well-Described?
+### Merge {#merge}
+
+A Paimon committer checks that the contribution meets the project requirements
+and merges it after review. A pull request with passing tests still needs
+review and agreement on its behavior.
+
+## Documentation changes
+
+The documentation source is in `docs/docs`, static images are in
+`docs/static/img`, and navigation is defined explicitly in `docs/sidebars.js`.
+When adding a page, add its document ID to the appropriate sidebar category.
+Use relative Markdown links between pages so that links remain within the
+selected documentation version.
+
+Prefer editable SVG for diagrams. Give each diagram descriptive alternative
+text and explain its essential steps in the page so that the information is
+also available without the image.
+
+From the repository root, install the documentation dependencies and build the
+site:
+
+```shell
+cd docs
+yarn install
+yarn build
+```
+
+The build runs the REST OpenAPI contract checks and compiles the documentation.
+Review the output for broken links and inspect the changed pages with
+`yarn serve`, including images and narrow-screen layouts. See the
+[documentation README](https://github.com/apache/paimon/blob/master/docs/README.md)
+for local development and generated configuration tables.
+
+## Code Review Guide
-Check whether the contribution is sufficiently well-described to support a good review. Trivial changes and fixes
-do not need a long description. If the implementation is exactly according to a prior discussion on issue or the
-development mailing list, only a short reference to that discussion is needed.
+Review these four areas in order. Establish the purpose and agreement on the
+change before spending time on implementation details.
-If the implementation is different from the agreed approach in the consensus discussion, a detailed description of
-the implementation is required for any further review of the contribution.
+### 1. Is the contribution well described?
-#### 2. Does the Contribution Need Attention from some Specific Committers?
+The description should make the problem and resulting behavior clear. Small
+fixes need only a short explanation. Link prior issue or mailing-list
+discussions when the implementation follows an agreed design; explain any
+departures from that design.
-Some changes require attention and approval from specific committers.
+### 2. Does it need attention from specific committers?
-If the pull request needs specific attention, one of the tagged committers/contributors should give the final approval.
+Some changes need review from people familiar with the affected component or
+contract. When specific attention is required, one of the tagged committers
+or contributors should give the final approval.
-#### 3. Is the Overall Code Quality Good, Meeting Standard we Want to Maintain in Paimon?
+### 3. Does the implementation meet Paimon's quality standards?
-- Does the code follow the right software engineering practices? Is the code correct, robust, maintainable, testable?
-- Are the changes performance aware, when changing a performance sensitive part?
-- Are the changes sufficiently covered by tests? Are the tests executing fast?
-- If dependencies have been changed, were the NOTICE files updated?
+- Check correctness, robustness, maintainability, and testability.
+- Consider performance when changing a performance-sensitive path.
+- Check that tests cover the changed behavior and run efficiently.
+- When dependencies change, check whether `LICENSE` or `NOTICE` needs updating.
-Code guidelines can be found in the [Flink Java Code Style and Quality Guide](https://flink.apache.org/how-to-contribute/code-style-and-quality-java/).
+Refer to the [Flink Java Code Style and Quality Guide](https://flink.apache.org/how-to-contribute/code-style-and-quality-java/)
+for code guidelines.
-#### 4. Are the documentation updated?
+### 4. Is the documentation current?
-If the pull request introduces a new feature, the feature should be documented.
+Document new features and changes to configuration, public APIs, or observable
+behavior. Check examples and links, and ensure that the documentation build
+passes.
## Become a Committer
-When you have made enough contributions, you can be nominated as Paimon's Committer. See [Committer](./committer).
+Sustained code and community contributions can lead to nomination as a
+committer. See the [committer guide](./committer.md) for the nomination process
+and community expectations.
diff --git a/docs/docs/project/creating-a-release.md b/docs/docs/project/creating-a-release.md
index 8e10c21fba..c8c15c41e2 100644
--- a/docs/docs/project/creating-a-release.md
+++ b/docs/docs/project/creating-a-release.md
@@ -37,77 +37,36 @@ after the vote.
:::
-## Release model
-
-The combined Paimon and PyPaimon release uses one shared version number. The
-Maven project version and `paimon-python/setup.py` version must be equal.
+## Before you start
-| Deliverable | Candidate | Published location |
-| --- | --- | --- |
-| Paimon source | `apache-paimon-PAIMON_VERSION-src.tgz`, `.asc`, `.sha512` | ASF distribution |
-| Java convenience artifacts | Maven artifacts built in the JDK 8, 11, and 17 lanes | Apache Nexus staging, then Maven Central |
-| PyPaimon source | `pypaimon-PAIMON_VERSION.tar.gz`, `.asc`, `.sha512` | ASF distribution |
-| Python convenience package | `pypaimon==PAIMON_VERSIONrcRC_NUMBER` for an RC | TestPyPI, then `pypaimon==PAIMON_VERSION` on PyPI |
+Read the [release overview](./releases.md) for the artifact model and roles.
+Run the following steps in order; examples use `2.0.0` only to illustrate the
+variable names. Select the version and release branch agreed by the community.
-A combined release vote covers both signed source candidates. This guide does
-not define an independent PyPaimon release. Before releasing PyPaimon
-separately, the PMC must define a Python-only tag and workflow which do not
-depend on the Maven version or Java jobs, and must provide a signed source
-package which is independently sufficient to build and test the release.
+| Step | Ready to continue when |
+| --- | --- |
+| [Set up the RM environment](#one-time-rm-setup) | The signing key, credentials, and service access are configured |
+| [Prepare the release](#prepare-the-release) | Versions agree and the signed RC tag identifies a clean commit |
+| [Sign and stage Java artifacts](#sign-and-stage-the-java-convenience-artifacts-locally) | One complete Nexus repository is closed |
+| [Stage source candidates](#stage-the-source-candidates) | Both source archives, signatures, and checksums are available |
+| [Call the vote](#call-the-vote) | All candidate URLs and provenance are in the vote email |
+| [Publish after approval](./publishing-a-release.md) | The vote passed and the approved candidate is unchanged |
-### Java build matrix
+## Release model
-The three Java lanes are different release targets, not interchangeable build
-JDKs:
+Paimon and PyPaimon use one shared version and one combined vote. See the
+[deliverables and Java build matrix](./releases.md#release-model).
-| JDK | Maven profiles and scope | Main artifacts |
-| --- | --- | --- |
-| 8 | `spark3,flink1` and the default reactor | Paimon core, Flink 1.x, Spark 3.x, Hive, filesystems, bundles, and other Java 8 artifacts |
-| 11 | `flink2` plus `paimon-iceberg` | Flink 2.x, `paimon-flink2-common`, and Iceberg integration |
-| 17 | `spark4` | Spark 4.x and its Scala 2.13 common artifacts |
+### Java build matrix
-Each lane must use the matching JDK. Building everything on JDK 17 with a lower
-compiler target is not a substitute for running the JDK 8 and JDK 11 lanes.
+See the [JDK 8, 11, and 17 release targets](./releases.md#java-build-matrix).
## GitHub Actions release workflow
-The release process uses the
-[Release workflow](https://github.com/apache/paimon/actions/workflows/release.yml)
-to package the JDK 8, JDK 11, and JDK 17 Java lanes and PyPaimon from every
-signed RC tag. The Java lanes are merged into one unsigned Maven repository
-image. The RM downloads that image, signs it, and stages it in Nexus. The RM
-also creates and signs the two ASF source archives locally from the same tag.
-The RM's GPG private key is never stored in GitHub Actions.
-
-The workflow has the following contract:
-
-| Job | Required behavior |
-| --- | --- |
-| Validation | Require an RC tag named `release-PAIMON_VERSION-rcN` or a final tag named `release-PAIMON_VERSION`, where `PAIMON_VERSION` exactly equals the root Maven `project.version` |
-| Java 8 | Use Temurin 8 to deploy the default reactor with Spark 3 and Flink 1 into a local Maven repository image |
-| Java 11 | Use Temurin 11 to deploy Flink 2 and Iceberg into a local Maven repository image |
-| Java 17 | Use Temurin 17 to deploy Spark 4 into a local Maven repository image |
-| Java repository | Require every deploy-enabled effective-POM project and its POM, main JAR, and source JAR; retain Javadoc JARs where Maven produces them; merge all three lanes; reject conflicting coordinates; then upload the complete unsigned Maven repository image, checksums, manifests, and logs |
-| Python package | Build and validate the PyPaimon source distribution and universal wheel, then upload them as workflow artifacts |
-| Python publish | Publish an RC to TestPyPI or a final tag to PyPI after Python packaging passes, without waiting for Java packaging |
-
-Before packaging, every Java lane runs Maven Enforcer's
-`requireReleaseVersion` and `requireReleaseDeps` rules over its complete reactor
-scope. The latter includes transitive dependencies. Any remaining
-`-SNAPSHOT` project, parent, direct dependency, or transitive dependency is a
-release blocker.
-
-The Java jobs run independently of the common validation and Python jobs. They
-use `-Dgpg.skip=true`, deploy only to runner-local file repositories, and never
-receive Nexus credentials or a GPG private key. The combined repository image
-contains POMs, main artifacts, source JARs, Javadoc JARs produced by Maven, and
-Maven-generated checksums. Scala-only and wrapper modules may not produce a
-Javadoc JAR. The image is the input to the RM's local signing and Nexus
-staging steps, not itself an ASF release. The Python RC job uses the
-`TEST_PYPI_API_TOKEN` repository Actions secret to publish
-`PAIMON_VERSIONrcRC_NUMBER` to TestPyPI. The final job uses the
-`PYPI_API_TOKEN` repository Actions secret to publish to PyPI. The release
-workflow passes only these two secrets to the reusable publishing workflow.
+The workflow packages Java artifacts and publishes Python candidates; the RM
+signs locally and stages the source and Java artifacts. See the
+[workflow contract](./releases.md#github-actions-release-workflow) before running
+the commands below.
## One-time RM setup
@@ -471,93 +430,24 @@ If the vote finds a problem:
## Finalize an approved release
-### Create the final signed tag
-
-The final tag must point to exactly the approved RC commit:
+After recording a successful vote result, follow [Publishing a Release](./publishing-a-release.md)
+with the approved candidate's variables and repository ID.
-```shell
-git tag -s "${RELEASE_TAG}" "refs/tags/${RC_REF}^{commit}" \
- -m "Release Apache Paimon ${PAIMON_VERSION}"
+### Create the final signed tag
-test "$(git rev-parse "refs/tags/${RC_REF}^{commit}")" = \
- "$(git rev-parse "refs/tags/${RELEASE_TAG}^{commit}")"
-git tag -v "${RELEASE_TAG}"
-git push origin "refs/tags/${RELEASE_TAG}:refs/tags/${RELEASE_TAG}"
-```
+[Tag the approved RC commit](./publishing-a-release.md#create-the-final-signed-tag).
### Promote the source releases
-Move, rather than copy or rebuild, both approved candidate directories:
-
-```shell
-svn mv -m "Release Apache Paimon ${PAIMON_VERSION}" \
- "https://dist.apache.org/repos/dist/dev/paimon/paimon-${PAIMON_VERSION}-rc${RC_NUMBER}" \
- "https://dist.apache.org/repos/dist/release/paimon/paimon-${PAIMON_VERSION}"
-
-svn mv -m "Release PyPaimon ${PAIMON_VERSION}" \
- "https://dist.apache.org/repos/dist/dev/paimon/pypaimon-${PAIMON_VERSION}-rc${RC_NUMBER}" \
- "https://dist.apache.org/repos/dist/release/paimon/pypaimon-${PAIMON_VERSION}"
-```
+[Move the approved source directories to ASF dist release](./publishing-a-release.md#promote-the-source-releases).
### Promote convenience artifacts
-1. In Nexus, confirm that the recorded Java staging repository is still closed
- and has the exact artifact tree approved by the vote.
-2. Release that exact closed repository to Maven Central. Do not upload or
- rebuild the Java artifacts again.
-3. Confirm that the final tag's PyPI publish job builds
- `pypaimon==PAIMON_VERSION` from the approved tag commit and does not change
- project source.
-4. Verify Maven Central and PyPI before announcing the release.
+[Release the closed Nexus repository and verify the final PyPI package](./publishing-a-release.md#promote-convenience-artifacts).
### Publish and announce
-Create a GitHub release from `release-PAIMON_VERSION`, review the generated
-notes, and link both source releases.
-
-Before announcing the release, publish the versioned documentation and update
-the project website. Treat the documentation in `apache/paimon` and the project
-website in `apache/paimon-website` as two separate, required updates.
-
-1. In `apache/paimon`, publish documentation for `DOC_VERSION` from the release
- branch so that the published content matches the released code:
- - On `RELEASE_BRANCH`, update `docs/docusaurus.config.js` with the released
- `baseUrl`, `version`, `versionTitle`, `branch`, `editUrl`, `isStable`,
- `stableDocs`, `previousDocs`, and navbar version menu.
- - On `master`, set the next development version and update `stableDocs`,
- `previousDocs`, and the navbar version menu to include `DOC_VERSION` as
- the stable release.
- - Review `docs/docs/project/download.mdx` and any release-specific engine or
- compatibility information. The `@@VERSION@@`, `<Stable>`, and `<Unstable>`
- sections must render the released artifacts on the stable site.
- - Run `yarn build` from the `docs` directory for both configurations.
-2. In `apache/paimon-website`, update every public release entry point:
- - Add the Paimon and PyPaimon source archives, checksums, signatures, and
- current dependency examples to `community/docs/downloads.md`.
- - Create or update the appropriate
- `community/docs/releases/release-${DOC_VERSION}.md` release note. Its
- `version` front matter must equal `PAIMON_VERSION`, and its weight must
- place it correctly in the release list.
- - Add `DOC_VERSION` to the `versions` list in
- `src/app/components/header/header.component.ts`. If the menu keeps a fixed
- number of versions, remove the oldest entry.
- - Run `pnpm build` to parse the release metadata and build the website.
-3. After deployment, verify all public entry points before sending the
- announcement:
- - `https://paimon.apache.org/docs/${DOC_VERSION}/` serves the released docs
- and the version switcher identifies it as stable;
- - the homepage `DOCUMENT` menu includes `DOC_VERSION` on desktop and mobile;
- - `https://paimon.apache.org/downloads/` lists both signed source releases;
- - `https://paimon.apache.org/releases/${PAIMON_VERSION}` shows the release
- note.
-
-After ASF mirrors, Maven Central, PyPI, the versioned documentation, and the
-project website are all available, announce the release to
-`dev@paimon.apache.org` and `announce@apache.org` from an `@apache.org` address.
-
-Remove superseded releases from the live ASF distribution area when required;
-they remain available from the
-[Apache archive](https://archive.apache.org/dist/paimon/).
+[Update documentation and the website before announcing](./publishing-a-release.md#publish-and-announce).
See [Verifying a Release Candidate](./verifying-a-release-candidate.md) for the
voter checklist.
diff --git a/docs/docs/project/download.mdx b/docs/docs/project/download.mdx
index b361f7b84c..b2660f4856 100644
--- a/docs/docs/project/download.mdx
+++ b/docs/docs/project/download.mdx
@@ -1,6 +1,6 @@
---
title: "Download"
-sidebar_position: 2
+sidebar_position: 1
---
import Stable from '@site/src/components/Stable';
@@ -27,17 +27,48 @@ under the License.
# Download
-This documentation is a guide for downloading Paimon Jars.
+Choose artifacts for Paimon **@@VERSION@@** and the engine version you run.
+For released source archives, signatures, and checksums, use the
+[project downloads page](https://paimon.apache.org/downloads/). For the Python
+client, see [PyPaimon installation](../pypaimon/installation.md).
-## Engine Jars
+## Choose an artifact
+
+| You need to | Download | Installation guide |
+| --- | --- | --- |
+| Use Paimon from a query engine | The matching [engine JAR](#engine-jars) or Trino plugin archive | [Flink](../flink/quick-start.mdx), [Spark](../spark/quick-start.mdx), or your engine's integration guide |
+| Access object storage | The required [filesystem JAR](#filesystem-jars), alongside the engine connector | [Filesystems](../maintenance/filesystems.mdx) |
+| Embed Paimon in a Java application | The [API bundle](#api-jars) | [Java API](../program-api/java-api.mdx) |
+
+Match the engine version in the table, including the Scala binary version in
+Spark artifact names. Follow the integration guide for where to install the
+artifact; downloading a JAR alone does not configure a catalog or storage.
<Unstable>
+This is development documentation. The snapshot links below are intended for
+contributors testing unreleased changes. A snapshot repository can contain
+multiple timestamped builds; inspect the JAR's [manifest](#manifestmf) when
+reporting which build you tested. Use the project downloads page above for
+released versions.
+
+</Unstable>
+
+<Stable>
+The links below resolve convenience artifacts for this documentation version
+from Maven Central. Refer to the source download page above to verify the
+signed Apache release.
+
+</Stable>
+
+## Engine JARs
+
+<Unstable>
| Version | Jar |
|------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| Flink 2.0 | Not yet released |
+| Flink 2.x | For development builds, see [Build from Source](../flink/installation.mdx#build-from-source). |
| Flink 1.20 | [paimon-flink-1.20-@@VERSION@@.jar](https://repository.apache.org/snapshots/org/apache/paimon/paimon-flink-1.20/@@VERSION@@/) |
| Flink 1.19 | [paimon-flink-1.19-@@VERSION@@.jar](https://repository.apache.org/snapshots/org/apache/paimon/paimon-flink-1.19/@@VERSION@@/) |
| Flink 1.18 | [paimon-flink-1.18-@@VERSION@@.jar](https://repository.apache.org/snapshots/org/apache/paimon/paimon-flink-1.18/@@VERSION@@/) |
@@ -54,17 +85,13 @@ This documentation is a guide for downloading Paimon Jars.
| Hive 2.3 | [paimon-hive-connector-2.3-@@VERSION@@.jar](https://repository.apache.org/snapshots/org/apache/paimon/paimon-hive-connector-2.3/@@VERSION@@/) |
| Hive 2.2 | [paimon-hive-connector-2.2-@@VERSION@@.jar](https://repository.apache.org/snapshots/org/apache/paimon/paimon-hive-connector-2.2/@@VERSION@@/) |
| Hive 2.1 | [paimon-hive-connector-2.1-@@VERSION@@.jar](https://repository.apache.org/snapshots/org/apache/paimon/paimon-hive-connector-2.1/@@VERSION@@/) |
-| Hive 2.1-cdh-6.3 | [paimon-hive-connector-2.1-cdh-6.3-@@VERSION@@.jar](https://repository.apache.org/snapshots/org/apache/paimon/paimon-hive-connector-2.1-cdh-6.3/@@VERSION@@/) | |
+| Hive 2.1-cdh-6.3 | [paimon-hive-connector-2.1-cdh-6.3-@@VERSION@@.jar](https://repository.apache.org/snapshots/org/apache/paimon/paimon-hive-connector-2.1-cdh-6.3/@@VERSION@@/) |
| Trino 440 | [paimon-trino-440-@@VERSION@@-plugin.tar.gz](https://repository.apache.org/content/repositories/snapshots/org/apache/paimon/paimon-trino-440/@@VERSION@@/) |
-
-
</Unstable>
<Stable>
-
-
| Version | Jar |
|------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Flink 2.2 | [paimon-flink-2.2-@@VERSION@@.jar](https://repo.maven.apache.org/maven2/org/apache/paimon/paimon-flink-2.2/@@VERSION@@/paimon-flink-2.2-@@VERSION@@.jar) |
@@ -89,75 +116,59 @@ This documentation is a guide for downloading Paimon Jars.
| Hive 2.1-cdh-6.3 | [paimon-hive-connector-2.1-cdh-6.3-@@VERSION@@.jar](https://repo.maven.apache.org/maven2/org/apache/paimon/paimon-hive-connector-2.1-cdh-6.3/@@VERSION@@/paimon-hive-connector-2.1-cdh-6.3-@@VERSION@@.jar) |
| Trino | [Download from master](https://paimon.apache.org/docs/master/project/download/) |
-
-
</Stable>
-## Filesystem Jars
+## Filesystem JARs
<Unstable>
-
-
| Version | Jar |
|--------------|-----------------------------------------------------------------------------------------------------------------------------|
| paimon-oss | [paimon-oss-@@VERSION@@.jar](https://repository.apache.org/snapshots/org/apache/paimon/paimon-oss/@@VERSION@@/) |
| paimon-jindo | [paimon-jindo-@@VERSION@@.jar](https://repository.apache.org/snapshots/org/apache/paimon/paimon-jindo/@@VERSION@@/) |
| paimon-s3 | [paimon-s3-@@VERSION@@.jar](https://repository.apache.org/snapshots/org/apache/paimon/paimon-s3/@@VERSION@@/) |
-
-
</Unstable>
<Stable>
-
-
| Version | Jar |
|--------------|----------------------------------------------------------------------------------------------------------------------------------------------------------|
| paimon-oss | [paimon-oss-@@VERSION@@.jar](https://repo.maven.apache.org/maven2/org/apache/paimon/paimon-oss/@@VERSION@@/paimon-oss-@@VERSION@@.jar) |
| paimon-jindo | [paimon-jindo-@@VERSION@@.jar](https://repo.maven.apache.org/maven2/org/apache/paimon/paimon-jindo/@@VERSION@@/paimon-jindo-@@VERSION@@.jar) |
| paimon-s3 | [paimon-s3-@@VERSION@@.jar](https://repo.maven.apache.org/maven2/org/apache/paimon/paimon-s3/@@VERSION@@/paimon-s3-@@VERSION@@.jar) |
-
-
</Stable>
-## API Jars
+## API JARs
<Unstable>
-
-
| Version | Jar |
|---------------|-------------------------------------------------------------------------------------------------------------------------------|
| paimon-bundle | [paimon-bundle-@@VERSION@@.jar](https://repository.apache.org/snapshots/org/apache/paimon/paimon-bundle/@@VERSION@@/) |
-
-
</Unstable>
<Stable>
-
-
| Version | Jar |
|---------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------|
| paimon-bundle | [paimon-bundle-@@VERSION@@.jar](https://repo.maven.apache.org/maven2/org/apache/paimon/paimon-bundle/@@VERSION@@/paimon-bundle-@@VERSION@@.jar) |
-
-
</Stable>
-<Unstable>
-
+## Inspect a JAR manifest {#manifestmf}
+For a snapshot build, inspect `META-INF/MANIFEST.MF` inside the downloaded JAR:
-<h2>MANIFEST.MF</h2>
+```shell
+unzip -p /path/to/paimon.jar META-INF/MANIFEST.MF
+```
-For unstable version, you can find git commit id in jar:
+For example:
-```shell
+```text
Manifest-Version: 1.0
Implementation-Title: Paimon : Common
Implementation-Version: @@VERSION@@
@@ -172,8 +183,4 @@ Build-Jdk: 1.8.0_301
Specification-Version: @@VERSION@@
```
-The `SCM-Revision` git commit id.
-
-
-
-</Unstable>
+The `SCM-Revision` field identifies the Git commit used to build the JAR.
diff --git a/docs/docs/project/index.md b/docs/docs/project/index.md
index d4f76af4f8..fc1cfdae26 100644
--- a/docs/docs/project/index.md
+++ b/docs/docs/project/index.md
@@ -21,3 +21,38 @@ KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
+
+# Project
+
+Find the right Paimon package, contribute to the community, or help prepare and
+verify a release. Start with the task you want to complete.
+
+## Use Paimon
+
+| Task | Start here |
+| --- | --- |
+| Choose an engine connector, filesystem plugin, or Java API bundle | [Download](./download.mdx) |
+| Install the Python client | [PyPaimon installation](../pypaimon/installation.md) |
+| Report a possible vulnerability privately | [Security](./security.md#reporting-security-issues) |
+| Understand Paimon's security boundaries | [Security model](./security.md#security-model) |
+
+## Join the community
+
+| Task | Start here |
+| --- | --- |
+| Ask a question, report a bug, or improve documentation | [Ways to contribute](./contributing.md#what-do-you-want-to-do) |
+| Prepare a code change | [Code contribution guide](./contributing.md#code-contribution-guide) |
+| Review a pull request | [Code review guide](./contributing.md#code-review-guide) |
+| Learn how committers are nominated and what is expected of them | [Committer guide](./committer.md) |
+
+## Help release Paimon
+
+| Task | Start here |
+| --- | --- |
+| Understand the roles, artifacts, and release workflow | [Release overview](./releases.md) |
+| Prepare and stage a candidate as Release Manager | [Creating a release](./creating-a-release.md) |
+| Independently verify a candidate and report a vote | [Verifying a release candidate](./verifying-a-release-candidate.md) |
+| Publish the approved artifacts, documentation, and announcement | [Publishing a release](./publishing-a-release.md) |
+
+Release candidates are for community review. For released source packages, use
+the [project downloads page](https://paimon.apache.org/downloads/).
diff --git a/docs/docs/project/publishing-a-release.md b/docs/docs/project/publishing-a-release.md
new file mode 100644
index 0000000000..dcc062a1ff
--- /dev/null
+++ b/docs/docs/project/publishing-a-release.md
@@ -0,0 +1,156 @@
+---
+title: "Publishing a Release"
+sidebar_position: 4
+---
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+# Publishing a Release
+
+This guide is for the Release Manager after the combined Paimon and PyPaimon
+vote has passed and its result has been recorded. To prepare a candidate, start
+with [Creating a Release](./creating-a-release.md).
+
+## Confirm the approved inputs
+
+Use the exact candidate named in the successful vote. Keep the vote result,
+source URLs, closed Nexus repository ID, commit SHA, and workflow run URL
+available throughout publication.
+
+Set the same variables used when preparing that candidate. These values are
+examples; replace them with the approved release values:
+
+```shell
+PAIMON_VERSION="2.0.0"
+DOC_VERSION="2.0"
+RC_NUMBER="1"
+RELEASE_BRANCH="release-2.0"
+RC_REF="release-${PAIMON_VERSION}-rc${RC_NUMBER}"
+RELEASE_TAG="release-${PAIMON_VERSION}"
+```
+
+Run the tag commands in the release clone with the RM's signing key configured
+and the approved RC tag available locally. Use the same ASF distribution and
+Nexus access configured during [RM setup](./creating-a-release.md#one-time-rm-setup).
+
+| Publish | Preserve |
+| --- | --- |
+| Final Git tag | The exact approved RC commit |
+| ASF source releases | The approved archives, signatures, and checksums |
+| Maven Central artifacts | The exact closed Nexus repository approved by the vote |
+| PyPI package | The approved source commit, using the final Python version |
+| Documentation and website | Version labels, links, and examples matching the release |
+
+## Create the final signed tag
+
+The final tag must point to exactly the approved RC commit:
+
+```shell
+git tag -s "${RELEASE_TAG}" "refs/tags/${RC_REF}^{commit}" \
+ -m "Release Apache Paimon ${PAIMON_VERSION}"
+
+test "$(git rev-parse "refs/tags/${RC_REF}^{commit}")" = \
+ "$(git rev-parse "refs/tags/${RELEASE_TAG}^{commit}")"
+git tag -v "${RELEASE_TAG}"
+git push origin "refs/tags/${RELEASE_TAG}:refs/tags/${RELEASE_TAG}"
+```
+
+## Promote the source releases
+
+Move, rather than copy or rebuild, both approved candidate directories:
+
+```shell
+svn mv -m "Release Apache Paimon ${PAIMON_VERSION}" \
+ "https://dist.apache.org/repos/dist/dev/paimon/paimon-${PAIMON_VERSION}-rc${RC_NUMBER}" \
+ "https://dist.apache.org/repos/dist/release/paimon/paimon-${PAIMON_VERSION}"
+
+svn mv -m "Release PyPaimon ${PAIMON_VERSION}" \
+ "https://dist.apache.org/repos/dist/dev/paimon/pypaimon-${PAIMON_VERSION}-rc${RC_NUMBER}" \
+ "https://dist.apache.org/repos/dist/release/paimon/pypaimon-${PAIMON_VERSION}"
+```
+
+## Promote convenience artifacts
+
+1. In Nexus, confirm that the recorded Java staging repository is still closed
+ and has the exact artifact tree approved by the vote.
+2. Release that exact closed repository to Maven Central. Do not upload or
+ rebuild the Java artifacts again.
+3. Confirm that the final tag's PyPI publish job builds
+ `pypaimon==PAIMON_VERSION` from the approved tag commit and does not change
+ project source.
+4. Verify Maven Central and PyPI before announcing the release.
+
+## Publish and announce
+
+Create a GitHub release from `release-PAIMON_VERSION`, review the generated
+notes, and link both source releases.
+
+Before announcing the release, publish the versioned documentation and update
+the project website. Treat the documentation in `apache/paimon` and the project
+website in `apache/paimon-website` as two separate, required updates.
+
+1. In `apache/paimon`, publish documentation for `DOC_VERSION` from the release
+ branch so that the published content matches the released code:
+ - On `RELEASE_BRANCH`, update `docs/docusaurus.config.js` with the released
+ `baseUrl`, `version`, `versionTitle`, `branch`, `editUrl`, `isStable`,
+ `stableDocs`, `previousDocs`, and navbar version menu.
+ - On `master`, set the next development version and update `stableDocs`,
+ `previousDocs`, and the navbar version menu to include `DOC_VERSION` as
+ the stable release.
+ - Review `docs/docs/project/download.mdx` and any release-specific engine or
+ compatibility information. The `@@VERSION@@`, `<Stable>`, and `<Unstable>`
+ sections must render the released artifacts on the stable site.
+ - Run `yarn build` from the `docs` directory for both configurations.
+2. In `apache/paimon-website`, update every public release entry point:
+ - Add the Paimon and PyPaimon source archives, checksums, signatures, and
+ current dependency examples to `community/docs/downloads.md`.
+ - Create or update the appropriate
+ `community/docs/releases/release-${DOC_VERSION}.md` release note. Its
+ `version` front matter must equal `PAIMON_VERSION`, and its weight must
+ place it correctly in the release list.
+ - Add `DOC_VERSION` to the `versions` list in
+ `src/app/components/header/header.component.ts`. If the menu keeps a fixed
+ number of versions, remove the oldest entry.
+ - Run `pnpm build` to parse the release metadata and build the website.
+3. After deployment, verify all public entry points before sending the
+ announcement:
+ - `https://paimon.apache.org/docs/${DOC_VERSION}/` serves the released docs
+ and the version switcher identifies it as stable;
+ - the homepage `DOCUMENT` menu includes `DOC_VERSION` on desktop and mobile;
+ - `https://paimon.apache.org/downloads/` lists both signed source releases;
+ - `https://paimon.apache.org/releases/${PAIMON_VERSION}` shows the release
+ note.
+
+After ASF mirrors, Maven Central, PyPI, the versioned documentation, and the
+project website are all available, announce the release to
+`dev@paimon.apache.org` and `announce@apache.org` from an `@apache.org` address.
+
+Remove superseded releases from the live ASF distribution area when required;
+they remain available from the
+[Apache archive](https://archive.apache.org/dist/paimon/).
+
+## Completion checklist
+
+- The final signed tag resolves to the approved RC commit.
+- Both source releases and their signatures and checksums are available.
+- Maven Central and PyPI expose the intended release versions.
+- Versioned documentation, download links, and release notes are published.
+- The announcement links the public release, and superseded candidates have
+ been handled without replacing the artifacts reviewed in the vote.
diff --git a/docs/docs/project/releases.md b/docs/docs/project/releases.md
new file mode 100644
index 0000000000..3e23b79fb7
--- /dev/null
+++ b/docs/docs/project/releases.md
@@ -0,0 +1,159 @@
+---
+title: "Release Overview"
+sidebar_position: 1
+---
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+# Release Overview
+
+Paimon and PyPaimon share a release version and a community vote. This page
+explains what is released and who does each part of the work. Use the linked
+guides for commands and verification steps.
+
+| Your task | Guide | Result |
+| --- | --- | --- |
+| Manage a release candidate (RC) | [Creating a release](./creating-a-release.md) | Signed source archives, a closed Java staging repository, and a vote thread |
+| Review a candidate | [Verifying a release candidate](./verifying-a-release-candidate.md) | An independent vote with the checks and environment recorded |
+| Publish an approved candidate | [Publishing a release](./publishing-a-release.md) | Public artifacts, documentation, release notes, and announcement |
+
+## Release lifecycle
+
+
+
+[Open the lifecycle diagram at full size](/img/project/release-lifecycle.svg).
+
+1. The Release Manager (RM) agrees the scope with the community and creates a
+ signed RC tag.
+2. GitHub Actions packages convenience artifacts. The RM signs and stages the
+ Java artifacts and both source archives from the same tag.
+3. Community members independently verify the candidate and vote. The RM
+ records the result.
+4. After approval, the RM publishes the approved artifacts and updates the
+ documentation and website before announcing the release. A failed
+ candidate needs a new RC number and a new vote.
+
+The process follows the [ASF Release Policy](https://www.apache.org/legal/release-policy.html)
+and [ASF Release Distribution Policy](https://infra.apache.org/release-distribution.html).
+
+:::warning Preserve the approved candidate
+
+The signed source archives are the Apache releases. Maven and PyPI packages
+are convenience artifacts. Promote the source archives and closed Java
+repository approved by the vote; do not rebuild or replace them. The final
+PyPI package is built from the approved commit with the final version.
+
+:::
+
+## Release model
+
+The combined Paimon and PyPaimon release uses one shared version number. The
+Maven project version and `paimon-python/setup.py` version must be equal.
+
+| Deliverable | Candidate | Published location |
+| --- | --- | --- |
+| Paimon source | `apache-paimon-PAIMON_VERSION-src.tgz`, `.asc`, `.sha512` | ASF distribution |
+| Java convenience artifacts | Maven artifacts built in the JDK 8, 11, and 17 lanes | Apache Nexus staging, then Maven Central |
+| PyPaimon source | `pypaimon-PAIMON_VERSION.tar.gz`, `.asc`, `.sha512` | ASF distribution |
+| Python convenience package | `pypaimon==PAIMON_VERSIONrcRC_NUMBER` for an RC | TestPyPI, then `pypaimon==PAIMON_VERSION` on PyPI |
+
+A combined release vote covers both signed source candidates. This guide does
+not define an independent PyPaimon release. Before releasing PyPaimon
+separately, the PMC must define a Python-only tag and workflow which do not
+depend on the Maven version or Java jobs, and must provide a signed source
+package which is independently sufficient to build and test the release.
+
+### Java build matrix
+
+The three Java lanes are different release targets, not interchangeable build
+JDKs:
+
+| JDK | Maven profiles and scope | Main artifacts |
+| --- | --- | --- |
+| 8 | `spark3,flink1` and the default reactor | Paimon core, Flink 1.x, Spark 3.x, Hive, filesystems, bundles, and other Java 8 artifacts |
+| 11 | `flink2` plus `paimon-iceberg` | Flink 2.x, `paimon-flink2-common`, and Iceberg integration |
+| 17 | `spark4` | Spark 4.x and its Scala 2.13 common artifacts |
+
+Each lane must use the matching JDK. Building everything on JDK 17 with a lower
+compiler target is not a substitute for running the JDK 8 and JDK 11 lanes.
+
+## GitHub Actions release workflow
+
+The release process uses the
+[Release workflow](https://github.com/apache/paimon/actions/workflows/release.yml)
+to package the JDK 8, JDK 11, and JDK 17 Java lanes and PyPaimon from every
+signed RC tag. The Java lanes are merged into one unsigned Maven repository
+image. The RM downloads that image, signs it, and stages it in Nexus. The RM
+also creates and signs the two ASF source archives locally from the same tag.
+The RM's GPG private key is never stored in GitHub Actions.
+
+The workflow has the following contract:
+
+| Job | Required behavior |
+| --- | --- |
+| Validation | Require an RC tag named `release-PAIMON_VERSION-rcN` or a final tag named `release-PAIMON_VERSION`, where `PAIMON_VERSION` exactly equals the root Maven `project.version` |
+| Java 8 | Use Temurin 8 to deploy the default reactor with Spark 3 and Flink 1 into a local Maven repository image |
+| Java 11 | Use Temurin 11 to deploy Flink 2 and Iceberg into a local Maven repository image |
+| Java 17 | Use Temurin 17 to deploy Spark 4 into a local Maven repository image |
+| Java repository | Require every deploy-enabled effective-POM project and its POM, main JAR, and source JAR; retain Javadoc JARs where Maven produces them; merge all three lanes; reject conflicting coordinates; then upload the complete unsigned Maven repository image, checksums, manifests, and logs |
+| Python package | Build and validate the PyPaimon source distribution and universal wheel, then upload them as workflow artifacts |
+| Python publish | Publish an RC to TestPyPI or a final tag to PyPI after Python packaging passes, without waiting for Java packaging |
+
+Before packaging, every Java lane runs Maven Enforcer's
+`requireReleaseVersion` and `requireReleaseDeps` rules over its complete reactor
+scope. The latter includes transitive dependencies. Any remaining
+`-SNAPSHOT` project, parent, direct dependency, or transitive dependency is a
+release blocker.
+
+The Java jobs run independently of the common validation and Python jobs. They
+use `-Dgpg.skip=true`, deploy only to runner-local file repositories, and never
+receive Nexus credentials or a GPG private key. The combined repository image
+contains POMs, main artifacts, source JARs, Javadoc JARs produced by Maven, and
+Maven-generated checksums. Scala-only and wrapper modules may not produce a
+Javadoc JAR. The image is the input to the RM's local signing and Nexus
+staging steps, not itself an ASF release. The Python RC job uses the
+`TEST_PYPI_API_TOKEN` repository Actions secret to publish
+`PAIMON_VERSIONrcRC_NUMBER` to TestPyPI. The final job uses the
+`PYPI_API_TOKEN` repository Actions secret to publish to PyPI. The release
+workflow passes only these two secrets to the reusable publishing workflow.
+
+## Artifact flow
+
+
+
+[Open the artifact diagram at full size](/img/project/release-artifacts.svg).
+
+Source and Java publication preserve the approved bytes. Python publication
+builds the final PyPI version from the final tag at the approved RC commit.
+All three paths must be checked before the release announcement.
+
+## Responsibilities and handoffs
+
+| Owner | Responsibility | Evidence to hand off |
+| --- | --- | --- |
+| RM | Review relevant CI results and prepare an immutable candidate | Signed tag, commit SHA, and release versions |
+| GitHub Actions | Package Java lanes and Python artifacts | Run URL, manifests, checksums, logs, and TestPyPI version |
+| RM | Sign locally and stage the candidate | Both source URLs, signing-key fingerprint, and closed Nexus repository URL |
+| Voters | Independently inspect, build, and test the source candidate | Vote with actual checks, platforms, tool versions, and any failures |
+| RM | Tally the vote and publish after approval | Vote result, final tag, public downloads, and updated documentation |
+
+The Java packaging lanes do not run the full test matrix. The RM reviews
+relevant CI results before calling the vote, and voters report their own
+source build and test scope. Packaging success alone is not release approval.
diff --git a/docs/docs/project/security.md b/docs/docs/project/security.md
index 134569d19d..e8dc525def 100644
--- a/docs/docs/project/security.md
+++ b/docs/docs/project/security.md
@@ -1,6 +1,6 @@
---
title: "Security"
-sidebar_position: 4
+sidebar_position: 2
---
<!--
@@ -24,6 +24,10 @@ under the License.
# Security
+Use this page to report a possible vulnerability and understand which trust
+boundaries Paimon owns. For ordinary bugs, use the
+[contribution guide](./contributing.md#what-do-you-want-to-do).
+
## Reporting Security Issues
The Apache Paimon Project uses the standard process outlined by the
@@ -34,11 +38,13 @@ Note that vulnerabilities should not be publicly disclosed until the project
has responded.
To report a possible security vulnerability, please email
-**[security@apache.org](mailto:security@apache.org)**.
+**[security@apache.org](mailto:security@apache.org)**. Include the affected
+Paimon version, deployment context, steps to reproduce, and the observed
+impact. Remove live credentials from examples and logs.
## Security Model
-Apache Paimon is a data lake platform and a set of libraries and integrations
+Apache Paimon is a data lake platform and a set of libraries and integrations
used inside larger systems such as catalogs, query engines, and services.
In most deployments, the primary trust and authorization boundaries are
diff --git a/docs/docs/project/verifying-a-release-candidate.md b/docs/docs/project/verifying-a-release-candidate.md
index d2ea99b6b3..c0a5b55933 100644
--- a/docs/docs/project/verifying-a-release-candidate.md
+++ b/docs/docs/project/verifying-a-release-candidate.md
@@ -29,6 +29,29 @@ PyPaimon source archives are the release. Maven, TestPyPI, and GitHub Actions
checks supplement source verification but do not replace it.
Report only the checks, platforms, and tool versions that you actually used.
+For roles and artifact relationships, see the [release overview](./releases.md).
+
+## Verification checklist
+
+Work through the checks in order, using the candidate named in the vote email.
+Keep notes for the [vote report](#report-your-vote).
+
+| Check | Evidence to record |
+| --- | --- |
+| [Collect inputs](#collect-the-candidate-inputs) | Version, RC number, source URLs, tag, commit, workflow, and staging URLs |
+| [Verify signatures and checksums](#verify-signatures-and-checksums) | Signing-key fingerprint and successful checks for both archives |
+| [Verify Git provenance](#verify-git-provenance) | Signed tag resolves to the announced commit |
+| [Inspect archives](#inspect-the-source-archives) | Expected source contents, versions, licenses, and legal reports |
+| [Build Java from source](#build-java-from-the-source-archive) | JDK, Maven, platform, build scope, and test or smoke-test result |
+| [Inspect Java staging](#verify-the-java-staging-repository) | Closed repository, complete artifacts, and representative runtime checks |
+| [Build and test PyPaimon](#build-and-test-pypaimon-from-source) | Python versions, package contents, and actual test results |
+| [Check TestPyPI](#verify-the-testpypi-candidate) | Exact RC installation and representative read/write result |
+| [Review workflow evidence](#review-github-actions-evidence) | Matching provenance, package manifests, and successful packaging lanes |
+
+For a binding `+1`, download all signed source packages, verify them, compile
+them, and test the result on your own platform, as required by the
+[ASF Release Policy](https://www.apache.org/legal/release-policy.html#release-approval).
+The optional packaging commands below skip tests and do not replace this work.
## Collect the candidate inputs
@@ -319,8 +342,9 @@ test suite for the PyPaimon candidate is supplied in the signed Paimon source
archive; the PyPaimon source distribution must not be used by itself for an
independent release. Run the tests from
`paimon-PAIMON_VERSION/paimon-python` on as many supported Python versions as
-your environment allows. The project CI selects Python 3.6, 3.7, 3.10, and
-3.11 for its main compatibility lanes:
+your environment allows. Use the Python matrix in the candidate's
+`.github/workflows/paimon-python-checks.yml` to select relevant versions rather
+than assuming that a matrix from another release applies:
```shell
(
diff --git a/docs/sidebars.js b/docs/sidebars.js
index eb32e6c79f..9c9f11a299 100644
--- a/docs/sidebars.js
+++ b/docs/sidebars.js
@@ -671,11 +671,25 @@ const sidebars = {
},
"items": [
"project/download",
- "project/creating-a-release",
- "project/verifying-a-release-candidate",
- "project/contributing",
- "project/committer",
- "project/security"
+ "project/security",
+ {
+ type: "category",
+ "label": "Community",
+ "items": [
+ "project/contributing",
+ "project/committer"
+ ]
+ },
+ {
+ type: "category",
+ "label": "Releases",
+ "link": { type: "doc", "id": "project/releases" },
+ "items": [
+ "project/creating-a-release",
+ "project/verifying-a-release-candidate",
+ "project/publishing-a-release"
+ ]
+ }
]
},
{
diff --git a/docs/static/img/project/contribution-workflow.svg b/docs/static/img/project/contribution-workflow.svg
new file mode 100644
index 0000000000..86cbc82fae
--- /dev/null
+++ b/docs/static/img/project/contribution-workflow.svg
@@ -0,0 +1,55 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="960" height="436" viewBox="0 0 960 436" role="img" aria-labelledby="title desc">
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<title id="title">From an idea to a merged contribution</title>
+<desc id="desc">Discuss the problem and agree on an approach. Implement a focused change with tests and documentation. Address review feedback; reviewers resolve conversations. A committer merges after requirements are met. Review feedback can lead back to implementation.</desc>
+<defs><marker id="arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" fill="#526277"/></marker></defs>
+<g font-family="Arial, Helvetica, sans-serif">
+<rect x="1" y="1" width="958" height="434" rx="12" fill="#ffffff" stroke="#d7dfeb" stroke-width="1.5"/>
+<text x="28" y="44" font-size="27" fill="#172b4d" font-weight="700" text-anchor="start">From an idea to a merged contribution</text>
+<text x="28" y="76" font-size="18" fill="#526277" font-weight="400" text-anchor="start">Agree on the problem, keep the change focused, and work with reviewers.</text>
+<rect x="28" y="117" width="199" height="153" rx="8" fill="#eaf2ff" stroke="#2463b4" stroke-width="1.5"/>
+<text x="127.5" y="150" font-size="21" fill="#2463b4" font-weight="700" text-anchor="middle">1 Discuss</text>
+<text x="127.5" y="180" font-size="18" fill="#526277" font-weight="400" text-anchor="middle">Explain the use case</text>
+<text x="127.5" y="205" font-size="18" fill="#526277" font-weight="400" text-anchor="middle">Agree on an approach</text>
+<text x="127.5" y="230" font-size="18" fill="#526277" font-weight="400" text-anchor="middle">Request assignment</text>
+<rect x="263" y="117" width="199" height="153" rx="8" fill="#eaf2ff" stroke="#2463b4" stroke-width="1.5"/>
+<text x="362.5" y="150" font-size="21" fill="#2463b4" font-weight="700" text-anchor="middle">2 Implement</text>
+<text x="362.5" y="180" font-size="18" fill="#526277" font-weight="400" text-anchor="middle">Follow the agreement</text>
+<text x="362.5" y="205" font-size="18" fill="#526277" font-weight="400" text-anchor="middle">Add tests and docs</text>
+<text x="362.5" y="230" font-size="18" fill="#526277" font-weight="400" text-anchor="middle">Open a focused PR</text>
+<rect x="498" y="117" width="199" height="153" rx="8" fill="#eaf2ff" stroke="#2463b4" stroke-width="1.5"/>
+<text x="597.5" y="150" font-size="21" fill="#2463b4" font-weight="700" text-anchor="middle">3 Review</text>
+<text x="597.5" y="180" font-size="18" fill="#526277" font-weight="400" text-anchor="middle">Address feedback</text>
+<text x="597.5" y="205" font-size="18" fill="#526277" font-weight="400" text-anchor="middle">Keep checks passing</text>
+<text x="597.5" y="230" font-size="18" fill="#526277" font-weight="400" text-anchor="middle">Reviewer resolves</text>
+<rect x="733" y="117" width="199" height="153" rx="8" fill="#e8f7f2" stroke="#087f6e" stroke-width="1.5"/>
+<text x="832.5" y="150" font-size="21" fill="#087f6e" font-weight="700" text-anchor="middle">4 Merge</text>
+<text x="832.5" y="180" font-size="18" fill="#526277" font-weight="400" text-anchor="middle">Committer checks</text>
+<text x="832.5" y="205" font-size="18" fill="#526277" font-weight="400" text-anchor="middle">the requirements</text>
+<text x="832.5" y="230" font-size="18" fill="#526277" font-weight="400" text-anchor="middle">and merges the PR</text>
+<path d="M 227 192 H 263" fill="none" stroke="#526277" stroke-width="2" marker-end="url(#arrow)"/>
+<path d="M 462 192 H 498" fill="none" stroke="#526277" stroke-width="2" marker-end="url(#arrow)"/>
+<path d="M 697 192 H 733" fill="none" stroke="#526277" stroke-width="2" marker-end="url(#arrow)"/>
+<path d="M 597 270 V 315 H 362 V 270" fill="none" stroke="#526277" stroke-width="2" stroke-dasharray="6 5" marker-end="url(#arrow)"/>
+<text x="480" y="343" font-size="18" fill="#526277" font-weight="400" text-anchor="middle">Revise the change as review progresses</text>
+<rect x="28" y="370" width="904" height="42" rx="8" fill="#f5f7fb" stroke="#c6d1df" stroke-width="1.5"/>
+<text x="480" y="397" font-size="18" fill="#172b4d" font-weight="400" text-anchor="middle">Small fixes, documentation, testing, and community support all count.</text>
+</g>
+</svg>
diff --git a/docs/static/img/project/release-artifacts.svg b/docs/static/img/project/release-artifacts.svg
new file mode 100644
index 0000000000..1b052ecced
--- /dev/null
+++ b/docs/static/img/project/release-artifacts.svg
@@ -0,0 +1,83 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="960" height="718" viewBox="0 0 960 718" role="img" aria-labelledby="title desc">
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<title id="title">Follow each artifact from the same signed RC tag</title>
+<desc id="desc">A signed RC tag identifies one commit. The Release Manager creates and signs the Paimon and PyPaimon source archives locally, stages them in ASF dist dev, and promotes them after approval. GitHub Actions packages Java on JDK 8, 11, and 17; the Release Manager signs the merged repository and closes it in Nexus, then promotes it to Maven Central after approval. Python validation and packaging publish the RC to TestPyPI independently of Java. After approval, the final signed [...]
+<defs><marker id="arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" fill="#526277"/></marker></defs>
+<g font-family="Arial, Helvetica, sans-serif">
+<rect x="1" y="1" width="958" height="716" rx="12" fill="#ffffff" stroke="#d7dfeb" stroke-width="1.5"/>
+<text x="28" y="44" font-size="27" fill="#172b4d" font-weight="700" text-anchor="start">Follow each artifact from the same signed RC tag</text>
+<text x="28" y="76" font-size="18" fill="#526277" font-weight="400" text-anchor="start">Sources define the Apache release; Java and Python packages are convenience artifacts.</text>
+<rect x="28" y="101" width="904" height="52" rx="8" fill="#eaf2ff" stroke="#2463b4" stroke-width="1.5"/>
+<text x="480" y="133" font-size="19" fill="#2463b4" font-weight="700" text-anchor="middle">Signed RC tag → one recorded commit and matching Paimon / PyPaimon versions</text>
+<text x="192" y="192" font-size="16" fill="#172b4d" font-weight="700" text-anchor="middle">BUILD AND SIGN</text>
+<text x="514" y="192" font-size="16" fill="#172b4d" font-weight="700" text-anchor="middle">CANDIDATE FOR REVIEW</text>
+<text x="820" y="192" font-size="16" fill="#087f6e" font-weight="700" text-anchor="middle">AFTER VOTE APPROVAL</text>
+<path d="M 665 178 V 653" fill="none" stroke="#526277" stroke-width="2" stroke-dasharray="6 5"/>
+<rect x="28" y="213" width="328" height="114" rx="8" fill="#eaf2ff" stroke="#2463b4" stroke-width="1.5"/>
+<text x="192.0" y="246" font-size="21" fill="#2463b4" font-weight="700" text-anchor="middle">Source archives · RM</text>
+<text x="192.0" y="276" font-size="18" fill="#526277" font-weight="400" text-anchor="middle">Build both sources locally</text>
+<text x="192.0" y="301" font-size="18" fill="#526277" font-weight="400" text-anchor="middle">Sign and checksum each archive</text>
+<rect x="404" y="213" width="220" height="114" rx="8" fill="#eaf2ff" stroke="#2463b4" stroke-width="1.5"/>
+<text x="514.0" y="246" font-size="21" fill="#2463b4" font-weight="700" text-anchor="middle">ASF dist dev</text>
+<text x="514.0" y="276" font-size="18" fill="#526277" font-weight="400" text-anchor="middle">Paimon + PyPaimon</text>
+<text x="514.0" y="301" font-size="18" fill="#526277" font-weight="400" text-anchor="middle">Signed source archives</text>
+<rect x="692" y="213" width="240" height="114" rx="8" fill="#e8f7f2" stroke="#087f6e" stroke-width="1.5"/>
+<text x="812.0" y="246" font-size="21" fill="#087f6e" font-weight="700" text-anchor="middle">ASF dist release</text>
+<text x="812.0" y="276" font-size="18" fill="#526277" font-weight="400" text-anchor="middle">Move approved directories</text>
+<text x="812.0" y="301" font-size="18" fill="#526277" font-weight="400" text-anchor="middle">Preserve every file</text>
+<path d="M 356 270 H 404" fill="none" stroke="#526277" stroke-width="2" marker-end="url(#arrow)"/>
+<path d="M 624 270 H 692" fill="none" stroke="#526277" stroke-width="2" marker-end="url(#arrow)"/>
+<rect x="28" y="355" width="328" height="137" rx="8" fill="#eaf2ff" stroke="#2463b4" stroke-width="1.5"/>
+<text x="192.0" y="388" font-size="21" fill="#2463b4" font-weight="700" text-anchor="middle">Java · Actions, then RM</text>
+<text x="192.0" y="418" font-size="18" fill="#526277" font-weight="400" text-anchor="middle">Package on JDK 8 / 11 / 17</text>
+<text x="192.0" y="443" font-size="18" fill="#526277" font-weight="400" text-anchor="middle">Merge the unsigned repository</text>
+<text x="192.0" y="468" font-size="18" fill="#526277" font-weight="400" text-anchor="middle">RM signs and stages locally</text>
+<rect x="404" y="355" width="220" height="137" rx="8" fill="#eaf2ff" stroke="#2463b4" stroke-width="1.5"/>
+<text x="514.0" y="388" font-size="21" fill="#2463b4" font-weight="700" text-anchor="middle">Closed Nexus repo</text>
+<text x="514.0" y="418" font-size="18" fill="#526277" font-weight="400" text-anchor="middle">One complete repository</text>
+<text x="514.0" y="443" font-size="18" fill="#526277" font-weight="400" text-anchor="middle">Signatures + checksums</text>
+<text x="514.0" y="468" font-size="18" fill="#526277" font-weight="400" text-anchor="middle">Same RC commit</text>
+<rect x="692" y="355" width="240" height="137" rx="8" fill="#e8f7f2" stroke="#087f6e" stroke-width="1.5"/>
+<text x="812.0" y="388" font-size="21" fill="#087f6e" font-weight="700" text-anchor="middle">Maven Central</text>
+<text x="812.0" y="418" font-size="18" fill="#526277" font-weight="400" text-anchor="middle">Release the approved repo</text>
+<text x="812.0" y="443" font-size="18" fill="#526277" font-weight="400" text-anchor="middle">Preserve every artifact</text>
+<text x="812.0" y="468" font-size="18" fill="#526277" font-weight="400" text-anchor="middle">No Java rebuild</text>
+<path d="M 356 423 H 404" fill="none" stroke="#526277" stroke-width="2" marker-end="url(#arrow)"/>
+<path d="M 624 423 H 692" fill="none" stroke="#526277" stroke-width="2" marker-end="url(#arrow)"/>
+<rect x="28" y="520" width="328" height="137" rx="8" fill="#eaf2ff" stroke="#2463b4" stroke-width="1.5"/>
+<text x="192.0" y="553" font-size="21" fill="#2463b4" font-weight="700" text-anchor="middle">Python · Actions</text>
+<text x="192.0" y="583" font-size="18" fill="#526277" font-weight="400" text-anchor="middle">Validate and package</text>
+<text x="192.0" y="608" font-size="18" fill="#526277" font-weight="400" text-anchor="middle">Publish after Python succeeds</text>
+<text x="192.0" y="633" font-size="18" fill="#526277" font-weight="400" text-anchor="middle">Runs independently of Java</text>
+<rect x="404" y="520" width="220" height="137" rx="8" fill="#eaf2ff" stroke="#2463b4" stroke-width="1.5"/>
+<text x="514.0" y="553" font-size="21" fill="#2463b4" font-weight="700" text-anchor="middle">TestPyPI</text>
+<text x="514.0" y="583" font-size="18" fill="#526277" font-weight="400" text-anchor="middle">Candidate version</text>
+<text x="514.0" y="608" font-size="18" fill="#526277" font-weight="400" text-anchor="middle">VERSIONrcN</text>
+<text x="514.0" y="633" font-size="18" fill="#526277" font-weight="400" text-anchor="middle">For community testing</text>
+<rect x="692" y="520" width="240" height="137" rx="8" fill="#e8f7f2" stroke="#087f6e" stroke-width="1.5"/>
+<text x="812.0" y="553" font-size="21" fill="#087f6e" font-weight="700" text-anchor="middle">PyPI</text>
+<text x="812.0" y="583" font-size="18" fill="#526277" font-weight="400" text-anchor="middle">Final tag at RC commit</text>
+<text x="812.0" y="608" font-size="18" fill="#526277" font-weight="400" text-anchor="middle">Build the final VERSION</text>
+<text x="812.0" y="633" font-size="18" fill="#526277" font-weight="400" text-anchor="middle">Same approved source</text>
+<path d="M 356 588 H 404" fill="none" stroke="#526277" stroke-width="2" marker-end="url(#arrow)"/>
+<path d="M 624 588 H 692" fill="none" stroke="#526277" stroke-width="2" stroke-dasharray="6 5" marker-end="url(#arrow)"/>
+<text x="28" y="690" font-size="17" fill="#526277" font-weight="400" text-anchor="start">Solid arrows: stage / promote artifacts. Dashed arrow: build the final Python version.</text>
+</g>
+</svg>
diff --git a/docs/static/img/project/release-lifecycle.svg b/docs/static/img/project/release-lifecycle.svg
new file mode 100644
index 0000000000..9e9d3551f3
--- /dev/null
+++ b/docs/static/img/project/release-lifecycle.svg
@@ -0,0 +1,55 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="960" height="448" viewBox="0 0 960 448" role="img" aria-labelledby="title desc">
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<title id="title">A candidate becomes a release after approval</title>
+<desc id="desc">The Release Manager prepares an immutable signed RC tag, stages source and convenience artifacts, and calls the community vote. After verification and approval, the approved candidate is published. Problems require fixes, a new RC number, and a new vote.</desc>
+<defs><marker id="arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" fill="#526277"/></marker></defs>
+<g font-family="Arial, Helvetica, sans-serif">
+<rect x="1" y="1" width="958" height="446" rx="12" fill="#ffffff" stroke="#d7dfeb" stroke-width="1.5"/>
+<text x="28" y="44" font-size="27" fill="#172b4d" font-weight="700" text-anchor="start">A candidate becomes a release after approval</text>
+<text x="28" y="76" font-size="18" fill="#526277" font-weight="400" text-anchor="start">One shared Paimon / PyPaimon version; one immutable candidate per vote.</text>
+<rect x="28" y="117" width="199" height="153" rx="8" fill="#eaf2ff" stroke="#2463b4" stroke-width="1.5"/>
+<text x="127.5" y="150" font-size="21" fill="#2463b4" font-weight="700" text-anchor="middle">1 Prepare</text>
+<text x="127.5" y="180" font-size="18" fill="#526277" font-weight="400" text-anchor="middle">Agree on the scope</text>
+<text x="127.5" y="205" font-size="18" fill="#526277" font-weight="400" text-anchor="middle">Set both versions</text>
+<text x="127.5" y="230" font-size="18" fill="#526277" font-weight="400" text-anchor="middle">Sign the RC tag</text>
+<rect x="263" y="117" width="199" height="153" rx="8" fill="#eaf2ff" stroke="#2463b4" stroke-width="1.5"/>
+<text x="362.5" y="150" font-size="21" fill="#2463b4" font-weight="700" text-anchor="middle">2 Stage</text>
+<text x="362.5" y="180" font-size="18" fill="#526277" font-weight="400" text-anchor="middle">Sign source archives</text>
+<text x="362.5" y="205" font-size="18" fill="#526277" font-weight="400" text-anchor="middle">Close Java staging</text>
+<text x="362.5" y="230" font-size="18" fill="#526277" font-weight="400" text-anchor="middle">Publish to TestPyPI</text>
+<rect x="498" y="117" width="199" height="153" rx="8" fill="#fff6e5" stroke="#946200" stroke-width="1.5"/>
+<text x="597.5" y="150" font-size="21" fill="#946200" font-weight="700" text-anchor="middle">3 Verify + vote</text>
+<text x="597.5" y="180" font-size="18" fill="#526277" font-weight="400" text-anchor="middle">Check the candidate</text>
+<text x="597.5" y="205" font-size="18" fill="#526277" font-weight="400" text-anchor="middle">Build and test source</text>
+<text x="597.5" y="230" font-size="18" fill="#526277" font-weight="400" text-anchor="middle">Record the result</text>
+<rect x="733" y="117" width="199" height="153" rx="8" fill="#e8f7f2" stroke="#087f6e" stroke-width="1.5"/>
+<text x="832.5" y="150" font-size="21" fill="#087f6e" font-weight="700" text-anchor="middle">4 Publish</text>
+<text x="832.5" y="180" font-size="18" fill="#526277" font-weight="400" text-anchor="middle">Promote artifacts</text>
+<text x="832.5" y="205" font-size="18" fill="#526277" font-weight="400" text-anchor="middle">Verify final packages</text>
+<text x="832.5" y="230" font-size="18" fill="#526277" font-weight="400" text-anchor="middle">Docs, then announce</text>
+<path d="M 227 192 H 263" fill="none" stroke="#526277" stroke-width="2" marker-end="url(#arrow)"/>
+<path d="M 462 192 H 498" fill="none" stroke="#526277" stroke-width="2" marker-end="url(#arrow)"/>
+<path d="M 697 192 H 733" fill="none" stroke="#526277" stroke-width="2" marker-end="url(#arrow)"/>
+<path d="M 597 270 V 318 H 127 V 270" fill="none" stroke="#526277" stroke-width="2" stroke-dasharray="6 5" marker-end="url(#arrow)"/>
+<text x="362" y="347" font-size="18" fill="#526277" font-weight="400" text-anchor="middle">Problem found: fix it, increment RC, and vote again</text>
+<rect x="28" y="378" width="904" height="42" rx="8" fill="#f5f7fb" stroke="#c6d1df" stroke-width="1.5"/>
+<text x="480" y="405" font-size="18" fill="#172b4d" font-weight="400" text-anchor="middle">Keep the approved source archives, Java repository, and commit unchanged.</text>
+</g>
+</svg>