Hi Leonard,

Thanks a lot for the support! Appreciate it

Giannis has already granted me the Confluence permissions, so I will migrate
this draft there.

- Anton

чт, 23 апр. 2026 г. в 09:14, Leonard Xu <[email protected]>:
>
> +1 from my side, the motivation and the proposed merge plan makes sense to me.
>
> Btw, could you left your jira account name? Anton, we can add the Confluence 
> edit permission for you.
>
> Best,
> Leonard
>
> > 2026 4月 23 14:50,Anton Borisov <[email protected]> 写道:
> >
> > Hi all,
> >
> > Following up on the 0.2.0-incubating roadmap thread, where the repo
> > merge came through as the strongest priority signal, I am opening this
> > as its own [DISCUSS] as promised.
> >
> > Per the consensus on that thread, 0.2.0 development continues on
> > fluss-rust in parallel and is not blocked by this FIP.
> >
> > I do not currently have edit rights on the FLUSS Confluence space, so
> > I am posting the full draft inline. Once discussion converges, a
> > committer can paste the agreed text into a FIP-XX page. Please treat
> > the text below as a working draft; I am happy to revise it as feedback
> > comes in.
> >
> > ===============================================================
> > FIP-XX: Consolidate apache/fluss-rust into apache/fluss
> >
> > Discussion thread: this thread
> > Vote thread: TBD
> > Release: Fluss 1.0 (target)
> > Status: Under Discussion
> >
> > Motivation
> > =============
> >
> > Fluss source code currently lives in two ASF repos.
> >
> > 1.1 Current layout today
> >
> > apache/fluss
> > ├─ fluss-server/
> > ├─ fluss-client/
> > ├─ fluss-rpc/
> > │ └─ src/main/proto/*.proto
> > ├─ fluss-flink/, fluss-spark/, ...
> > ├─ website/
> > │ └─ fluss.apache.org
> > └─ .github/workflows/
> >
> > apache/fluss-rust
> > ├─ crates/fluss/
> > │ └─ src/proto/*.proto
> > │ hand-ported subset
> > ├─ bindings/python/
> > ├─ bindings/cpp/
> > ├─ bindings/elixir/
> > ├─ website/
> > │ └─ clients.fluss.apache.org
> > └─ .github/workflows/
> >
> > fluss-rust was incubated in its own repo so the Rust core could move
> > quickly. With 1.0 GA on the horizon, the costs of the split now exceed
> > the benefit.
> >
> > As discussed on the 0.2.0 thread, 1.0 should represent the complete
> > form of the project: all language SDKs and unified release
> > coordination from a single repository, to signal maturity to users. A
> > fragmented multi-repo layout at GA undermines that message.
> >
> > 1.2 Concrete costs today
> >
> > Protobuf schema is duplicated and can diverge. The source of truth is
> > fluss-rpc/src/main/proto/FlussApi.proto (package fluss).
> > fluss-rust carries a hand-maintained subset at
> > crates/fluss/src/proto/fluss_api.proto (package proto).
> > The subset exists only because the two repos cannot share files;
> > nothing enforces consistency.
> >
> > Server version is pinned manually in two files:
> > crates/fluss-test-cluster/test-images.env and
> > bindings/elixir/test/support/cluster.ex, both pointing today to
> > apache/fluss:0.9.0-incubating, with no automation.
> >
> > Docs are split across two subdomains. fluss.apache.org/docs/apis/
> > *-client.md pages are stubs that link out to
> > clients.fluss.apache.org/user-guide//... This means two
> > Docusaurus builds and two deployment pipelines.
> >
> > Infrastructure is duplicated: 8 CI workflows in each repo,
> > duplicated LICENSE / NOTICE / DISCLAIMER files at repo root, and
> > two release trains.
> >
> > Cross-repo changes cost two PRs, two reviews, and a Docker image cut
> > per wire-protocol change.
> >
> > 1.3 ASF peer evidence
> >
> > ASF peer evidence points the other way: mature ASF projects
> > overwhelmingly colocate language bindings with core.
> >
> > Apache Thrift -> apache/thrift/lib/{java,py,cpp,rs,go,rb,...}
> >
> > Apache Avro -> apache/avro/lang/{java,py,c,rust,ruby,...}
> >
> > Apache Beam -> apache/beam/sdks/{java,python,go,typescript}
> >
> > PyFlink -> apache/flink/flink-python/
> >
> > PySpark -> apache/spark/python/
> >
> > Apache Arrow is the visible counter-example: arrow-rs, arrow-go,
> > arrow-java, and arrow-js live in separate repos. Apache Avro also
> > externalized its Go binding (apache/avro-go) on a similar trajectory.
> > In both cases, the split happened after the format stabilized and
> > after the specific language community had grown large enough to
> > self-sustain.
> >
> > Fluss is at neither milestone. The wire protocol is still evolving
> > aggressively pre-1.0, and the Rust, Python, C++, and Elixir bindings
> > are all co-maintained by the same contributors. Splitting now incurs
> > coordination overhead that Arrow and Avro only accepted at maturity,
> > without yet having their enabling conditions.
> >
> > The Flink connector-externalization retrospective is sometimes cited,
> > but does not really apply: connectors are N external-system
> > integrations maintained by independent communities, not N language
> > wrappers over one wire protocol.
> >
> > Public interfaces
> > ====================
> >
> > None. Published artifacts remain unchanged:
> >
> > Maven Central: org.apache.fluss:fluss-*
> >
> > crates.io: fluss-rs
> >
> > PyPI: pyfluss
> >
> > git: Elixir fluss (planned hex.pm publication)
> >
> > CMake / Bazel: fluss-cpp
> >
> > Proposed changes
> > ===================
> >
> > Jark outlined the merge as five workstreams: code migration, CI
> > unification, documentation restructuring, issue migration, and
> > contributor workflow changes. Sections 3 and 4 address each.
> >
> > 3.1 Code migration - target layout
> >
> > apache/fluss/
> > ├─ fluss-server/ (Java, unchanged)
> > ├─ fluss-client/ (Java, unchanged)
> > ├─ fluss-rpc/ (single .proto source; see 3.4)
> > │ └─ src/main/proto/FlussApi.proto
> > ├─ fluss-flink/, fluss-spark/, ... (Java modules, unchanged)
> > ├─ fluss-rust/ (new: today's apache/fluss-rust tree)
> > │ ├─ Cargo.toml, Cargo.lock
> > │ ├─ crates/{fluss, examples, fluss-test-cluster}/
> > │ ├─ bindings/{python, cpp, elixir}/
> > │ ├─ justfile, MODULE.bazel, rust-toolchain.toml,
> > │ │ deny.toml, rustfmt.toml
> > │ └─ scripts/
> > ├─ website/ (unified Docusaurus; see 3.3)
> > └─ .github/workflows/ (unified with path filters; see 3.2)
> >
> > fluss-rust mirrors sibling naming such as fluss-server/ and
> > fluss-flink/. Bindings stay nested because they share a Cargo
> > workspace, rust-toolchain.toml, deny.toml, and workspace-level
> > dependency resolution with the Rust core.
> >
> > 3.2 CI unification
> >
> > A single .github/workflows/ directory. Path filters are a hard
> > requirement:
> >
> > Java CI: pom.xml, fluss-*/** (excluding fluss-rust/), tools/**
> >
> > Rust core CI: fluss-rust/Cargo.*, fluss-rust/crates/**
> > OR fluss-rpc/src/main/proto/**
> >
> > Binding CI: fluss-rust/bindings//**
> > OR fluss-rpc/src/main/proto/**
> >
> > Docs build: website/**
> >
> > Existing release workflows move over unchanged. Their triggers are
> > tag-based and already disjoint from each other.
> >
> > 3.3 Documentation restructuring
> >
> > fluss/website/docs/
> > ├─ intro.md
> > ├─ quickstart/
> > ├─ concepts/
> > ├─ clients/ (new section)
> > │ ├─ support-matrix.md
> > │ ├─ java/
> > │ ├─ rust/
> > │ ├─ python/
> > │ └─ cpp/
> > ├─ engine-flink/, engine-spark/, ...
> > └─ ...
> >
> > clients.fluss.apache.org is retired. Redirects from old paths use
> > @docusaurus/plugin-client-redirects, with mappings generated by
> > walking the two sidebars.ts files. The
> > fluss-rust/.github/workflows/deploy_documentation.yml workflow is
> > removed; deployment converges on the existing fluss/website ->
> > apache/fluss-website dispatch.
> >
> > 3.4 Protobuf single source of truth
> >
> > Today, crates/fluss/src/proto/fluss_api.proto exists as a
> > hand-maintained subset of the Java-side canonical proto solely because
> > the two repos could not share files. The merge removes that
> > constraint, and this FIP removes the subset.
> >
> > After the structural merge:
> >
> > Delete fluss-rust/crates/fluss/src/proto/fluss_api.proto.
> >
> > Point fluss-rust/crates/fluss/build.rs at the canonical proto:
> >
> > config.compile_protos(
> > &["../../../fluss-rpc/src/main/proto/FlussApi.proto"],
> > &["../../../fluss-rpc/src/main/proto"],
> > )?;
> >
> > Update the .bytes() prefixes in build.rs from ".proto." to
> > ".fluss." because the canonical proto declares package fluss.
> >
> > Update lib.rs include! from "/proto.rs" to "/fluss.rs", since
> > prost names the generated file after the proto package.
> >
> > The vendored copy exists only to satisfy crates.io packaging rules;
> > the monorepo build reads the canonical proto directly. For crates.io
> > publishing, vendor the canonical .proto into the crate at
> > cargo-publish time via scripts/release.sh, with build.rs falling
> > back to the in-crate copy when the monorepo path is absent.
> >
> > All existing crate::proto::TypeName call sites compile unchanged,
> > because the pub mod proto { ... } wrapper in lib.rs preserves the
> > import path.
> >
> > After this, adopting a new server RPC becomes a single-PR change: the
> > message lands in the canonical proto and Rust types appear
> > automatically. Nothing remains to drift against, so no CI drift-gate
> > is needed. Section 6 covers why a drift-gate alone would be the wrong
> > answer.
> >
> > 3.5 Release cadence
> >
> > Java server and Rust client keep their current independent SemVer
> > cadences until 1.0 GA. From 1.0 onward, both trees cut a jointly
> > numbered X.Y.Z release from a single tag; patch releases can still
> > ship independently where scope is binding-only or server-only.
> > Binding-specific SemVer continues where public APIs diverge, for
> > example if a pyfluss major bump is driven by PyO3 ABI changes.
> >
> > Open to revision: the post-1.0 release model is listed in section 8
> > and likely deserves its own [DISCUSS] once this FIP lands.
> >
> > Compatibility, deprecation, and migration plan
> > =================================================
> >
> > 4.1 Phases
> >
> > [0 Agreement] -> [1 Dry run] -> [2 Merge window] -> [3 Archive] -> [4 
> > Cleanup]
> >
> > DISCUSS + VOTE
> >
> > fork dry run
> >
> > follow-up PRs
> >
> > redirects
> >
> > INFRA ticket
> >
> > Agreement. This FIP's DISCUSS + VOTE. INFRA ticket filed and
> > resolved before VOTE is called, so the migration plan is confirmed
> > viable rather than assumed.
> >
> > Dry run on a fork: verify CI, path filters, docs build, redirects,
> > and git log --follow across the boundary.
> >
> > Merge window. Short freeze on apache/fluss-rust; structural merge
> > commit into apache/fluss. Protobuf (3.4) and docs (3.3)
> > consolidation land as separate follow-up PRs for reviewability.
> >
> > Archive. INFRA archives apache/fluss-rust read-only; issues, PRs,
> > commits, and tags remain as permalinks. Subdomain redirects go
> > live. A pinned README on the archived repo points to apache/fluss,
> > since GitHub does not forward content-moves between repos
> > automatically.
> >
> > Cleanup. Consolidate root-level duplicates such as LICENSE /
> > NOTICE / DISCLAIMER and contributor docs.
> >
> > 4.2 History preservation
> >
> > On a clone of apache/fluss-rust:
> >
> > git filter-repo --to-subdirectory-filter fluss-rust
> >
> > In apache/fluss:
> >
> > git remote add rust ../fluss-rust-rewritten
> > git fetch rust
> > git merge --allow-unrelated-histories --no-ff rust/main
> >
> > This preserves git log --follow and git blame --follow on every
> > rewritten file. git subtree breaks log --follow on files inside the
> > subtree; git filter-branch is deprecated.
> >
> > 4.3 Issue migration
> >
> > Closed issues and PRs remain at their apache/fluss-rust archive URLs
> > as permalinks. Open issues at merge time are re-filed in apache/fluss
> > with cross-links, scripted via gh CLI. Open PRs are reopened by their
> > authors against the new path; GitHub does not support cross-repo PR
> > transfer.
> >
> > 4.4 Contributor workflow
> >
> > Contributors re-clone and re-open in-flight PRs against the new path.
> > Downstream artifact consumers see no change. Docs visitors follow
> > redirects.
> >
> > 4.5 Timeline
> >
> > There is no dependency on a specific release. Target completion is
> > before 1.0 GA, per the fluss-rust roadmap 0.2.0 DISCUSS consensus.
> > Within that bound, the community can pick the window that minimizes
> > rebase pain, most likely after 0.2.0-incubating is cut, to avoid
> > forcing in-flight roadmap work to rebase across the merge.
> >
> > Test plan
> > ============
> >
> > In the merged repo, CI runs the full Java + Rust + all-binding
> > matrices on every PR.
> >
> > Path-filter correctness is explicitly tested: a Rust-only PR must
> > not trigger Java jobs, and vice versa.
> >
> > Protobuf: a change to fluss-rpc/src/main/proto/FlussApi.proto alone
> > produces a green Rust build with no Rust-side edit, confirming the
> > single-source claim.
> >
> > Docs: every fluss-rust/website/docs/user-guide/... page renders
> > under fluss.apache.org/docs/clients/...; sampled old URLs redirect.
> >
> > History: git log --follow on a sample migrated file shows full
> > pre-merge history.
> >
> > Rejected alternatives
> > ========================
> >
> > Status quo. The section 1 costs recur every release cycle and grow
> > with each new binding.
> >
> > Drift-gate instead of full proto consolidation. Keep the Rust
> > subset and add CI to flag divergence on messages present in both
> > files. Rejected because it catches only half the drift problem,
> > preserves a hand-maintained file whose only reason to exist was the
> > cross-repo constraint the merge removes, and adds custom comparison
> > logic to maintain.
> >
> > Polyglot-repo federation, Iceberg-style. This works for Iceberg
> > because bindings have independent maintainer communities and the
> > table-format spec is stable enough that protocol-evolution coupling
> > is low. Neither holds for Fluss pre-1.0: bindings are co-maintained
> > by the same team, and the wire protocol is still evolving
> > aggressively. For Fluss in the run-up to 1.0, locking bindings to
> > server evolution is a feature, not a bug.
> >
> > Apache Arrow precedent (arrow-rs split, 2021).
> > https://arrow.apache.org/blog/2021/05/04/rust-dev-workflow/
> > Section 1 covers the structural frame: Arrow split after
> > stabilization and after each binding had grown an autonomous
> > community. Arrow's specific 2021 rationale also inverts for Fluss.
> >
> > Git submodules. Standard UX problems and does not solve the docs
> > split.
> >
> > Further splitting into per-binding repos. This multiplies every cost
> > listed in section 1.
> >
> > Flatten bindings to the top level of the merged repo. This breaks
> > the shared Cargo workspace. Keeping them under fluss-rust/
> > preserves it; rearrangement remains an option later.
> >
> > Risks
> > ========
> >
> > CI blast radius if path filters are misconfigured. Mitigated by
> > sections 3.2 and 5.
> >
> > In-flight PRs stall during the freeze. Mitigated by maintainers
> > proactively reopening high-value PRs.
> >
> > Open questions
> > =================
> >
> > Directory name for the Rust tree. Proposal: fluss-rust/
> > (mirrors fluss-server/ and fluss-flink/ sibling naming).
> > Alternatives: rust/, clients/rust/.
> >
> > Docs section name. Proposal: docs/clients/ to unify client and
> > binding docs under one heading, while keeping docs/engine-*/ for
> > pipeline integrations. Alternative: keep docs/apis/ to reduce link
> > churn during migration.
> >
> > Post-1.0 release model. Section 3.5 proposes synchronized X.Y.Z
> > across Java and Rust with independent patches. Alternative:
> > Arrow-style coordinated-but-independent versioning. This likely
> > deserves its own [DISCUSS] once this FIP lands.
> >
> > Looking forward to feedback.
> >
> > Best,
> > Anton
>

Reply via email to