Trying to distill to 1st principles here - we have a few things to optimize for or make decisions on. Each of the following 3 have identical affordances between a separate cassandra-utils vs. lib published from C*: 1. Who can depend on the code. This is priority target #1; both fix. 2. Who breaks when the code changes. Right now it's everyone but C*. Either basic semver or per-API versioning fix this. 3. When integration happens. C* is pre-merge, everyone else is at time of integration. The knobs we can tune as I see it are: 1. Do we decouple API changes and bugfix availability? I say yes. This requires either one branch w/per-API versioning (as proposed in CEP), or semver utils where we only do breaking API changes on MAJOR. 2. When does that integration break surface? Status quo == lazy at integration time. Alternative would be CI targets wherever utils lives to surface breaks immediately. Some more observations / axioms: • Any combination of approaches (cassandra-utils vs. lib, versioned APIs vs. non) will be a strict improvement on copy-pasted duplicated code. • Any approach w/out API versioning couples bugfix adoption w/API integration. • Any versioned API approach pushes that friction upstream to people working on the shared utils to keep that separate, whether due to annotation-based versioning or maintaining multiple branches.
I think it's reasonable for us to target removing duplicated code and decoupling bug-fix integration in this shared code from API surface area change adoption. Before going further, do we broadly agree on these 2 goals? On Wed, Aug 19, 2026, at 4:29 AM, Štefan Miklošovič wrote: > I am not against the annotation as such but I think that we are trying > to do a lot of things at once. Just move the code over to utils, make > it 0.1.x, wait until it stabilizes, see what has a tendency to break / > change a lot and _then_ annotate if we still find it necessary to do > so. If you asked me "what to annotate with what" right now I would not > be able to say. > > I just prefer to move things progressively and not put annotations > into something we will be obliged to live with from day one without > gathering some evidence first if it is even really necessary and what > would that look like in practice etc ... Maybe we realize that, in > utils, just living with Semver and not having annotations at all is > actually good enough, but I just do not know right now. > > On Wed, Aug 19, 2026 at 2:30 AM Yifan Cai <[email protected]> wrote: > > > > Sharing my 2 cents. > > > > If we want the utils library to provide stable APIs from the start, > > deferring the annotation decision isn't deferring anything — it's deciding > > for public-by-default. > > > > If we want to preserve the flexibility of making breaking changes (since > > the version is 0.x), I'm good with deferring and getting things moving. > > > > Honestly, from the ecosystem projects' perspective — not just Cassandra, > > but also the projects under the same Cassandra umbrella — having the API > > lifecycle annotated makes life easier for both consumers and maintainers. > > That said, I am not going to die on this hill. > > > > - Yifan > > > > On Tue, Aug 18, 2026 at 2:45 PM Štefan Miklošovič <[email protected]> > > wrote: > >> > >> I feel like we are trying to solve everything at once. I think that > >> extracting the utility code outside of Cassandra is already enough to > >> deal with for now. That extraction might be a bit tricky, especially > >> if it depends on some 3rd party library etc ... If it is really only > >> about the candidates put into examples in the Scope section of the > >> CEP, the dependencies should be minimal. We should strive for utils > >> depending on the minimum of dependencies because as soon as it is > >> going to be used in another project which is itself depending on other > >> stuff there might be conflicts etc ... If utils is "pure Java" or > >> close enough to that then this problem is minimized. > >> > >> I would leave the discussion about annotation public / private etc. > >> for another time / outside of this CEP. In utils, for starters I would > >> just follow Semver (non-event for patch releases, code change on the > >> consumer side for minor releases) and leave annotations in Cassandra > >> out of this. > >> > >> On Tue, Aug 18, 2026 at 11:00 PM David Capwell <[email protected]> wrote: > >> > > >> > Thanks for the reply Francisco! > >> > > >> > > Instead, I was thinking that producing an artifact with utils > >> > > as part of the Cassandra release process is probably a > >> > > more sustainable approach. > >> > > >> > The main utility that has caused this debate are the test utilities > >> > which we do not publish as part of the cassandra release. Cassandra also > >> > only releases every 1-2 years so being able to pick up changes to these > >> > test utilize (including bug fixes) would have to follow that same > >> > timeline, making it harder to depend on; this was the motivating reason > >> > for extracting outside of Cassandra. > >> > > >> > > >> > > On Aug 18, 2026, at 1:17 PM, Francisco Guerrero <[email protected]> > >> > > wrote: > >> > > > >> > > I'm not convinced having utils in an external repo will > >> > > be a good idea. We already have problems with > >> > > Analytics/Sidecar repositories and you've been helping > >> > > with the effort of consolidating those repos. > >> > > > >> > > Instead, I was thinking that producing an artifact with utils > >> > > as part of the Cassandra release process is probably a > >> > > more sustainable approach. I would expect the classes in > >> > > this artifact will be mostly stable and don't expect many > >> > > changes. Ecosystem projects can consume the released > >> > > utils artifact. > >> > > > >> > > On 2026/08/18 14:05:05 Josh McKenzie wrote: > >> > >>> We just make sure the builds don't break. > >> > >> To ensure builds don't break across all projects using utils, we'd > >> > >> need to integrate a basic build of all GA supported branches of > >> > >> Cassandra and all ecosystem projects as a CI gate for the > >> > >> cassandra-utils project. That would foist needing to fix all > >> > >> dependents up to the workflow of committing an API breaking change, > >> > >> onto the person making the change to utils or onto the delegates they > >> > >> find at that time. This is predicated on the "one branch to rule them > >> > >> all" model though. > >> > >> > >> > >> The alternative (existing API endpoints are static but you can add > >> > >> new ones) decouples that need to update all dependents to whenever > >> > >> they want to integrate that new API and takes that burden off the > >> > >> person making the change to utils. In theory we'd get to have our > >> > >> cake and eat it too (i.e. frictionless iteration on an API endpoint > >> > >> flagged @BETA, users have stable APIs they can rely on with @STABLE), > >> > >> at the risk / cost of having a proliferation of @DEPRECATED APIs > >> > >> littered behind us. > >> > >> > >> > >> My intuition is that the latter is actually significantly less work > >> > >> for anyone that wants to modify utils vs. the former and the risk of > >> > >> that long tail of deprecated API proliferation isn't that high. > >> > >> > >> > >>> I’m against creating any API boundaries we need to maintain for any > >> > >>> external users > >> > >> 100% agree. I think we get this as a free side-effect of a model > >> > >> where we have STABLE flagged APIs and BETA, since it defers that > >> > >> integration cost to *any* consumer's timeline. i.e. someone could > >> > >> iterate on an API they need a change for in cassandra-analytics and > >> > >> core cassandra can keep trucking with a now @DEPRECATED endpoint > >> > >> until such time as it wants to integrate the new structure. > >> > >> > >> > >> One other point that's come up in conversation offline is around > >> > >> bug-fixing; being able to fix bugs in implementation w/out consumers > >> > >> having to also refactor to new API endpoints is just good hygiene for > >> > >> limiting blast radius of changes. > >> > >> > >> > >> > >> > >> On Tue, Aug 18, 2026, at 4:25 AM, Benedict Elliott Smith wrote: > >> > >>> I’m hard -1 on this the > >> > >>> > >> > >>> I’m very pro code sharing between Cassandra projects, but these do > >> > >>> not need any special handling - we just make sure the builds don’t > >> > >>> break. I’m against creating any API boundaries we need to maintain > >> > >>> for any external users > >> > >>> > >> > >>> On 2026/08/17 20:33:32 David Capwell wrote: > >> > >>>>> They're all internal, this is a convenience to improve code > >> > >>>>> sharing. > >> > >>>> > >> > >>>> Once they go into utils they are not “internal” (whatever that > >> > >>>> means). Why I started this effort in the first place is that the > >> > >>>> test utilities have been requested to be used in projects like > >> > >>>> Cassandra-ecosystem, but also non-cassandra projects. Both users > >> > >>>> need to know that a hot fix doesn’t break their build hence why I > >> > >>>> propose basic properties you would expect: major versions might > >> > >>>> have breaking changes, minor / patch won’t. For the classes anyone > >> > >>>> has talked about moving here, non of them should have issues with > >> > >>>> this; we are free to add new methods over time, but removing causes > >> > >>>> issues for consumers. > >> > >>>> > >> > >>>>> to improve code sharing. > >> > >>>> > >> > >>>> Even if you think about this only for cassandra ecosystem, if I > >> > >>>> depend on version 0.1.0 and we find a bug so get that fixed and now > >> > >>>> we depend on 0.1.10… I shouldn’t expect to deal with breaking > >> > >>>> changes. The mentality of “They’re all internal” as a > >> > >>>> justification to not document these assumptions causes me concern > >> > >>>> as breaking changes explicitly make it harder for parties to depend > >> > >>>> on these classes; breaking changes make is so much harder to “share > >> > >>>> code”. > >> > >>>> > >> > >>>>> We only care about versioning to ensure we don't break any builds > >> > >>>> > >> > >>>> What do you mean by this? Major versions I am ok with breaking > >> > >>>> changes; minor / patch is what I want to avoid. We can add new > >> > >>>> APIs without issue, the concern is only on removal. > >> > >>>> > >> > >>>>> and even decide when we upgrade the jar so can spot and fix any > >> > >>>>> breakages. > >> > >>>> > >> > >>>> If we are upgrading to enable a new JDK change, I wouldn’t expect > >> > >>>> users to have to rewrite all their tests, redo all their > >> > >>>> collections, etc…. You shouldn’t have to worry about upgrading the > >> > >>>> version cross minor / patch versions, as that should impose a no > >> > >>>> breaking change rule. > >> > >>>> > >> > >>>> > >> > >>>>> On Aug 14, 2026, at 3:06 PM, Benedict Elliott Smith > >> > >>>>> <[email protected]> wrote: > >> > >>>>> > >> > >>>>> Why are we defining this at all? They're all internal, this is a > >> > >>>>> convenience to improve code sharing. We only care about versioning > >> > >>>>> to ensure we don't break any builds, and we have all the builds, > >> > >>>>> and even decide when we upgrade the jar so can spot and fix any > >> > >>>>> breakages. > >> > >>>>> > >> > >>>>> Let's not overcomplicate things, or bind our future selves in red > >> > >>>>> tape and regret. > >> > >>>>> > >> > >>>>> On 2026/08/14 17:57:40 Josh McKenzie wrote: > >> > >>>>>> While I read your email I found myself wondering "To what are we > >> > >>>>>> referring to when we say 'API'"? ;) > >> > >>>>>> > >> > >>>>>> Are you talking about a public interface? Or are you talking > >> > >>>>>> about "any class that's public and any public method within a > >> > >>>>>> public class"? > >> > >>>>>> > >> > >>>>>> If the latter, my primary theoretical concern is that if we pull > >> > >>>>>> in code that has components that are scoped public for > >> > >>>>>> cross-package accessibility within-project, promoting those to > >> > >>>>>> "public by default" immediately calcifies their interface whether > >> > >>>>>> we intend for that to be consumed or not. Basically, we don't > >> > >>>>>> have an interim scope layer between "package private" and > >> > >>>>>> "public" that corresponds to "project public". In theory the post > >> > >>>>>> JDK9 modularity kind of provides that but then everyone just > >> > >>>>>> add-opens bulldozes across things (the joys of legacy code...). > >> > >>>>>> > >> > >>>>>> I think "Any interface that's public is a public API" is pretty > >> > >>>>>> obvious to maintainers and users and good. I'm also good with > >> > >>>>>> "anything public is an API unless otherwise documented" and we > >> > >>>>>> add a simple annotation like @INTERNAL > >> > >>>>>> <https://github.com/apiguardian-team/apiguardian/blob/main/src/main/java/org/apiguardian/api/API.java#L87> > >> > >>>>>> from API Guardian to basically say "yeah, this is public, but > >> > >>>>>> it's not intended for public consumption" (I think we should roll > >> > >>>>>> our own to match our proposed lifecycles but that's a clear > >> > >>>>>> example of the idea). > >> > >>>>>> > >> > >>>>>> I'm worried about the approach of "Any public method in a public > >> > >>>>>> class is considered public API and you can't change it". I'd > >> > >>>>>> prefer we start with a more constrained surface area we commit to > >> > >>>>>> as being an API and widen it later if we find there's a need; > >> > >>>>>> it's much harder to go in the other direction. > >> > >>>>>> > >> > >>>>>> On Fri, Aug 14, 2026, at 1:24 PM, David Capwell wrote: > >> > >>>>>>> Josh and I talked about this offline and not perfectly in-sync > >> > >>>>>>> so would be good to get other peoples views > >> > >>>>>>> > >> > >>>>>>> My take is that if you are adding the API to this shared repo we > >> > >>>>>>> need to care about backwards compatibility so things should be > >> > >>>>>>> PUBLIC by default (anything that is java public is part of the > >> > >>>>>>> public interface and breaking changes are not allowed without a > >> > >>>>>>> long enough deprecation window similar to Cassandra’s.). I think > >> > >>>>>>> Josh is in favor of using a annotation to mark that a API is > >> > >>>>>>> public, but without custom tooling I don’t think anyone will > >> > >>>>>>> notice and then we will get to a effectively public state and > >> > >>>>>>> breaking changes will be a nightmare to deal with for the > >> > >>>>>>> community. So if you want to post the API here, it should be > >> > >>>>>>> stable and we shouldn’t be putting APIs that have not been > >> > >>>>>>> fleshed out first. > >> > >>>>>>> > >> > >>>>>>>> On Aug 7, 2026, at 8:16 AM, Josh McKenzie > >> > >>>>>>>> <[email protected]> wrote: > >> > >>>>>>>> > >> > >>>>>>>> One thing worth immediately calling out that we might want to > >> > >>>>>>>> split out: we *could* do this work in Ant. > >> > >>>>>>>> > >> > >>>>>>>> It would be somewhat more imperative and brittle: we'd > >> > >>>>>>>> explicitly orchestrate the build ordering in Ant, while relying > >> > >>>>>>>> on the Gradle build inside Accord for its cassandra-utils > >> > >>>>>>>> dependency resolution / source substitution. That leaves us > >> > >>>>>>>> with a somewhat more complicated mixed Ant/Gradle build > >> > >>>>>>>> relationship but it's entirely workable for an interim time. > >> > >>>>>>>> > >> > >>>>>>>> So if the Gradle migration is a sticking point, we can break > >> > >>>>>>>> that out into a separate discussion and CEP rather than making > >> > >>>>>>>> it part of CEP-65. > >> > >>>>>>>> > >> > >>>>>>>> Doing so would mean retaining and extending some of the > >> > >>>>>>>> complexity in our existing build system that a future migration > >> > >>>>>>>> could remove, but it's not a crushing amount of additional > >> > >>>>>>>> complexity. The benefit of doing that work here with this CEP > >> > >>>>>>>> is that we have one more concrete build need providing a reason > >> > >>>>>>>> to move toward a unified build stack, and it fits the "clean > >> > >>>>>>>> things up and refactor as you're working on things that could > >> > >>>>>>>> benefit from that work" approach many have argued for in the > >> > >>>>>>>> past on the project. > >> > >>>>>>>> > >> > >>>>>>>> On Fri, Aug 7, 2026, at 10:58 AM, Josh McKenzie wrote: > >> > >>>>>>>>> As per the previous ML thread: [DISCUSS] Forking Cassandra > >> > >>>>>>>>> utilities into a separately released library > >> > >>>>>>>>> <https://lists.apache.org/thread/7kllp45vvonsg7ggzxpz39c5kdcy7r6g>, > >> > >>>>>>>>> David and I put together a draft of what we discussed and > >> > >>>>>>>>> worked through some implications and requirements that came up > >> > >>>>>>>>> as we tried to nail things down. > >> > >>>>>>>>> > >> > >>>>>>>>> The goal here is to provide a material backstop to continue > >> > >>>>>>>>> our discussion and version it. As with all CEP DISCUSS > >> > >>>>>>>>> threads, this is very fluid and none of it should be taken as > >> > >>>>>>>>> settled or an implicit mandate. Let's see if we can make some > >> > >>>>>>>>> progress on this long-standing pain point in our ecosystem. > >> > >>>>>>>>> > >> > >>>>>>>>> CEP-65 DRAFT: link > >> > >>>>>>>>> <https://cwiki.apache.org/confluence/spaces/CASSANDRA/pages/446071230/CEP-65+cassandra-utils+-+A+shared+utility+library+for+the+cassandra+ecosystem+DRAFT> > >> > >>>>>>>>> > >> > >>>>>>>>> *Why You Should Read This Draft:* > >> > >>>>>>>>> 1. Build system impact: we need a parent project and one of > >> > >>>>>>>>> its submodule to depend on another submodule. We're proposing > >> > >>>>>>>>> freezing ant's API surface area, maintaining that into > >> > >>>>>>>>> perpetuity, and moving to gradle going forward. > >> > >>>>>>>>> 2. Branching model: read the draft to see what "One Branch to > >> > >>>>>>>>> Rule Them All" means. > >> > >>>>>>>>> 3. API Lifecycle: Is @BETA/@STABLE/@DEPRECATED enough? Do we > >> > >>>>>>>>> need a @PRIVATE? > >> > >>>>>>>>> 4. To Release or Not To Release: we're proposing consumers > >> > >>>>>>>>> embed this as a submodule initially to minimize friction in > >> > >>>>>>>>> moving shared code into a shared space. > >> > >>>>>>>>> We have 1 outstanding unanswered question we didn't come up > >> > >>>>>>>>> with an opinionated proposal for: > >> > >>>>>>>>> > >> > >>>>>>>>> What should unannotated methods and classes in the library be > >> > >>>>>>>>> considered by potential consumers? @PRIVATE? @PUBLIC? Should > >> > >>>>>>>>> we lint and fail on any class without a top-level annotation > >> > >>>>>>>>> forcing us to make a choice on our dev list [DISCUSS] threads > >> > >>>>>>>>> whenever we bring in new things? > >> > >>>>>>>>> > >> > >>>>>>>>> There's no timeline on this thread; let's keep turning the > >> > >>>>>>>>> crank on this until we've hit our pareto-polish frontier. ;) > >> > >>>>>>>>> > >> > >>>>>>>>> ~Josh > >> > >>>>>>>>> > >> > >>>>>>>>> > >> > >>>>>>>> > >> > >>>>>> > >> > >>>> > >> > >>>> > >> > >>> > >> > >> > >> > >
