forked from confluentinc/parallel-consumer
-
Notifications
You must be signed in to change notification settings - Fork 8
Expand file tree
/
Copy pathupstream-map.yaml
More file actions
1331 lines (1272 loc) · 174 KB
/
Copy pathupstream-map.yaml
File metadata and controls
1331 lines (1272 loc) · 174 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
# Copyright (C) 2026 Antony Stubbs and contributors
# =============================================================================
# upstream-map.yaml -- fork <-> upstream tracking cache (SOURCE OF TRUTH)
# =============================================================================
#
# WHY THIS FILE EXISTS
# This repo is a long-lived hard fork (bz.stub.parallelconsumer) of the
# effectively-archived confluentinc/parallel-consumer. Upstream's open issues
# and PRs are a backlog worth mining, but the fork<->upstream mapping kept
# being re-derived by hand every session. This file caches that mapping ONCE,
# in machine-readable form, so it can be queried, diffed and staleness-checked
# instead of rediscovered.
#
# This file holds the FACTS (which fork branch/PR <-> which upstream issue/PR
# <-> status <-> work group). The editorial judgement (rankings, verdicts,
# recommended merge order) stays in `upstream-pr-analysis.adoc`; entries here
# link back to it via `adoc_anchor`.
#
# HOW TO KEEP IT FRESH
# Upstream is archived, so tracked PRs rarely change state -- but NEW issues,
# PRs and comments still arrive from users unaware a maintained fork exists.
# - `last_swept` = the date we last checked upstream for *new* activity.
# - Per-entry `upstream.last_checked` = when that entry's state was verified.
# Refresh with a read-only `gh` sweep (see scripts/upstream-sweep.sh).
# Design inspired by Debian DEP-3, Yocto `Upstream-Status:`, and OpenShift's
# `UPSTREAM:` fork convention.
#
# ENTRY SCHEMA
# id stable kebab-case key (never reuse/rename once referenced)
# group work group (rebalance-stability, metrics-observability,
# vertx, java-baseline-kafka4, features, deps-security,
# deps-major, deps-routine, build-tooling, logging-ux, release,
# governance)
# summary one line
# fork:
# branches local branch names carrying the work (may be [])
# prs fork PR numbers on `fork_repo` (astubbs/parallel-consumer)
# fork_issue single fork issue number, when the entry maps 1:1 to one
# fork_issues list of fork issue numbers, when one entry groups several
# upstream items that want designing together (mirrors of a
# cohort, an epic and its children). Same meaning as fork_issue,
# plural form -- prefer it over inventing one entry per mirror.
# status lifecycle of OUR work -- does NOT imply landed unless merged/released:
# none upstream item we track but haven't started
# in-progress actively being worked, not complete
# ready fix complete on a branch, no fork PR yet
# pr-open fix complete in an OPEN fork PR, awaiting merge
# merged landed on fork master
# released shipped in a published fork release
# superseded | wontfix
# upstream:
# repo usually the top-level `upstream_repo`
# issues upstream issue numbers this work primarily addresses
# prs upstream PR numbers this work primarily maps to / carries
# related other upstream issues/PRs that are linked but not primary
# status last-known upstream state (open | closed | merged | mixed)
# last_checked ISO date the above was verified
#
# =============================================================================
last_swept: 2026-08-06
upstream_repo: confluentinc/parallel-consumer
fork_repo: astubbs/parallel-consumer
# =============================================================================
# BRANCH ACCOUNTING
#
# WHY THIS SECTION EXISTS
# This is the record of what we decided about a branch, and it must OUTLIVE the
# branch. It also carries the tag pinning each preserved tip, absorbing two
# earlier records (see below). The failure it
# prevents is specific - a branch is reviewed, judged worthless and deleted,
# its only trace was itself, and the next audit re-finds the absence, cannot
# tell a deliberate deletion from an accident, and redoes the work.
#
# So a deleted branch KEEPS its entry, with its tip, its date and its reason.
# `state: deleted` is the case this section exists for.
#
# WHAT NOT TO PUT HERE
# Nothing a command answers. Open PRs are `gh pr list`; merged-ness is
# `git branch --merged`. Record the judgement, not the state.
#
# FIELDS
# ref branch name as it exists on `fork_repo` (or `<remote>:<name>` if not ours)
# tip short SHA at the time of the decision
# state mirrored | ours | archived | deleted
# deleted ISO date, required when state is `deleted`; the `note` carries the why
# tag the annotated tag pinning that SHA, when one exists
# pr the upstream PR this tip is the head of, when it is one
# see where the reasoning lives - an inflight note, astubbs#NN, confluentinc#NN
# note one line, only when it says something the fields do not
#
# THIS IS THE ONLY BRANCH RECORD, deliberately. Two others existed and recorded
# the SAME COMMITS under different framings: `preserved_branch_tips` (branch tips
# pinned as tags) and `sweep-2023-admin-closure.preserved_heads` (swept PR heads
# pinned as tags). Every one of those PR heads is the tip of an upstream branch -
# confluentinc#443 and the `pyallel-consumer` tip were two names for one SHA - so
# they are folded in here as the `tag` and `pr` fields. Do not re-split them: a
# corrected SHA fixed in one copy while another still reads as authoritative is
# the drift this consolidation removes.
#
# Tags are kept alongside the mirrored branches rather than replaced by them. A
# branch can be deleted or force-moved; an annotated tag is the record that a
# specific commit was deliberately preserved. Verify without fetching:
# git ls-remote --tags origin 'archive/*'
#
# ENFORCED by `bin/check-upstream-map.sh` (via `scripts/upstream-map.py validate`): ref present and
# unique, state in the closed set, a `deleted` entry carries an ISO date, and `tip` is a STRING - an
# all-digit SHA otherwise parses as an integer and never compares equal to `git rev-parse` output.
# The tip is required only for `deleted` and `archived`, because for a live branch it is one command
# away and this section records nothing a command answers.
#
# A fork receives branches ONCE, at creation, and never again. This one dates
# from 2020-11-11, so nothing upstream created afterwards ever arrived. That is
# why the `upstream/*` mirror below exists rather than being redundant.
# =============================================================================
branch_accounting_checked: 2026-08-20
branch_accounting:
# --- upstream branches mirrored onto this fork 2026-08-20, tips verified ----
# Namespaced deliberately: eight share a name with one of ours carrying divergent
# work (master, 0.5.3.x, features/dynamic-concurrency-control, features/retry-exception,
# improvements/commit-command-actor, improvements/lambda-actor-bus,
# improvements/rebalance-messages, improvements/remove-static), so pushing under
# their own names would have overwritten our history. Re-derive rather than trusting
# the list: compare `git ls-remote --heads origin` against `--heads upstream` by name
# and tip.
- {ref: upstream/pyallel-consumer, tip: 4533f6d8d, state: mirrored, tag: archive/upstream-pr-443, pr: confluentinc#443, see: [confluentinc#443, confluentinc#539, astubbs#293, "docs/inflight/process-fork-branch-archaeology.md"],
note: "Prior Python client. The strongest prior art for the proxy work in astubbs#242, and unread. Its PR head is also pinned at archive/upstream-pr-443."}
- {ref: upstream/python-cd-pipeline, tip: c3796a2fd, state: mirrored, tag: archive/upstream-branch/python-cd-pipeline, see: [confluentinc#539],
note: "Publishing pipeline for the Python client above. Named in no document before this entry."}
- {ref: upstream/master, tip: 9b582c246, state: mirrored, tag: archive/upstream-branch/master, see: ["docs/inflight/process-fork-branch-archaeology.md"],
note: "Upstream master. Two commits we do not carry, both README notices - the maintenance notice and the link to this fork - so the divergence is benign."}
- {ref: upstream/features/dynamic-concurrency-control, tip: ba6b71f10, state: mirrored, tag: archive/upstream-pr-22, pr: confluentinc#22, see: [astubbs#227],
note: "The one upstream branch that predates our fork and is absent by name here only because OUR branch of the same name diverged under our own work. Not a deletion."}
- {ref: upstream/features/batching, tip: 7e2607560, state: mirrored, tag: archive/upstream-branch/features/batching, see: ["docs/inflight/branch-audit-orphans.md"],
note: "Batching shipped upstream separately; the tip may predate what landed."}
- {ref: upstream/PL-176/DontDrainIssue, tip: 4869ccf65, state: mirrored, tag: archive/upstream-branch/PL-176/DontDrainIssue, see: ["docs/inflight/branch-audit-orphans.md"],
note: "Name suggests real drain-behaviour work; unread."}
- {ref: upstream/docs/back-pressure, tip: 50cd1cf01, state: mirrored, tag: archive/upstream-branch/docs/back-pressure, see: [confluentinc#508],
note: "Back-pressure notes. confluentinc#508 was closed inside a dependabot batch on a CLA technicality, never judged on merits."}
- {ref: upstream/0.5.3.x, tip: c097a3745, state: mirrored, tag: archive/upstream-branch/0.5.3.x}
- {ref: upstream/v0.5.2.x-dev, tip: 5f5de9154, state: mirrored, tag: archive/upstream-branch/v0.5.2.x-dev}
- {ref: upstream/v0.6.x, tip: 58159a0b9, state: mirrored, tag: archive/upstream-branch/v0.6.x}
- {ref: upstream/v0.6.x-dev, tip: 60fd76d50, state: mirrored}
- {ref: upstream/improvements/vertx-vertical, tip: 02ab32894, state: mirrored, tag: archive/upstream-pr-204, pr: confluentinc#204}
- {ref: upstream/improvements/rebalance-messages, tip: 007ae0906, state: mirrored, tag: archive/upstream-pr-270, pr: confluentinc#270}
- {ref: upstream/improvements/remove-static, tip: 77a021ee1, state: mirrored, tag: archive/upstream-pr-405, pr: confluentinc#405}
- {ref: upstream/improvements/commit-command-actor, tip: 7e117a5ca, state: mirrored}
- {ref: upstream/improvements/lambda-actor-bus, tip: 96114737a, state: mirrored}
- {ref: upstream/improvements/package-restructure, tip: d86a87ef0, state: mirrored}
- {ref: upstream/improvements/transaction-docs, tip: b2be8dac7, state: mirrored}
- {ref: upstream/refactor/actor-base-fixes, tip: 09a13d070, state: mirrored}
- {ref: upstream/refactor/interface, tip: 400643c87, state: mirrored}
- {ref: upstream/features/retry-exception, tip: 1b087e554, state: mirrored}
- {ref: upstream/fix-charts, tip: 33d93af09, state: mirrored, tag: archive/upstream-pr-506, pr: confluentinc#506}
- {ref: upstream/DP-12547, tip: 87cdcf48c, state: mirrored, tag: archive/upstream-branch/DP-12547}
- {ref: upstream/correct-failing-license-check, tip: e8c6ff5fa, state: mirrored, tag: archive/upstream-branch/correct-failing-license-check}
- {ref: upstream/chore-service-bot-update, tip: "255916684", state: mirrored}
# --- deleted, deliberately, with the reasoning that made it safe --------------
# Each kept its own entry rather than one aggregate row: this section's contract is that a
# deleted branch keeps its TIP, and a glob in `ref` also defeats the ref-matching check the
# section exists to feed. Shared reasoning, stated once: mirrored 2026-08-20 and removed the
# same day once contents were checked - each was a single commit touching only pom.xml,
# bumping a dependency of UPSTREAM's tree, which has diverged from ours in both dependency set
# and package paths, so they would not apply here and will never merge upstream either. Not
# tagged, so upstream's copy is the last one; accepted, because a recreatable version bump is
# not work. The tips below make them addressable from upstream while it exists.
- {ref: upstream/dependabot/maven/junit.platform.version-6.0.0, tip: 9a25939d7, state: deleted, deleted: 2026-08-20, see: ["docs/inflight/process-fork-branch-archaeology.md"]}
- {ref: upstream/dependabot/maven/org.apache.maven.plugins-maven-gpg-plugin-3.2.8, tip: d38e3cc67, state: deleted, deleted: 2026-08-20, see: ["docs/inflight/process-fork-branch-archaeology.md"]}
- {ref: upstream/dependabot/maven/testcontainers.version-1.21.3, tip: 52540d9a1, state: deleted, deleted: 2026-08-20, see: ["docs/inflight/process-fork-branch-archaeology.md"]}
- {ref: upstream/dependabot/maven/vertx.version-5.0.5, tip: c1320b1f2, state: deleted, deleted: 2026-08-20, see: ["docs/inflight/process-fork-branch-archaeology.md"]}
- {ref: upstream/renovate/master-com.github.tomakehurst-wiremock-jre8-3.x, tip: 99e35fb7c, state: deleted, deleted: 2026-08-20, see: ["docs/inflight/process-fork-branch-archaeology.md"]}
- {ref: upstream/renovate/master-com.github.tomakehurst-wiremock-jre8-replacement, tip: f87d9e55a, state: deleted, deleted: 2026-08-20, see: ["docs/inflight/process-fork-branch-archaeology.md"]}
- {ref: upstream/renovate/master-io.smallrye.reactive-mutiny-3.x, tip: 2fa2a10c4, state: deleted, deleted: 2026-08-20, see: ["docs/inflight/process-fork-branch-archaeology.md"]}
- {ref: upstream/renovate/master-kafka.version, tip: 76a6a695f, state: deleted, deleted: 2026-08-20, see: ["docs/inflight/process-fork-branch-archaeology.md"]}
- {ref: upstream/renovate/master-logback.version, tip: cf4c4b59c, state: deleted, deleted: 2026-08-20, see: ["docs/inflight/process-fork-branch-archaeology.md"]}
- {ref: upstream/renovate/master-major-kafka, tip: 6d1fceb6e, state: deleted, deleted: 2026-08-20, see: ["docs/inflight/process-fork-branch-archaeology.md"]}
- {ref: upstream/renovate/master-major-testing-libraries, tip: 52d774b05, state: deleted, deleted: 2026-08-20, see: ["docs/inflight/process-fork-branch-archaeology.md"]}
- {ref: upstream/renovate/master-major-vertx.version, tip: 3f5a215a4, state: deleted, deleted: 2026-08-20, see: ["docs/inflight/process-fork-branch-archaeology.md"]}
- {ref: upstream/renovate/master-maven-org.assertj-assertj-core-vulnerability, tip: 78da8a5e7, state: deleted, deleted: 2026-08-20, see: ["docs/inflight/process-fork-branch-archaeology.md"]}
- {ref: upstream/renovate/master-maven-org.postgresql-postgresql-vulnerability, tip: ac48acadd, state: deleted, deleted: 2026-08-20, see: ["docs/inflight/process-fork-branch-archaeology.md"]}
- {ref: upstream/renovate/master-micrometer-core.version, tip: c37794713, state: deleted, deleted: 2026-08-20, see: ["docs/inflight/process-fork-branch-archaeology.md"]}
- {ref: upstream/renovate/master-minor+patch-dependencies, tip: 35608cae9, state: deleted, deleted: 2026-08-20, see: ["docs/inflight/process-fork-branch-archaeology.md"]}
- {ref: upstream/dependabot/maven/org.threeten-threeten-extra-1.8.0, tip: 5bbfea783, state: deleted, deleted: 2026-08-20,
see: ["docs/inflight/process-fork-branch-archaeology.md"],
note: "Recorded separately because it was NOT a bot branch despite the name. A maintainer pushed four commits onto it - semaphore CI java-home fix, missing licence headers, gitignore, and a master merge - on top of the threeten-extra bump. Read before deleting: the CI config is upstream's semaphore, which we do not use, and the licence headers are on io/confluent paths this fork renamed, so none of it applies here. Kept as its own entry because a prefix sweep would have taken human commits silently, which is the failure this whole section exists to prevent."}
# --- our own branches, where a decision exists that the branch does not -----
- {ref: presentation, tip: ffda9c6a3, state: deleted, deleted: 2026-08-26, tag: archive/presentation, see: ["docs/inflight/handoff-fork-branch-audit.md", "docs/inflight/process-fork-branch-archaeology.md"],
note: "Carried Demo.java, the code behind the asciinema cast embedded in the README. Unmerged since 2021 and named in no ledger - the branch that triggered the whole audit. Archived and deleted 2026-08-26. Not merged, because the code is demo-grade and its own commits say so - one records an unfixed data race under load. Not dropped either, because the README still embeds the cast it produced, so the source behind a published artefact stays recoverable: git show archive/presentation."}
- {ref: refactor/deprecate-jstream, tip: 8a8f6508d, state: deleted, deleted: 2026-09-03, tag: archive/refactor/deprecate-jstream, see: [astubbs#116, astubbs#122, "docs/refactoring.md"],
note: "Two WIP commits from 2022 deprecating the JStream API - 3880b55e0 'there's no use for it really?' and 7d8dfe457 'not a very good interface'. Never merged. It carried a one-line description and its tip in docs/refactoring.md's branch inventory, but had no branch_accounting record until this entry - and this file is the source of truth, so a future audit finding the branch gone had nothing here to tell a deliberate deletion from an accident. Archived and deleted 2026-09-03 once astubbs#116 settled the question the branch was holding open: that PR fixed the result-stream defect the 2026 restatement of the deprecation argued FROM, and the owner withdrew the queued removal rather than deprecate an API that now works. Not kept as a live branch, because nothing was going to be merged from it. Not dropped either, because its javadoc is the only surviving statement of the DESIGN argument - poorly shaped interface, distinct from the defect - which astubbs#116 did not refute and nobody has re-made: git show archive/refactor/deprecate-jstream."}
# --- pre-fork branches, read and classified 2026-09-03 --------------------
# Every branch below predates the 2026-03-24 fork point, still exists on origin, and had NO record
# here. Four agents read each one's COMMITS and diff - never its name, which this directory's rules
# forbid guessing from, and which would have filed `improvements/privacy-restriction` (a
# shared-nothing spike) under privacy.
#
# `class` answers the question that prompted the sweep: has the idea already landed?
# absorbed - shipped, by this branch or another route; the note names what supersedes it
# superseded - the problem no longer exists, or is solved differently
# open-idea - real, unabsorbed work someone might still want. THE ONES THAT MATTER.
# spent - scaffolding of its era, no lasting value
# Nothing is `unclear`: every branch was resolved.
#
# Re-derive rather than trusting the tally, which is stale the moment anyone acts on it:
# grep -c 'class: open-idea' src/docs/development/upstream-map.yaml
#
# THIS IS NOT A WORKLIST. A branch being `open-idea` says the code never landed, not that it
# should. Several are breaking changes belonging in docs/refactoring.md's release-gated queue,
# several are stacked on an unfinished actor base, and a few are worth less than the cost of
# reviving them. Read the note before reviving anything.
# -------------------------------------------------------------------------
- {ref: refactor/interface, tip: 400643c87, state: ours, class: open-idea, note: "Single `WIP! Playing around with some interface naming` commit. Adds a marker interface `Handler<T> extends Consumer<T>` and renames the user-function entrypoint `poll(Consumer<...>)` to `register(Handler<...>)` across core, vertx and the examples. No tests, no decision recorded. VERDICT: Not absorbed. `origin/master:.../ParallelStreamProcessor.java` still declares `void poll(Consumer<PollContext<K, V>> usersVoidConsumptionFunction)` alongside the `pollAndProduce*` family, and there is no `Handler` type in `parallel-consumer-core/src/main/java`. The complaint behind it is still live - `poll` names a registration, not a poll - but it is a breaking public rename, so it belongs in the release-gated breaking-change queue in `docs/refactoring.md` rather than as a branch. Low value relative to cost."}
- {ref: bugs/turn-on-commit-tests, tip: 009bb7122, state: ours, class: absorbed, note: "One `WIP!` commit deleting two `@Disabled` annotations, on `offsetsAreNeverCommittedForMessagesStillInFlightLong` and `processInKeyOrder`, which the commit says were \"dibbled when the offset map feature was added\". VERDICT: Absorbed. Both tests are live on master: `ParallelEoSStreamProcessorTest.java` has `offsetsAreNeverCommittedForMessagesStillInFlightLong(CommitMode)` and `processInKeyOrder(CommitMode)` as plain `@ParameterizedTest @EnumSource(CommitMode.class)` with no `@Disabled` above either. Nothing left to do."}
- {ref: features/dynamic-concurrency-control, tip: 6f85eac41, state: ours, class: open-idea, note: "LINKED to astubbs/parallel-consumer#333 (auto scaling / adaptive concurrency), which ALREADY KNEW: its core-auto-scaling.md cites this branch by SHA under Prior art (design references, bitrotted) and summarises it - Netflix concurrency-limits Gradient2Limit as the worker pool, auto-scale module extraction started, README section written. The idea was not lost; it was catalogued in docs/refactoring.md idea bank and found from there. What was missing was a record HERE, which is why the branch still had to be rediscovered by reading commits. `WIP! feature: Dynamic concurrency controls using Netflix's concurrency-limits project` - sizes the worker thread pool at runtime by measuring execution performance, using TCP-congestion-control theory. Its body says the original plan was to hand-roll it from control theory before finding the library. Follow-up commits extract it to a separate module so core keeps zero deps, and document auto-scaling in the README. VERDICT: NOT absorbed. No `parallel-consumer-core-auto-scale` module on master (modules are core, examples, mutiny, reactor, vertx), no `AutoScalingProcessor`, and no `concurrency-limits`/Netflix dependency in any pom. What master has instead is `internal/DynamicLoadFactor`, which tunes the *queue loading factor*, not the pool size - and `maxConcurrency` remains a fixed user-set number (`ParallelConsumerOptions.maxConcurrency = DEFAULT_MAX_CONCURRENCY`). To finish it: re-target the extracted-module design at today's `AbstractParallelEoSStreamProcessor.setupWorkerPool`/`workerThreadPool` supplier, and decide whether the Netflix dep is acceptable in an optional module."}
- {ref: 0.2.0.x, tip: 573a3907e, state: ours, class: spent, note: "Release-maintenance branch for the 0.2.0.x line; its tip `[maven-release-plugin] prepare for next development iteration` is itself the merge-base with master, i.e. fully contained in master. VERDICT: Zero commits ahead of master - `git merge-base origin/master origin/0.2.0.x` returns the branch tip itself. Nothing unique on it. Safe to delete."}
- {ref: commit-timeout-supervise, tip: 9a46780ca, state: ours, class: absorbed, note: "`WIP! Supervise commit process` - body: \"Add timeout to commit wait - if it hits, supervise poller to make sure it hasn't crashed.\" Wraps `committer.commit()` in a retry loop that catches `TimeoutException` and calls `supervise()`. VERDICT: Absorbed, and considerably further developed. Master's `internal/ConsumerOffsetCommitter` carries a `commitTimeout` field fed from `options.getOffsetCommitTimeout()`, a `commit() throws TimeoutException` that polls `commitResponseQueue` with that timeout, and a long diagnostic block naming \"AbstractParallelEoSStreamProcessor's supervise() backstop\" plus `PollThreadStallDiagnosis`. The exact WIP idea - timeout, then supervise the poller - is what shipped."}
- {ref: feature/progress-monitoring, tip: 4843286a2, state: ours, class: absorbed, note: "`WIP! Progress monitoring POC` adds a `processingLimbo` map to WorkManager and, when a work scan returns nothing while limbo is non-empty, finds the longest-waiting `WorkContainer` and WARNs if it has waited more than 3x the retry delay. Plus `Reduce default retry delay` and `Supervise control thread` (calls `supervise()` from the control loop). VERDICT: Absorbed in both halves. Control-thread supervision is on master - `AbstractParallelEoSStreamProcessor` calls `brokerPollSubsystem.supervise()` from the control loop and has an explicit javadoc about the supervise backstop. Progress monitoring became the micrometer subsystem: `metrics/PCMetricsDef` defines `SLOW_RECORDS` (\"Total number of records that spent more than the configured time threshold in the waiting queue... defaults to 10 seconds\") alongside `INFLIGHT_RECORDS`, `WAITING_RECORDS`, `FAILED_RECORDS`. The one nuance not absorbed is stuck/leaked-work detection, which master still carries as a comment in `state/ShardManager` (\"work is 'missing'/stuck (candidate leak)\")."}
- {ref: bug/back-pressure-fix, tip: 551acae28, state: ours, class: absorbed, note: "`Fix back-pressure system` plus four small follow-ups (`test`, `Tests`, `impl`, `More`) - reworks WorkManager's queue-pressure accounting and adds `BackPressureTests`. This is the root of the whole 2020 self-tuning lineage. VERDICT: Absorbed. The lineage's product is on master: `internal/DynamicLoadFactor` (with its `isNotCoolingDown()`/`isWarmUpPeriodOver()` stepping), `ParallelConsumerOptions.getTargetAmountOfRecordsInFlight()`, and `checkPipelinePressure` in the processor. The branch's own test class name did not survive, but `offsets/OffsetEncodingBackPressureTest` and `OffsetEncodingBackPressureUnitTest` cover the same ground on master."}
- {ref: feature/auto-tuning-pressure, tip: f4aa09788, state: ours, class: absorbed, note: "`Wip! Experiments in self tuning` - one commit on top of bug/back-pressure-fix adding a `BackoffAnalyser` class to decide when to step the pressure system. VERDICT: Absorbed in substance, not in shape. There is no `BackoffAnalyser` on master, but its job - deciding when to step the loading factor up, with cooldown and warm-up guards - is exactly what `internal/DynamicLoadFactor` does. Note master's `DynamicLoadFactor` still carries the class-level `// todo make so can be fractional like 50%`, which is the one part of the self-tuning ambition never finished (see external-engine-higher-pressure below, where that was tried and rejected for external engines)."}
- {ref: direct-ringbuffer, tip: c247d89c5, state: ours, class: superseded, note: "`WIP! Direct ring buffer approach for work publishing - avoid intermediate buffer which must be managed` - body: \"A new Thread blocks putting work into the buffer, which feeds directly into the ExecutorService.\" Then `Nearly works - is faaaaaast`, `Performance breakthrough - pressure system all the way back to the consumer`, `Return process work finish directly from worker threads`, and a first batch draft. The committed `RingBufferManager` is visibly experimental (commented-out fields and calls, a `Semaphore(numberOfThreads * 2)`). VERDICT: Superseded. Master kept the intermediate-buffer design the branch set out to remove: `AbstractParallelEoSStreamProcessor` has `private final BlockingQueue<ControllerEventMessage<K, V>> workMailBox = new LinkedBlockingQueue<>()`, and the pressure story landed as `DynamicLoadFactor` + `checkPipelinePressure` rather than as a ring buffer. `DynamicLoadFactor` and `RateLimiter` (as a log-rate limiter) did land; `RingBufferManager`, `ExponentialMovingAverage` and `WindowedEventRate` are absent from master. The concurrency shape the branch was groping toward has since been re-decided several times (mailbox, `ThreadConfinedConsumer`, `ExternalEngine.dispatchCeiling`), so this is history rather than a resumable branch."}
- {ref: ringbuffer-batch, tip: ee9428303, state: ours, class: absorbed, note: "Sibling of direct-ringbuffer off the same `64e35628a Batch draft (code still single mode) WORKS`. Takes the batch half further; the author's own commit subject records it failing - `Batch implementation, but seems to be a problem`. VERDICT: The batching idea is absorbed, by a much later and independent route: master's `ParallelConsumerOptions.batchSize` (default 1) plus `getTargetAmountOfRecordsInFlight()` = maxConcurrency x batchSize, `state/RecordPopulation`, and the `*BatchTest` families. The ring-buffer scaffolding underneath is superseded exactly as for direct-ringbuffer. Nothing here is worth reviving."}
- {ref: encoders-truncate-themselves, tip: 8d3903b9a, state: ours, class: superseded, note: "Superset of move-cons-to-pc. `WIP! Encode offsets continuously to assess required space` -> `Draft algo complete` -> `Big change - stop using old find scan and use continuous instead` -> `Encoders truncate and reinitialise themselves`. The idea: keep the offset encoders running continuously as work completes so the required metadata payload size is always known, instead of scanning and encoding from scratch at commit time; encoders truncate and reinitialise themselves when the base offset moves. VERDICT: Not absorbed, and the problem is now solved differently. Master's `offsets/OffsetSimultaneousEncoder` is still constructed per-commit as `new OffsetSimultaneousEncoder(baseOffsetForPartition, highestSucceeded, incompleteOffsets)` inside `OffsetMapCodecManager` - the from-scratch model - and contains no `truncate`/`reinitialise`/`continuous` machinery, and there is no `ContinuousEncodingTests` on master. The pressure signal the continuous encoding was meant to feed arrived instead as the reactive `PartitionState.allowedMoreRecords` / `USED_PAYLOAD_THRESHOLD_MULTIPLIER_DEFAULT` path. Reviving this would be a large rewrite of the encoder layer for a performance win nobody has measured since 2020."}
- {ref: move-cons-to-pc, tip: f25256cf3, state: ours, class: superseded, note: "The same lineage one step earlier (its tip is an ancestor of encoders-truncate-themselves). Two named ideas: `Move consumer back to PC wrapped for thread safety, so commits are in line with control`, and `More - add work container epoch - ignore old fenced off work when partition assignment changes`. VERDICT: Split verdict, both settled. The epoch idea IS absorbed and is now load-bearing: master has `internal/EpochAndRecordsMap` and `state/PartitionState.epochIsStale(...)` with a long javadoc warning not to \"fix\" it per-record. The consumer-thread-safety idea was settled the OPPOSITE way: master does not move the consumer to the control thread but confines it to the poll thread, via `internal/ThreadConfinedConsumer` (\"Delegating wrapper around Consumer that enforces thread confinement at runtime... the poll thread calls claimOwnership()\") plus `ConsumerManager` and `ConsumerOwnership`. So the branch's question is answered, just not its way."}
- {ref: massive-refactor, tip: f96e0bc44, state: ours, class: absorbed, note: "`Big refactor` on top of `Wip! Extract parathion [sic] state and shard management` - breaks the ~1000-line god-class WorkManager into partition-state, shard-management, mailbox and offset-encoding collaborators. VERDICT: Absorbed - this is literally master's package layout. `parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/state/` now holds `PartitionState`, `PartitionStateManager` (the branch's `PartitionMonitor`), `ProcessingShard`, `ShardManager` (its `ShardManagement`), `ShardKey`, `RetryQueue` and a much smaller `WorkManager`; the mailbox extraction landed as `internal/EpochAndRecordsMap` + the `workMailBox` queue, and offset encoding as the whole `offsets/` package. Nothing unique remains."}
- {ref: partition-state, tip: a5be48854, state: ours, class: absorbed, note: "Sibling of massive-refactor off the same `6553e87ff Wip! Extract parathion state and shard management`; tip commit is `Hardwork`, moving partition bookkeeping out of WorkManager into PartitionMonitor/PartitionState. Stops short of the four-way split massive-refactor did. VERDICT: Absorbed, same evidence as massive-refactor: `state/PartitionState.java` and `state/PartitionStateManager.java` exist on master and own exactly this responsibility. Strictly redundant with massive-refactor, which went further."}
- {ref: predictive-offset-payloads, tip: fa4a79bd2, state: ours, class: absorbed, note: "Two layers. The reactive layer: `Offset payload size restriction is not shared across partitions, it is per partition`, `WIP! Initial partition back pressure from encoder space required`, `Partition back pressure tested ok`. The predictive layer on top: `OffsetPayloadPerformanceHistory` and `Approximate num in flight for partition with offset range` - estimate the payload space a partition will need before encoding, rather than reacting after. VERDICT: The reactive layer is absorbed and is the load-bearing mechanism on master: `state/PartitionState` has `allowedMoreRecords`, `updateBlockFromEncodingResult(offsetMapPayload)` blocking when `metaPayloadLength > DefaultMaxMetadataSize`, and `PartitionStateManager.USED_PAYLOAD_THRESHOLD_MULTIPLIER_DEFAULT`; the branch's `OffsetEncodingBackPressureTest` is on master by name, as is `ProgressTracker`. The *predictive* layer is not - there is no `OffsetPayloadPerformanceHistory` anywhere in master. Classed absorbed because the payoff (never blowing the 4096-byte metadata limit) is achieved; the predictive refinement is a performance idea, not a missing capability."}
- {ref: features/configure-retry, tip: 917e4698a, state: ours, class: absorbed, note: "Two workstreams. `START WIP! feature #18: Batching initial` with a `BatchTest`, and `START WIP feature: #34 retry` - which is docs-only at the tip, describing that a user-function throw is always retriable, that there is no terminal-error support, and linking confluentinc#65 (enhanced retry epic), #48 (scheduled retry) and #34 (monitor for progress / shutdown / skip / DLQ). VERDICT: Absorbed, with one named gap that master already tracks itself. Batching landed as `ParallelConsumerOptions.batchSize`; retry configurability landed as `defaultMessageRetryDelay` + `retryDelayProvider` (confluentinc#82, from the same epic) plus `state/RetryQueue`. The branch's docs paragraph is on master's README verbatim - line 908 still reads \"At the moment there is no terminal error support, so messages will continue to be retried forever\", with the same issue list plus confluentinc#196 (max retries + DLQ callback). So the DLQ/max-retries half is genuinely still open, but it is open *on master* as a documented gap, not as anything this branch holds."}
- {ref: custom-thread-pool, tip: 8e7f56c96, state: ours, class: open-idea, note: "`Addresses: Allow customization of the ThreadPoolExecutor #78` - adds a `Supplier<ThreadPoolExecutor> threadPoolFactory` builder option; when set, the processor uses it instead of the hardwired `new ThreadPoolExecutor(maxConcurrency, maxConcurrency, 0L, MILLISECONDS, new LinkedBlockingQueue<>())`. Javadoc warns the caller to match `maxConcurrency` and use a `LinkedBlockingQueue`. VERDICT: Not absorbed as a public option. Master builds the pool in `AbstractParallelEoSStreamProcessor.setupWorkerPool(int poolSize)`, which is `protected` (so subclassing is the only extension point - and `ExternalEngine` uses it), memoized behind `workerThreadPool`, and now hard-gated by `requireRejectionIsVisible(...)` which throws unless the handler is `ThreadPoolExecutor.AbortPolicy`. `ParallelConsumerOptions` has `managedThreadFactory`/`managedExecutorService` JNDI names but no pool supplier. To finish: add the `Supplier` option routed through `setupWorkerPool`, and decide how it interacts with the AbortPolicy invariant - a user-supplied pool with a different rejection handler is precisely what that check exists to refuse, so this is a real design question, not a one-line add. Confluentinc#78 is presumably still open upstream."}
- {ref: parallel-join-technique, tip: 1317fe7b6, state: ours, class: open-idea, note: "`Parallel joins technique documentation` - a README section plus a small runnable Kafka Streams example (`ParallelJoin` with `UserEvent`/`UserId`/`UserProfile`) showing how to do a slow enrichment join in parallel with PC alongside a KStreams topology, rather than serially inside the topology. VERDICT: Not absorbed. `grep -in join origin/master:README.adoc` returns only one hit, about cooperative rebalancing - the technique section is absent - and none of `ParallelJoin`, `UserEvent`, `UserId`, `UserProfile` exist under `parallel-consumer-examples/` on master (which has core, metrics, reactor, streams, vertx). This is pure docs+example work with no engine risk, and it is the kind of \"why would I use this\" material `STRATEGY.md` cares about. Cheap to land: port the three tiny model classes and the README section into `parallel-consumer-example-streams`, updating for the `PollContext` API."}
- {ref: demo, tip: 92a44fbec, state: ours, class: absorbed, note: "`START: add asciinema link` plus `svg` - embeds `https://asciinema.org/a/404299` as a clickable SVG near the top of the README. VERDICT: Absorbed. Master's README lines 172-173 carry the same recording - \".Click on the animated SVG image to open the https://asciinema.org/a/404299[Asciinema.org player]\" with the SVG hosted on an astubbs gist. Landed by another route, and improved (self-hosted SVG rather than asciinema's)."}
- {ref: client-factory, tip: 9636c33da, state: ours, class: open-idea, note: "LINKED to astubbs/parallel-consumer#420, which builds the producer through a factory PC enforces - the same shape this branch proposed for the CONSUMER. #420 reaches it only through docs/refactoring.md; the two halves of PC-owns-the-client-it-uses are worth reading together. `WIP-START: Prevent client reuse by using factories` - body: \"A consumer instance can't be shared by PC and anything else. This is an easier way to make sure users don't share clients.\" Replaces the `consumer`/`producer` instance options with `Supplier<Consumer<K,V>> consumerSupplier` / `Supplier<Producer<K,V>> producerSupplier` plus `consumerConfig`/`producerConfig` `Properties`, and extracts all the construction-time checks out of the processor into a testable `ConfigurationValidator`. A later commit adds a group-id presence check \"fixes coordinator NPE on reflection checks for auto commit\". VERDICT: Mostly not absorbed - two of three parts are open. (a) Factories: master's `ParallelConsumerOptions` still declares `private final Consumer<K, V> consumer` and `private final Producer<K, V> producer` - instances only, no supplier, no Properties. (b) Extracted validator: there is no `ConfigurationValidator` on master; validation still lives in the options' own `validate()` and in the processor's constructor. (c) The group-id NPE fix DID land, differently: `AbstractParallelEoSStreamProcessor` has `requireNonNull(coordinator, \"Consumer coordinator must not be null. Ensure that group.id is configured for this consumer.\")`, and `ConsumerManager` carries a comment explicitly demarcating what its catch is and is not for. The factory idea is the valuable half and has grown *more* relevant since: master now enforces poll-thread confinement via `ThreadConfinedConsumer`/`ConsumerOwnership`, so \"PC owns the client, you don't get to share it\" is already the de-facto contract - handing PC a factory instead of an instance would make it structural rather than checked. That is a breaking options change, so it wants the same major as the other queued breaks in `docs/refactoring.md`."}
- {ref: ci-tests, tip: 4ae41364b, state: ours, class: absorbed, note: "`tests: Turn off parallel tests in CI profile` - adds `<parallel-tests>false</parallel-tests>` to the `ci` profile's properties. VERDICT: Absorbed exactly. Master's root `pom.xml` `ci` profile contains `<parallel-tests>false</parallel-tests>` (with `<parallel-tests>true</parallel-tests>` as the default property), alongside `<surefire.forkCount>1C</surefire.forkCount>` and a comment explaining that CI parallelises by forking JVMs rather than JUnit threads \"so it does not resurrect the thread-parallel flakes\" - the same conclusion, better documented."}
- {ref: editor-config, tip: 6a1f83e5e, state: ours, class: absorbed, note: "`START: add editor config file` - adds a 10-line `.editorconfig`. VERDICT: Absorbed. `.editorconfig` exists on master (`git ls-tree origin/master .editorconfig` -> blob 7dda17caa) and AGENTS.md's Code Style section names it as enforced (4-space Java indent, 120-char lines). Landed by another route."}
- {ref: slf4j-no-logger, tip: 9c9396b8a, state: ours, class: open-idea, note: "`ux: Adds a warning when no SLF4J loger detected` - a `GeneralUtils` helper that detects the SLF4J NOP/no-op binding and warns at PC startup, so a user whose logging is unconfigured is told why they see nothing from the library. VERDICT: Not absorbed. There is no `GeneralUtils` anywhere on master, and grepping `parallel-consumer-core/src/main/java` for SLF4J turns up only `@Slf4j` annotations, `MDC` propagation (`MdcPropagation`, `mdcPropagation` option) and formatting comments - no binding detection. Small, self-contained, and squarely in the \"don't make users raise log levels to find out why nothing works\" space this repo already cares about. Would need porting to `internal/utils/` and checking it does not itself log through the missing binding. Genuinely useful and cheap."}
- {ref: tx-commit-failure, tip: 56d1e0273, state: ours, class: absorbed, note: "`START: WIP: Brainstorming for #144 - granular producer commit failure handling` - replaces a blanket `catch (Exception e) { retry }` around transaction commit with a three-way classification, carrying an inline table marking each KafkaProducer commit exception r(etriable)/f(atal)/u(nknown): retry `IllegalStateException | InterruptException`, fail fast on `ProducerFencedException | UnsupportedVersionException | InvalidProducerEpochException`, rethrow unknown `KafkaException`. Carries its own `todoo this needs testing` note. VERDICT: Absorbed, with the classification corrected on the way in. Master's `internal/ProducerManager` has the same exception table as a comment block (\"Only catch and retry the retriable ones, others fail fast the control thread\"), retries `catch (TimeoutException | InterruptException e)` - note master retries `TimeoutException` and does NOT retry `IllegalStateException`, which is the sounder call - and imports `ProducerFencedException` / `InvalidProducerEpochException` for the fatal paths, with a dedicated `catch (ProducerFencedException e)`. Confluentinc#144's substance shipped."}
- {ref: external-engine-higher-pressure, tip: 944808e9c, state: ours, class: superseded, note: "`WIP-START: Experiment with adding pressure system to external engines, with fractional steps` - turns `ExternalEngine.checkPressure()` from a no-op into a real stepping implementation (`dynamicExtraLoadFactor.maybeStepUp()` when in-flight drops below 90% of maxConcurrency and the mailbox has more), and multiplies the request quantity by the current load factor. Commented-out `isWithin`/fractional experiments left in place. VERDICT: Superseded, and master records why in the code. `internal/ExternalEngine.checkPipelinePressure()` on master is a deliberate no-op with the reasoning inline: \"the load factor stays at its initial value... The patch experiment's second arm showed the BUFFER is the recovery and the pressure system's stepping adds nothing on top for these engines; letting it step would only deepen the wait queue and the memory held behind the ceiling, never the concurrency, which #dispatchCeiling fixes.\" Master solved the underlying problem with a `Semaphore dispatchCeiling` sized at `getTargetAmountOfRecordsInFlight()`. This branch's experiment has been run and rejected on evidence - do not revive it."}
- {ref: features/rate-limiting, tip: e9f49d321, state: ours, class: open-idea, note: "LINKED both directions with astubbs/parallel-consumer#392 (hasten navigator micro-MVP), which ALREADY KNEW: its core-distributed-throttling.md names this branch among related abandoned branches, alongside features/dynamic-concurrency-control, feature/auto-tuning-pressure and upstream draft confluentinc#22. The reverse link is what was missing - the branch had no way to point at the work that superseded it. `START: POC for bucketj rate limiting integration` - adds a bucket4j dependency and a `RateLimitTest`, and reworks the reactor and vertx example apps to demonstrate throttling PC's consumption rate (e.g. to respect a downstream API quota). VERDICT: Not absorbed. No `bucket4j` in any pom on master and no user-facing rate limiting anywhere. Master's `internal/RateLimiter` is unrelated - it is a log-throttle used by `queueStatsLimiter`, `loadFactorAtCeilingLimiter`, `pauseLimiter`, `brokenRetryDelayProviderWarnLimiter`. This is a real and frequently-asked capability for the target use case (parallel calls to a rate-limited external service, which is what the vertx/reactor modules exist for). It is only a POC - 36 test lines and example churn - so finishing it means deciding whether throttling is a PC option, a documented user-side pattern, or an optional module, and whether the dependency belongs in core."}
- {ref: parallel-webservice, tip: 1d19e37d7, state: ours, class: open-idea, note: "`START: scatter-gather POC` - a `ParallelServiceRouter` in the reactor example that fans a request out to several backing services in parallel and gathers the responses, with a WireMock-backed test. Positions PC as a parallel web-service router, not only a Kafka consumer. VERDICT: Not absorbed. No `ParallelServiceRouter` on master and nothing scatter-gather shaped in `parallel-consumer-examples/`. This is a product-positioning artefact more than a library feature - it demonstrates a use case rather than adding capability - so its value is whether that story is one `STRATEGY.md` still wants to tell. If yes it is cheap (an example plus a test); if no, close it."}
- {ref: vertx-web-examples, tip: 5b8dc37ae, state: ours, class: open-idea, note: "`START: api: Add convenience methods for vertx calls` - single-argument overloads `vertxHttpRequest(webClientRequestFunction)` and `vertxHttpWebClient(webClientRequestFunction)` that default the `onSend`/`onWebRequestComplete` callbacks to no-ops, plus filling in the empty `@param` javadoc tags on the existing three-arg forms. VERDICT: Not absorbed. Master's `VertxParallelStreamProcessor` declares only `vertxHttpReqInfo(...)`, the three-arg `vertxHttpRequest(...)`, the two-arg `vertxHttpWebClient(...)` and `vertxFuture(...)` - callers who do not care about the callbacks must still pass two no-op lambdas. Small, additive, non-breaking ergonomics; needs porting to the `PollContext` signatures master now uses, and a decision about how it interacts with the JStream deprecation work in astubbs#116. Worth doing on its own."}
- {ref: docker-fixes, tip: 622f3ab8f, state: ours, class: open-idea, note: "`START: refactor: Extract TestContainer avoids Class initialisation failure` - body: \"Previously the container was constructed as part of a static initializer block for the static field. If a container failed to start, it would cause a ~Failed to initialize class error, which was confusing and unclear in logs.\" Moves container construction into a `KafkaContainerManager` so a Docker failure surfaces as itself. (The six other commits are ancestors already on master by other SHAs.) VERDICT: Not absorbed - the exact shape it complained about is still there. Master's `BrokerIntegrationTest` declares `public static KafkaContainer kafkaContainer = createKafkaContainer(null)` and starts it from a bare `static { kafkaContainer.start(); }` block; there is no `KafkaContainerManager` anywhere in the tree. So a Docker-unavailable or image-pull failure still presents as `NoClassDefFoundError: Could not initialize class BrokerIntegrationTest` across every IT at once. Given how much this repo invests in tests failing legibly (the `AMBIENT PROBE AUTOPSY` block hangs off this very class), this is a well-matched, low-risk fix: move the start into a lifecycle callback or a manager holder and let the real exception through. Note master has since added `resetKafkaContainer()`, which mutates the same static field - any port must account for that."}
- {ref: features/disrupter, tip: 9473ab395, state: ours, class: open-idea, note: "`START: Disrupter engine experiments` (LMAX Disruptor, spelled \"disrupter\" throughout) - a new module with a `PCDisrupter` prototype and a `VolatileTest`, exploring replacing the queue-based work handoff with a Disruptor ring buffer. Only the top commit is the experiment; the 21 below it are ancestors already on master (batching, poll context, processing shard, dependency bumps). VERDICT: Not absorbed. No disruptor dependency in any pom and no such module on master (core, examples, mutiny, reactor, vertx). It is the 2022 restatement of the 2020 `direct-ringbuffer` idea - same goal, different library - which suggests it is a recurring itch rather than a one-off. Weigh it against master's current design before reviving: the mailbox is a `LinkedBlockingQueue<ControllerEventMessage>` and the external engines are now bounded by `ExternalEngine.dispatchCeiling`, so any Disruptor work would have to beat those on a measured benchmark first. 124 lines of prototype; treat it as a spike to redo, not code to merge."}
- {ref: animal-sniffer, tip: 6a1624f08, state: ours, class: superseded, note: "`START: animal-sniffer-maven-plugin` plus a `version` bump - wires in `animal-sniffer-maven-plugin` to verify the compiled bytecode only touches the Java 8 API surface, catching accidental use of Java 9+ methods that compile fine but fail at runtime on 8. VERDICT: Superseded by the compiler itself. Master's root `pom.xml` runs `maven-compiler-plugin` with `<release>${source.version}</release>` plus the `jabel-javac-plugin`, and AGENTS.md states the arrangement: Java 17 source, Java 8 bytecode, \"`--release 8` restricts the API surface\". `--release` enforces at compile time exactly what animal-sniffer verified afterwards, so the plugin would be redundant - `grep animal-sniffer` over master's poms returns nothing, correctly. Close it."}
- {ref: features/failure-history, tip: b81c99350, state: ours, class: open-idea, note: "`START: Store failures and make accessible - useful for .. ?` - replaces `WorkContainer`'s single-slot `numberOfFailedAttempts` / `lastFailedAt` / `lastFailureReason` with a `LinkedList<Failure>` (a `@Value` record of `Instant time` + `Throwable cause`), derives `getLastFailedAt()` from it, and exposes `RecordContext.getFailureHistory()` as an unmodifiable list. Note the immediately preceding commit on the same lineage, `821dca631 step: remove feailure history, migrate to threeten's MutableClock`, had just *removed* an earlier version - so this is a second attempt, and the author's own subject line questions the value (\"useful for .. ?\"). VERDICT: Not absorbed. Master's `state/WorkContainer` still keeps only `lastFailureReason` (set once in `lastFailureReason = Optional.ofNullable(cause)`), and `RecordContext` exposes `getNumberOfFailedAttempts()`, `getLastFailureAt()`, `getLastFailureReason()` - the last failure, never the sequence. The idea has a clear use today that it did not obviously have in 2022: a per-record failure history is what a DLQ / max-retries callback (confluentinc#196, still named as open in master's README) would want to hand the user, and what a \"why did this record keep failing\" diagnostic needs. To finish it: bound the list (an unbounded per-record `LinkedList<Throwable>` is a leak under a permanently failing record - that is presumably why it was removed once), and land it with, not before, the terminal-error work that gives it a consumer."}
- {ref: improvements/headset, tip: 3e67fe7d1, state: ours, class: open-idea, note: "Two things bundled: (a) adopt the Truth-Generator (`WIP: use truth generator`, `truth: minor: compatibility changes`) with `PodamUtils`/`ModelUtils` test fixtures, and (b) `START: use headSet instead of search` — replace `getIncompleteOffsetsBelowHighestSucceeded()`'s `incompleteOffsets.parallelStream().filter(x -> x < highestSucceeded)` full scan with a `NavigableSet.headSet(...)` on the sorted structure. VERDICT: The Truth-Generator half is fully absorbed — master pins `truth-generator-maven-plugin.version` 0.1.1 and carries `ModelUtils.java`, `WorkContainerTest.java`, `TruthGeneratorTests.java` and `internal/utils/PodamUtils.java`. The headSet half is NOT: master's `PartitionState.getIncompleteOffsetsBelow(long)` still does `incompleteOffsets.keySet().parallelStream().filter(x -> x < bound)`. Master has since moved `incompleteOffsets` to `ConcurrentSkipListMap`, so the O(n)→sub-range win is now trivially available (master already uses `keySet().headSet(bootstrapPolledOffset, false)` elsewhere in the same class). `docs/refactoring.md` Performance section already lists it as \"**Concrete, still relevant**\". Caveat: the 2022 commit's own code was wrong (`headSet(Long.MAX_VALUE, true)` ignores the bound) — take the idea, not the diff."}
- {ref: build-repetition, tip: f1d74b333, state: ours, class: spent, note: "One commit, `build: Fix maven repetition` — collapses the Jenkins goal list from `clean verify install dependency:analyze site validate -U` to `-U dependency:analyze clean install`. VERDICT: Spent. There is no `Jenkinsfile` on master at all (`git ls-tree origin/master` root listing); CI is GitHub Actions under `.github/`. The artefact it edits no longer exists."}
- {ref: improvements/privacy-restriction, tip: d86a87ef0, state: ours, class: open-idea, note: "Despite the name, this is the shared-nothing-architecture spike. Commits: `START: Shared nothing architecture - last step realise partition events` (which also drops the `onPartitionsLost` handler as redundant with `onPartitionsRevoked`), `START: Refactor - move from type packages to area packages`, `broke: tighten access` (the privacy restriction — narrowing public surface once the areas are separated), `broken: pass commit data through messages, instead of lookup`. Last three commits are self-labelled `broke:`/`broken:`/`save` — it does not compile. VERDICT: Not absorbed and, unusually for this cohort, **referenced nowhere** in the tracking corpus (`git grep 'privacy-restriction' origin/master` over refactoring.md / upstream-map.yaml / docs/inflight/ / upstream-pr-analysis.adoc returns nothing). Master still has flat `internal`/`state`/`offsets` packages, no `controller`/`kafkabridge`/`sharedstate`, and `ControllerEventMessage` remains a package-private static nested class inside `AbstractParallelEoSStreamProcessor` rather than a first-class message type. It is the same confluentinc#200 / astubbs#142 shared-nothing family that `docs/refactoring.md` \"Thread model\" tracks, but this branch is not listed among its abandoned branches. Cheapest correct action: add it to that section's branch list."}
- {ref: improvements/nonnull-default, tip: 684c02a0d, state: ours, class: open-idea, note: "One commit, `START: Adopt ParametersAreNonnullByDefault` — a four-line `package-info.java` applying `@ParametersAreNonnullByDefault` to the `internal` package, plus the JSR-305 dependency in the root pom. VERDICT: Not absorbed — `git grep ParametersAreNonnullByDefault origin/master` hits only `docs/refactoring.md`, and there is no `package-info.java` anywhere in master's main sources. It is deliberately deferred, not forgotten: refactoring.md lists it twice, once under \"**Evaluate for breakage at the bump**\" alongside `origin/improvements/module-info`, because tightening the published nullability contract can break downstream callers. What it would take: a major-version window, and a decision on whether to annotate the public API packages or only `internal`."}
- {ref: improvements/loom, tip: 32ebac171, state: ours, class: superseded, note: "One commit, `START: Loom POC` — a scratch `Loom` class plus `--enable-preview` build plumbing, to see whether virtual threads could back the worker pool. VERDICT: Superseded, and already recorded as such: `docs/refactoring.md` reads \"`origin/improvements/loom` @32ebac17 - Loom/Virtual-Threads POC → **superseded by confluentinc#908**\". Nothing named `Loom` or `virtualThread` exists in master's Java sources. Note the build constraint that makes the POC unusable as-is: master compiles Java 17 source to Java 8 bytecode via Jabel, so virtual threads are a runtime-floor decision, not a code change."}
- {ref: parallel-tests-ci, tip: 8031d8193, state: ours, class: superseded, note: "`ci: Turn on parallel tests in Jenkins` — flips `<parallel-tests>` from `false` to `true` inside the `ci` Maven profile, plus a master merge. VERDICT: Superseded — the decision was made the other way, deliberately. Master's `ci` profile still sets `<parallel-tests>false</parallel-tests>`, and the pom comment beside `surefire.forkCount` states why: process-level forks are used \"unlike JUnit thread parallelism (`parallel-tests`) which contends on static state\", with the CI profile scaling `surefire.forkCount` to `1C` instead. Turning this flag on is the thing master explicitly avoids."}
- {ref: editorconfig, tip: 5bf496d87, state: ours, class: open-idea, note: "`docs: Recommended Plugins` then `START: .editorconfig plugin check` — wire the ec4j EditorConfig Maven plugin into the `verify` phase so violations fail the build, with `add some test bad formatting` as the proof it fires. VERDICT: Half absorbed, half open. The documentation half landed (master has `.editorconfig`, and `README.adoc` lists `EditorConfig` in the recommended-plugins block). **The enforcement half did not** — `git grep 'ec4j\\|editorconfig-maven-plugin' origin/master` returns nothing, so nothing fails a build on a formatting violation. Master already names this gap: `docs/inflight/ci-build-hardening-register.md` records Checkstyle/Spotless as ruled out because \"EditorConfig covers the rules; unenforced in CI is a real gap but a cosmetic one\". The 2022 branch is the ready-made answer to that gap. What it would take: bump ec4j past 0.1.1, run it once to size the existing violation count, decide `verify` vs a `bin/` gate."}
- {ref: features/connect-in-pc, tip: e2cc920fd, state: ours, class: superseded, note: "`START: Connect POC` — the *embed* direction: hand-construct Kafka Connect `SinkTask`s inside a PC application, as a runnable example module. VERDICT: Superseded by a later, reasoned decision. `docs/inflight/branch-connect-on-pc-workstream.md` records that the embed direction \"was tried, written up and **rejected**: one task per partition caps concurrency at the partition count\", in favour of patching Connect's `WorkerSinkTask` at build time (draft PR astubbs#269, branch `feats/connect-on-pc-spike`). Master's `parallel-consumer-examples/pom.xml` has no connect module. **One caveat worth surfacing**: that same note says the 2026 rejection \"was reasoned from source without opening it\" and calls this branch \"prior art nobody re-read\" — so the rejection is sound in principle but this specific 221-line app has never actually been read by the people who rejected the direction."}
- {ref: features/partial-batch-failure, tip: 486caa5aa, state: ours, class: open-idea, note: "The retry-exception line taken one step further into batching. Adds an `Offsets` value type (`@Delegate List<Long>`, `Offsets.from(List<RecordContext>)`) and overloads `PCRetriableException(String message, Offsets offsets)` so a user function processing a batch can throw and say **which offsets in the batch actually failed**. All of the exception handling is lifted out of `AbstractParallelEoSStreamProcessor` into a new `UserFunctionRunner`. VERDICT: **Not absorbed, and it is the direct answer to an open bug.** Master has none of `Offsets.java`, `PCTerminalException`, `PCUserException` or `UserFunctionRunner`; master's `PCRetriableException` has only the four plain `(message/cause)` constructors. `docs/inflight/core-189-batch-failure-granularity.md` verifies at HEAD that \"one thrown exception calls `onUserFunctionFailure` on **every** container. The user function is invoked before anything is marked succeeded, so no innocent record is ever distinguishable from the poison one\" — which is precisely the ignorance this branch's `Offsets`-carrying exception removes. `docs/inflight/core-batching-enhancements.md` names the same \"partial-batch-failure ask\". Listed as an unattributed orphan in `branch-audit-orphans.md`. What it would take: decide whether the failure manifest rides on the exception (this branch) or on a per-record API (the ideation's third rung), then re-do it on master's batch loop."}
- {ref: features/retry-exception, tip: 14aad84ef, state: ours, class: open-idea, note: "`START: Explicit retry exception for cleaner logging` plus 22 more. Introduces a three-class exception hierarchy under a common `PCUserException`: `PCRetriableException` (retry quietly, no ERROR log) and **`PCTerminalException`** (this record can never succeed), with a new `ParallelConsumerOptions.TerminalFailureReaction` enum (`SKIP` / `SHUTDOWN`) deciding what PC does on terminal. Extracts the whole user-function invocation path into `UserFunctionRunner`. Its final commit is `revert partial batch failure` — i.e. this branch is `features/partial-batch-failure` with the `Offsets` work stripped back out. VERDICT: **Half absorbed, and the missing half is the interesting one.** `PCRetriableException` shipped and is on master with its quiet-logging contract intact. `PCTerminalException`, `PCUserException`, `TerminalFailureReaction` and `UserFunctionRunner` did **not** — `git grep TerminalFailureReaction origin/master` returns nothing, and master's failure path is still inline in `AbstractParallelEoSStreamProcessor.runUserFunctionInternal`. This matters because `core-189-batch-failure-granularity.md` records \"**There is no retry ceiling** - the same finding astubbs#149 records as the DLQ's prerequisite - so it never ends\", and the manifest's `sweep-2023-retry-lifecycle` says the same: \"Fork has retryDelayProvider and PCRetriableException, but the exception carries no Duration\". A terminal-failure signal from user code is the cheapest first rung of that ladder. `branch-audit-orphans.md` guesses confluentinc#291 / confluentinc#268 as the upstream homes; no manifest entry exists for the pair."}
- {ref: features/retry-exception-w-terminal, tip: 14aad84ef, state: ours, class: open-idea, note: "**This is not a separate branch.** `origin/features/retry-exception-w-terminal` and `origin/features/retry-exception` point at the same commit, `14aad84ef` — same tree, same 23 commits, byte-identical diffstat. The `-w-terminal` name is the more accurate one (the terminal-exception work is what distinguishes the tip from its `revert partial batch failure` parent). VERDICT: See `features/retry-exception` above; the verdict is the same object. Ledger-wise the two names should share one row, or one should be deleted. `branch-audit-orphans.md` already treats them as a pair. Note its warning that the same-named *upstream* branch tip diverged from origin's, so attribution should look at both lines."}
- {ref: features/multi-cluster, tip: 66564563d, state: ours, class: open-idea, note: "Stacked on `features/key-partition-combine`; its own tip commit is a bare `START: Multi-cluster support`. The multi-cluster content is two `@Value` skeletons — `Cluster { String clusterId; }` and `ClusterTopicPartition { Cluster cluster; TopicPartition topicPartition; }` — i.e. the type change needed to make shard keys cluster-aware. Everything else in the diff belongs to the key-partition-combine parent. VERDICT: Not absorbed — neither class exists on master, and no cluster identity appears in `ShardKey`. Already tracked as an idea: manifest `sweep-2023-long-tail` lists `features/multi-cluster` under fork branches with fork issue coverage. Genuinely valuable but essentially unstarted: the branch is two records and a `todo docs`. What it would take: a real design (one PC per cluster vs one PC across clusters), which is far more than this branch contains."}
- {ref: features/producer-facade, tip: d7a118c0c, state: ours, class: superseded, note: "Wrap PC's producer in a delegating facade (`Change from 'is a' to 'has a' (implementation vs delegation facade)`), carried on top of the consumer-facade and lambda-actor-bus lines. The tip commit is the conclusion: **`end: doesn't make sense to have a producer facade`**. VERDICT: Superseded by its own recorded conclusion — the author already answered the question. `docs/refactoring.md` states it verbatim: \"`origin/features/producer-facade` @d7a118c0 - **DEAD-END, conclusion recorded**: 'doesn't make sense to have a producer facade.' Don't revisit.\" Master has neither `ProducerFacade` nor `ConsumerFacade`. The *consumer* facade half is a different, still-live question (see `bugs/issue-184-reproduce-using-cfacade`)."}
- {ref: improvements/scheduled-commit, tip: b6f0a542b, state: ours, class: open-idea, note: "`START: Use a scheduled executor to do commits` plus `remove commit command` — move commits off the control loop's ad-hoc timing onto a scheduled executor, which lets the `commitCommand` signalling path be deleted. Sits on the lambda-actor-bus + interrupt-reason stack, so most of the diff is that substrate. VERDICT: Not absorbed — master still drives commits from the control loop (`AbstractParallelEoSStreamProcessor`) with no `csid/actors` package and no `InterruptibleThread`. Already catalogued in `docs/refactoring.md` under \"Actor / IPC message bus for commits & results\" and registered in the manifest as `sweep-2023-actor-ipc`, where the entry says the family is \"Only meaningful as part of the confluentinc#200 (mirror astubbs#142) rework\". What it would take: the thread-model decision first; this is a consequence of it, not a standalone change."}
- {ref: bugs/issue-184-reproduce-w-cf-reverted, tip: 49642eee3, state: ours, class: absorbed, note: "The confluentinc#184 (multi-topic subscription) reproduction, with the consumer-facade experiment backed out — the tip commit is literally `Revert \"Merge branch 'features/consumer-interface' into merging\"`, leaving the test asserting commits via a **separate** consumer instead of through PC. Its substantive commit is `MAJOR: multi test passes and is fast and completely event based`. 108 commits ahead only because it accumulated four unrelated merged branches (version bumps, OSS Index, Truth-Generator upgrade). VERDICT: Absorbed. Master carries `MultiTopicTest` (javadoc: \"Originally created to investigate issue report confluentinc#184\"), parameterized over every `ProcessingOrder`, asserting through `assertSeparateConsumerCommit(...)` with `assertThat(assertingConsumer).hasCommittedToPartition(partitions)` — i.e. exactly this branch's revert-side design, on the landed `ConsumerSubject`/`CommitHistorySubject`. `ShardKey` and `ShardKeyTest` are on master too. The issue itself is closed (`docs/inflight/issue-index.md` row for #184). Nothing is left here but the 2022 scaffolding."}
- {ref: features/key-partition-combine, tip: d4d54bda3, state: ours, class: open-idea, note: "`START: KEY ordering partition combine options` — make KEY-ordered sharding configurable in how far a key's identity reaches. Adds `KeyIsolation { ISOLATE, COMBINE_PARTITIONS, COMBINE_TOPICS }` (default `ISOLATE`) and `KeyOrderSorting { OFFSET, TIMESTAMP }` (default `TIMESTAMP`), plus a `ShardKey` subclass per isolation mode (`KeyIsolated`, `KeyPartitionsCombined`, `KeyTopicsCombined`) and a `ShardCollection` to own the shard map. Also carries the null-key test (`test for null keys`). VERDICT: **Partly absorbed; the configurable part is not.** `ShardKey` with `KeyOrderedKey`/`TopicPartitionKey` landed on master, including null-key tolerance (\"Nullable if record is produced with a null key\") — but master's `KeyOrderedKey` is hard-wired to the `ISOLATE` semantics (`TopicPartition` + key), and `git grep 'KeyIsolation\\|KeyOrderSorting\\|COMBINE_PARTITIONS' origin/master` returns **nothing**. `ShardCollection` does not exist; the map still lives in `ShardManager`. So a user who wants one key to be sequential across partitions or across topics still cannot ask for it. `branch-audit-orphans.md` flags it: \"check against `sweep-2023-null-key-ordering` before assuming\". What it would take: modest — the ShardKey subclass hierarchy is drafted and the enum is two lines; the real work is deciding whether COMBINE_TOPICS is coherent with per-partition offset commits, and writing the docs the branch left as `todo docs`."}
- {ref: 0.5.3.x, tip: bd638e70b, state: ours, class: spent, note: "A single `[maven-release-plugin] prepare for next development iteration 0.5.3.0-SNAPSHOT` commit — the release plugin's post-tag version bump, on a maintenance-line branch. VERDICT: Spent. Pure release plumbing from the 0.5.3 line; master is at `0.6.0.0-SNAPSHOT` and this commit is not an ancestor of master (`git merge-base --is-ancestor bd638e70b origin/master` → false). No idea to absorb. Keep the branch only if the 0.5.3.x maintenance line is still meant to be a thing."}
- {ref: 0.6.x, tip: 361bf7235, state: ours, class: spent, note: "A single `[maven-release-plugin] prepare for next development iteration 0.6.0.0-SNAPSHOT` commit. VERDICT: Spent by convergence. The version it sets is the version master is on today (`0.6.0.0-SNAPSHOT` in master's root pom), reached by a different commit — this tip is not an ancestor of master. Nothing to absorb."}
- {ref: bugs/issue-184-reproduce-using-cfacade, tip: 140deac45, state: ours, class: open-idea, note: "The other half of the confluentinc#184 pair — the same reproduction, but asserting commits **through PC itself** via a full `ConsumerFacade` (`ebfd06e7c facade test skeleton, basics seem to work so far`). `f3e73ea02 ConsumerSubject blocked by PC no multi threaded access` records why it was hard. Its Truth subject `ParallelEoSStreamProcessorSubject.getConsumer()` calls `actual.getConsumerFacade()`. VERDICT: The reproduction is absorbed (see the `-w-cf-reverted` entry), but **the facade this branch needed is not, and master carries a live, dark hole because of it.** `MultiTopicTest` on master still contains a wholesale commented-out `assertCommit(...)` helper marked `// depends on merge of features/consumer-interface branch`, and its live javadoc says \"When consumer-interface #XXX is merged, could just poll PC directly\". `docs/test-hardening/inactive-tests-audit-2026-08-08.md` §4 calls this out as one of two \"standing intentions, not deleted but never fulfilled\", and `docs/refactoring.md` describes it as \"waits on a branch that does not exist on master\". `ConsumerFacade` and `ParallelEoSStreamProcessorSubject` are both absent from master. What it would take: land a consumer facade (this branch's 383-line draft, or `origin/features/consumer-interface`), then uncomment one seven-line assertion. Related: confluentinc#186 thread-safe public APIs, which is why the facade was hard in 2022."}
- {ref: features/retry-dlq, tip: e5bf77c9b, state: ours, class: open-idea, note: "The retry-exception stack's terminus: `START: DLQ draft`, `add failure cause to headers`, `try to create dlq topics if missing, with server defaults`. On a terminal failure, produce the record to a dead-letter topic through `ProducerManager` with the cause carried in record headers, auto-creating the DLQ topic with broker defaults if absent. VERDICT: Not absorbed — no dead-letter code exists in master's Java sources (the only `DLQ` hits are prose). This is the most heavily tracked branch in the chunk and is explicitly kept alive: manifest `sweep-2023-retry-lifecycle` names it \"Draft of both remaining children: PR #366 astubbs/features/retry-dlq @e5bf77c9b\"; `docs/data/roadmap.yaml` has `id: dead-letter-queue`, `horizon: next-0x`, `stage: requirements-drafted`, \"the 2022 draft (astubbs#8) is the seed implementation\"; `docs/inflight/pr-blockers-and-collisions.md` records astubbs#8 as \"an abandoned draft, kept only because it is the sole\" record. What it would take: the retry-ceiling decision first (astubbs#149 records it as the DLQ's prerequisite) — a DLQ with no expiry policy has nothing to trigger it."}
- {ref: improvements/actor-scheduled, tip: 4db0da0fd, state: ours, class: open-idea, note: "`START: Actors Bus - migrate to lambda bus` then `START: Scheduled actors` — give the actor mailbox a scheduling capability (delayed/periodic messages) so time-driven control-loop work becomes messages rather than sleep-and-poll. Tip commit `split: old multi topic test` is housekeeping. VERDICT: Not absorbed; no `csid/actors` package on master. Catalogued in `docs/refactoring.md` under \"Actor / IPC message bus for commits & results\" (`origin/improvements/actor-scheduled` @4db0da0f) and in the manifest as part of `sweep-2023-actor-ipc`, gated on confluentinc#200 / astubbs#142. One member of a family of six near-duplicate actor branches; not independently valuable."}
- {ref: improvements/interrupt-reason, tip: 93a06fe00, state: ours, class: open-idea, note: "`START: Interrupt reason` — wrap the control thread in an `InterruptibleThread` that carries a *reason* alongside the interrupt, with `delegate logger and root reason` / `better logging and fix reason` refining who logs what, so a receiver can tell why it was woken. VERDICT: **Not absorbed, and this is the branch that maps onto a currently-named, currently-costed defect.** `InterruptibleThread` is absent from master. `docs/refactoring.md` describes the problem in today's terms: \"`Thread#interrupt` has no payload, so the one bit currently carries four meanings - wake up, stop blocking, shut down, and 'your next commit-lock acquisition will throw'. Receivers cannot tell which, so the class has accumulated four hand-clears instead of a fix, one of which does not clear and merely warns that it cannot tell. astubbs#296 hit it by adding an ordinary state transition and inheriting a shutdown hazard from a wakeup.\" The same doc's \"concrete, already-costed first slice\" (payload-free nudge variant, shutdown as a message, coalescing on an `AtomicBoolean`) is a *different* answer to the same problem than this branch's — worth reading the branch before committing to either. Also listed under Thread model as \"the interrupting-poll model - wake a blocking poll when work arrives\"."}
- {ref: improvements/multi-topic-test, tip: dd3ad77b5, state: ours, class: open-idea, note: "The clean extraction of the multi-topic test out of the 108-commit `bugs/issue-184-*` tangle (`split: multi topic test`, `split: old multi topic test`), plus the missing Truth subject its tip commit restores: `add back in the missing code - be careful moving from ignored to main - IDE doesn't auto git add`. VERDICT: The test is absorbed — master's `MultiTopicTest` is this test. `ParallelEoSStreamProcessorSubject` is **not**: it is absent from master, and it is the exact class master's commented-out `MultiTopicTest.assertCommit` needs (it exposes `hasCommittedToPartition(NewTopic)` by delegating to `ConsumerSubject` through `actual.getConsumerFacade()`). So this branch is the smallest carrier of the missing piece — 69 lines, but blocked on the same `ConsumerFacade` as `bugs/issue-184-reproduce-using-cfacade`. Untracked: `git grep 'improvements/multi-topic-test' origin/master` over the tracking corpus returns nothing."}
- {ref: improvements/poller-bus-actor, tip: b1598f219, state: ours, class: open-idea, note: "`split: poller` and `split: actor base - needs unifying of the two actor classes` — turn `BrokerPollSystem` into an actor addressed by `ActorRef`, on the second (unreconciled) actor base. VERDICT: Not absorbed. Tracked in **two** places in `docs/refactoring.md`: under Thread model (\"poller as an actor\") and under Actor/IPC, where the entry records the specific unfinished business — \"it carries the *second*, unreconciled actor base: `IActor`/`Actor` + `ActorRef`, vs lambda-actor-bus's `Actor`/`ActorImpl`; its commit d391398f1 records the unification as unfinished\". Registered as `sweep-2023-actor-ipc`. Gated on the confluentinc#200 thread-model decision; the branch's own commit says the two actor bases must be unified first."}
- {ref: features/broker-connection-status, tip: 782429b0c, state: ours, class: open-idea, note: "`START: Broker status informer` — a `BrokerStatusInformer` interface (`addStatusListener`, `getConnectionStatus`, nested `BrokerStatusListener` and `BrokerStatus { CONNECTED, DISCONNECTED }`) implemented by `BrokerPollSystem` and re-exposed on `AbstractParallelEoSStreamProcessor`, so an application can observe whether PC is talking to the broker. VERDICT: Not absorbed — no `BrokerStatusInformer` or broker-status field anywhere in master, and master's `metrics` package (`PCMetrics`, `PCMetricsDef`) exposes no connectivity gauge. Real user-facing gap, but **the branch is a skeleton, not an implementation**: `statusListeners` is declared and never initialised (an NPE on first `addStatusListener`), `brokerStatus` is never assigned, and `onBrokerStatusChange` is private and never called. `branch-audit-orphans.md` guesses confluentinc#185 / confluentinc#353 as the upstream homes and notes it is \"related to but distinct from `sweep-2023-broker-disconnect-commit`\". What it would take: essentially all of it — decide where DISCONNECTED is detected (poll timeouts? `ConsumerManager` errors?) and whether the surface is a listener or a `PCMetricsDef` gauge."}
- {ref: improvements/async-process-send-results-using-actor, tip: 00f350166, state: ours, class: open-idea, note: "Three threads in one branch: `START: Transactional mode docs`, `step - batch the read lock holding`, and the tip `START: Use actor system to process send results when they're done, instead of blocking get on future` — stop `ProducerManager` blocking on `future.get()` for each produced record and instead handle send results as actor messages when they arrive. VERDICT: Not absorbed in its main claim; partly absorbed at the edges. `csid/actors` and `Interruptible` are absent from master and `ProducerManager` still resolves sends synchronously. But the **test scaffolding did land** — master carries `internal/ProducerManagerTest.java`, `truth/ProducerManagerSubject.java` and `truth/ConsumerRecordsSubject.java` (though not `TransactionBlockTest`). Well tracked: `docs/refactoring.md` names it \"(process send-results via actor instead of a blocking `future.get` - relates to draft `confluentinc#356`)\", and the manifest has its own `fork.branches: [improvements/async-process-send-results-using-actor]` entry with fork issue 230. Same confluentinc#200 gate as the rest of the actor family."}
- {ref: improvements/async-process-send-results, tip: a89f0bce2, state: ours, class: open-idea, note: "Removes the blocking `futureSend.get(sendTimeout)` from the produce path. The tip commit body: use the producer's **send callback** to wake the controller, cache the list of expected records to produce and count them down as they complete, then `onSuccess` each `WorkContainer`. Commit `9b91d5773` explicitly *reverted the dependency on the actor system* — \"just use a concurrent queue, result is the same\" — so unlike its actor-based siblings it needs no unfinished actor base. VERDICT: **Not absorbed.** `origin/master:parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/ParallelEoSStreamProcessor.java` still does `futureSend.get(options.getSendTimeout().toMillis(), TimeUnit.MILLISECONDS)` on the worker thread. `docs/refactoring.md` records the *sibling* `improvements/async-process-send-results-using-actor` @00f35016 but never this branch — and this is the more landable of the two, precisely because the actor dependency was removed. Maps to draft confluentinc#356 / confluentinc#29."}
- {ref: features/streams, tip: e2f1d53e4, state: ours, class: open-idea, note: "A Kafka-Streams-shaped DSL over PC: `PCTopologyBuilder.stream(topic|collection|Pattern, Consumed<K,V>)` returning a `PCStream<K,V>` with `map` / `mapKS` / `flatMap` / `foreach` / `join` / `to(topic, Produced)` / `through`. The point is per-topic handlers over a multi-topic subscription rather than one global function. Carries the `Actor` base as a dependency. All new interfaces are `todo docs` stubs — a skeleton, not a working DSL. VERDICT: **Not absorbed** — no `PCStream`, `Consumed`, `Produced` or `csid/actors` anywhere on master. This is the head of upstream PR confluentinc#390, closed unmerged in the 2023-06-15 sweep. It is already named by SHA `e2f1d53e4` in fork issue **astubbs#254** (open, mirror of confluentinc#372), which warns the upstream body's \"Implemented in: #390\" claim is false. Related open fork issue **astubbs#255** (Kafka Streams on PC). To take it further: decide it alongside confluentinc#175 (separate consume/produce K,V types) — per-topic handlers are worth little while every handler shares one `<K,V>`."}
- {ref: improvements/transactions-dont-block, tip: 17f019b83, state: ours, class: superseded, note: "The tip commit adds **two TODO comments only** — \"message these to the controller thread instead of blocking for them here\" beside `futureSend.get(...)`, and \"check for produced message send success or not here\" in `onUserFunctionSuccess`. Everything else on the branch is the transactional-docs/produce-lock work. VERDICT: The infrastructure half **landed**: master has `allowEagerProcessingDuringTransactionCommit`, `produceLockAcquisitionTimeout`, `commitLockAcquisitionTimeout`, `BlockedThreadAsserter`, and a `ProducerManagerTest` that is a superset of the branch's `TransactionBlockTest` (`sendingGetsLockedInTx`, `producingIsBlockedForTheDurationOfTheCommitAndResumesOnRelease`, `produceLockIsReleasedExactlyOnce`). The residual idea is a duplicate of `improvements/async-process-send-results`, which carries an actual implementation rather than a comment — treat that branch as the successor. Already named in `docs/refactoring.md` under the actor cluster as \"non-blocking tx, depends on the actor system\"."}
- {ref: bugs/block-asserter-subject, tip: 1486466aa, state: ours, class: spent, note: "Adds `io.confluent.csid.utils.BlockedThreadAsserter` to the truth-generator plugin's `<classes>` list with the inline comment `todo why doesn't this work?`. A one-line probe at a build-plugin limitation, not a feature. VERDICT: Master's core `pom.xml` `<classes>` block lists only main-source classes (`PollContext`, `ParallelEoSStreamProcessor`, `ProducerManager`, `WorkContainer`, `WorkManager`, `PartitionState`, `ProcessingShard`, `ShardKey`, `OffsetEncoding`) — `BlockedThreadAsserter` is a **test** class, which is very likely the reason it \"doesn't work\". The underlying want (assertions over `BlockedThreadAsserter`) is met on master by hand-written `internal/utils/BlockedThreadAsserterTest.java`. Nothing to salvage."}
- {ref: issues/num395, tip: 6052fcf78, state: ours, class: superseded, note: "Despite the subject saying \"#395\", the added test method is named `largeNumberOfInstancesIssue397` — the target is **confluentinc#397 \"parallel consumer not scaling as expected\"** (CLOSED), not confluentinc#395 (\"API to send records through wrapped producer\"). Content: un-`@Disabled`s `largeNumberOfInstances`, adds a 60-partition / 3-instance / 500k-record variant, and makes `maxConcurrency` settable per runnable (was hard-coded 10). Plus a 3M-record, 3-instance, 12-partition consume-only soak (`MultiInstanceHighVolumeTestTwo`). VERDICT: **Superseded by master's own suite.** `MultiInstanceRebalanceTest` on master has grown capacity profiles with an `onlyCapacityProfilesMayScale` guard, `scriptedChurnRoundsCompleteWithoutStall`, `cooperativeStickyRebalanceShouldNotStall`, `gentleChaosRebalance`, and `largeNumberOfInstances` is **enabled** (`@Tag(\"performance\")` + `@Quarantined`) rather than `@Disabled`; `MultiInstanceHighVolumeTest` is parameterised by `-Dmultiinstance.messages`. The branch's two ideas (enable the disabled test, make concurrency configurable) are both present in stronger form."}
- {ref: m1-changes, tip: aa9ecb77e, state: ours, class: spent, note: "The branch's **own** commit is Apple-M1 local-dev fiddling: cp-kafka image `7.0.1` → `7.1.3`, two `log.info` lines around container start, dropping `//@Isolated` from `KafkaSanityTests`, widening `OffsetCommittingSanityTest`/`CheckMode` to public, and a javadoc reword. The 137 commits under it are the `improvements/transaction-docs` line. VERDICT: Environment-specific scaffolding with no lasting content of its own. The transaction work beneath it landed (see `improvements/transactions-dont-block` above: master carries `TransactionTimeoutsTest`, `BlockedThreadAsserter`, the produce/commit lock options). Nothing to mine."}
- {ref: improvements/test-perf, tip: 932210b6a, state: ours, class: spent, note: "Four \"test tweak\" commits plus a cp-kafka image bump. The substantive change is **commenting out** `junit.jupiter.execution.parallel.config.dynamic.factor=20`, i.e. backing off JUnit parallelism to stop the transactional IT thrashing, plus a reshuffle of `TransactionAndCommitModeTest`. VERDICT: Era-specific flake-chasing against a 2022 test layout. `docs/refactoring.md` already lists it (\"test perf / multi-topic\") but it carries no idea — turning parallelism down is the move this repo now handles through its suite split and lane scripts. Nothing to salvage."}
- {ref: v0.5.2.2, tip: cc9694f32, state: ours, class: spent, note: "A single commit, \"update cp image\": `confluentinc/cp-kafka:7.0.1` → `7.1.3`. A release-branch stub that never carried a release. VERDICT: A test-container image bump from 2022; master's broker matrix has moved on entirely. No content."}
- {ref: improvements/module-info, tip: d74f5e8b4, state: ours, class: open-idea, note: "Own commit adds JPMS descriptors. Core's declares `requires` on kafka.clients, lombok, unij, zstd/snappy, slf4j — and, revealingly, `wiremock.jre8.standalone` — and `exports io.confluent.csid.utils`, `.parallelconsumer`, `.parallelconsumer.internal`, `.parallelconsumer.state`. The other 142 commits are the transaction-docs line. VERDICT: **Not absorbed** — `git ls-tree -r origin/master | grep module-info` returns nothing. Already recorded in `docs/refactoring.md` twice, correctly, as **version-gated**: \"Evaluate for breakage at the bump ... add a JPMS `module-info` ... can break downstream callers / module-path consumers\". To land it: the draft exports `internal` and `state` and requires a *test* dependency (wiremock) from the main module — both need fixing, and the package rename means every name in it changes."}
- {ref: improvements/remove-static-use-pcmodule, tip: 806b505ef, state: ours, class: absorbed, note: "Replaces `WorkContainer`'s static `retryDelayProvider` / `defaultRetryDelay` (and the interim `WorkContainerContext` holder) with a single injected `PCModule<K,V>` reference, so retry-delay and clock come from `module.options()` / `module.clock()`. VERDICT: **Landed, in exactly this shape.** `origin/master:.../state/WorkContainer.java` has `private final PCModule<K, V> module;` with the javadoc \"Instance reference to otherwise static state, for access to the instance type parameters of WorkContainer as static fields cannot access them\", the constructor `WorkContainer(long epoch, ConsumerRecord<K,V> cr, @NonNull PCModule<K,V> module, @NonNull String workType)`, and `module.clock().instant()` / `module.options()` call sites — matching the branch line for line. Note `docs/refactoring.md` still lists this branch under \"Still relevant\" for astubbs#131; that half of the entry is stale (the `improvements/remove-static` half is not — see below)."}
- {ref: features/queue-priority, tip: 383a87456, state: ours, class: open-idea, note: "Per-key **priority queues**. Adds `ParallelConsumerOptions.priorityQueueSupplier` (an `Optional<PriorityQueueSupplier extends Supplier<Priority>>`) and `priorityQueueRatio` (default `Percentage.fromDouble(0.1)`), documented as *not reserved* capacity — if no priority shard has work, all capacity goes to normal shards. `ShardManager.getWorkIfAvailable` is split into `getHighPriorityWork` + `getNormalPriorityWork`, each running the existing `LoopingResumingIterator` over its own shard set. VERDICT: **Not absorbed and not recorded anywhere** — no `Percentage` class in main sources on master (the name only appears in unrelated Reactor/Mutiny/Vertx test code), no priority concept in `ShardManager`, and the branch appears in no document in the repo. Incomplete: `getHighPrioirtyIterator()` (sic) and `Priority` are referenced but never defined, and `priorityQueueRatio` is declared but never consumed by the shard split. What it would take: define the `Priority`/shard-classification type, decide whether priority is derived per-record (a `RecordContext` function, as the javadoc says) or per-shard, and make `getWorkIfAvailable` honour the ratio instead of requesting the full `requestedMaxWorkToRetrieve` from both sides. **This is the most interesting genuinely-lost idea in the chunk** — it is adjacent to per-topic prioritisation (confluentinc#50) which astubbs#254 flags as the same \"topics are not all alike\" theme."}
- {ref: improvements/remove-commit-queue, tip: 381d6997b, state: ours, class: absorbed, note: "\"Unify PartitionState collections\" (`39cc5ec5b`): collapses the two parallel structures — `ConcurrentSkipListSet<Long> incompleteOffsets` plus `NavigableMap<Long, WorkContainer<K,V>> commitQueue` — into one `ConcurrentSkipListMap<Long, Optional<ConsumerRecord<K,V>>> incompleteOffsets`. VERDICT: **Landed verbatim.** `origin/master:.../state/PartitionState.java` declares `private ConcurrentSkipListMap<Long, Optional<ConsumerRecord<K, V>>> incompleteOffsets;`, uses `incompleteOffsets.containsKey(recOffset)`, `this.incompleteOffsets.remove(offset) != null; // NOSONAR` and `incompleteOffsets.put(offset, Optional.of(record))` — including the same `// NOSONAR` the branch introduced. There is no `commitQueue` field on master."}
- {ref: improvements/set-to-list, tip: 7ada9918c, state: ours, class: absorbed, note: "Stops the encoder copying its input: `OffsetSimultaneousEncoder(long, long, List<Long>)` + internal `new TreeSet<>(incompleteOffsets)` becomes `OffsetSimultaneousEncoder(long, long, SortedSet<Long>)`, with a new `JavaUtils.toTreeSet()` collector so `PartitionState` builds the sorted set once at source. VERDICT: **Landed.** Master has `public OffsetSimultaneousEncoder(long baseOffsetToCommit, long highestSucceededOffset, SortedSet<Long> incompleteOffsets)` assigning `this.incompleteOffsets = incompleteOffsets` (no copy), `JavaUtils.toTreeSet()` in `internal/utils/JavaUtils.java`, and `PartitionState.getIncompleteOffsetsBelow(...)` collecting `.collect(toTreeSet())`. `docs/refactoring.md` still lists this branch under shard-count caching as \"**Concrete, still relevant**\" — stale for this branch (its two siblings `cache-counts`/`headset` are not in my chunk and were not checked)."}
- {ref: improvements/remove-static, tip: c34ee4a4f, state: ours, class: open-idea, note: "Removes the remaining mutable statics that force serial test execution: turns `public static int DefaultMaxMetadataSize = 4096` into `public static final int KAFKA_MAX_METADATA_SIZE_DEFAULT`, deletes `METADATA_DATA_SIZE_RESOURCE_LOCK` and the `public static Optional<OffsetEncoding> forcedCodec` back-door, replacing the latter with a test-only `ForcedOffsetSimultaneousEncoder` subclass, and routes the values through `PCModule`. VERDICT: **Not absorbed — and master's own code points at this branch.** `origin/master:.../offsets/OffsetMapCodecManager.java` still carries `public static int DefaultMaxMetadataSize = 4096;` preceded by the comment `// todo refactored to constant in the remove statics branch`, still carries `public static Optional<OffsetEncoding> forcedCodec = Optional.empty();`, and still carries `METADATA_DATA_SIZE_RESOURCE_LOCK` with its \"Manipulation of static state in tests needs to be removed so this isn't necessary\" note. Correctly recorded as \"**Still relevant**\" in `docs/refactoring.md` (astubbs#131; drafts confluentinc#405 / confluentinc#126 → confluentinc#143). The clean-up pattern (a test subclass instead of a static back-door) is the reusable part."}
- {ref: refactors/offsets-class, tip: 6916467a1, state: ours, class: open-idea, note: "Introduces a typed offset — `@Value class Offset { long value; }` with an `Offsets` wrapper (`@Delegate List<Long>`, `fromRecords`/`fromLongs`/`fromArray`) — \"to avoid being Longly typed\". Sits on top of the PSM/PS rework and the encoding data-structure work. VERDICT: **Not absorbed** — there is no `Offsets`/`Offset` class on master; offsets are bare `long`/`Long` throughout (`ConcurrentSkipListMap<Long, …>`, `SortedSet<Long>`, `encodeIncompleteOffset(long)`). Recorded in `docs/refactoring.md` under \"Offsets/state classes\", tied to confluentinc#233 / confluentinc#200 (mirrors astubbs#117 / astubbs#142). Cost of landing it is the reason it stalled: `Offset` touches every encoder signature, every state collection and the public `PollContext`/`RecordContext` surface."}
- {ref: refactors/offsets-class-partition-state, tip: d79f47bde, state: ours, class: open-idea, note: "A single spike commit that actually *uses* the new type: `ConcurrentSkipListMap<Long, Optional<ConsumerRecord<K,V>>>` → `ConcurrentSkipListMap<Offset, …>`, with `Offset.of(offset)` at the two put sites. It is the \"does the `Offset` type survive contact with the hot collection?\" experiment for the branch above. VERDICT: Same verdict as `refactors/offsets-class` — nothing of it on master. Worth keeping only as the worked first step of that refactor; `docs/refactoring.md` lists it alongside its parent. Note it does not compile-complete the change (only the two puts are converted), so read it as a probe, not a candidate."}
- {ref: refactors/refactor-psm-and-ps, tip: e2d512b43, state: ours, class: absorbed, note: "Moves per-partition responsibility out of the manager and into the state object — `addNewIncompleteWorkContainer`, `checkIfWorkIsStale`, `getEpochOfPartitionForRecord`, `getNumberOfEntriesInPartitionQueues`, `hasWorkInCommitQueues`, `isBlocked`, `isBlockingProgress`, `isPartitionRemovedOrNeverAssigned`, `isRecordPreviouslyCompleted` all leave `PartitionStateManager`. VERDICT: **Landed.** Method-set comparison of `PartitionStateManager` across merge-base `de21a35f3`, branch tip and `origin/master`: every one of the nine methods the branch removed is **also absent from master's PSM**, and they are present on master's `PartitionState` (`isRecordPreviouslyCompleted` L257, `isBlockingProgress` L720, `checkIfWorkIsStale` L767). `docs/refactoring.md` lists this branch under \"Offsets/state classes — PSM/PS rework\"; that half of the entry is now stale (the `Offsets` class half is not)."}
- {ref: refactors/mvnw, tip: 1d0bb2af0, state: ours, class: absorbed, note: "Adds the Maven wrapper to the project, plus a Jabel bump for Java 19. VERDICT: **Landed.** `origin/master` has `.mvn/`, `mvnw` and `mvnw.cmd` at the root, and `AGENTS.md` mandates `./mvnw` (\"do not use system Maven\"). The Jabel-for-19 half is moot: the project targets JDK 17 source → Java 8 bytecode."}
- {ref: features/extend-functional, tip: f831137a9, state: ours, class: open-idea, note: "Replaces the raw JDK functional types in the public API with named ones — `poll(Consumer<PollContext<K,V>>)` becomes `poll(UserFunctions.Processor<K,V>)`, `pollAndProduceMany(Function<PollContext, List<ProducerRecord>>)` becomes `pollAndProduceMany(UserFunctions.Transformer<K,V>)` — each extending the JDK interface it replaces, so the *javadoc* (retry semantics, `PCRetriableException`, `retryDelayProvider`) lives on the type the user actually writes against instead of being scattered across overloads. Also renames `RetriableException` → `PCRetriableException`. VERDICT: **Half absorbed.** The rename landed — master has `bz/stub/parallelconsumer/PCRetriableException.java`. The named-interface API did **not**: `origin/master:.../ParallelStreamProcessor.java` still declares `void poll(Consumer<PollContext<K, V>> usersVoidConsumptionFunction)` and `pollAndProduceMany(Function<PollContext<K,V>, List<ProducerRecord<K,V>>>, …)`, and nothing named `PollConsumer`/`Processor`/`Transformer` exists anywhere. This is the \"cohesive Consumer/Function API\" family (draft confluentinc#303) that `docs/refactoring.md` tracks only via `origin/features/consumer-interface` — this branch is unrecorded. Cheap and high-value for docs/UX; source-compatible for lambdas, binary-breaking, so it belongs in the next-major queue."}
- {ref: continuous-encode, tip: 25340f898, state: ours, class: superseded, note: "**Not what the name says.** Despite the branch name, it does *not* carry the continuous-encoding implementation: `git ls-tree` finds no `BitSetFragment` in its tree, and it lacks commit `70d6d51d0 \"START: Continuous Encode - rebase old code from 2020\"`. What it holds is the raw merge snapshot of the 2020 spike into the Oct-2022 tree — a `ContinuousEncodingTests.java` whose test bodies are **commented out**, sitting beside duplicated old-path copies of tests that already existed at new paths. VERDICT: Superseded **within its own cluster** by `continuous-encoding-tests` (which has the working `BitSetFragment` implementation) and `refactor/continuous-encode-22` (which has that plus the run-length rewrite). Caution for the ledger: `docs/refactoring.md` cites `origin/continuous-encode` @25340f89 as \"continuous encoding\" — that citation points at the least complete member of the cluster."}
- {ref: continuous-encode-backup, tip: 3454c3977, state: ours, class: superseded, note: "A sibling snapshot of the same merge, taken at a different moment — neither branch is an ancestor of the other (`git merge-base --is-ancestor` false both directions), and `git diff 25340f898..3454c3977` is 392 insertions / 1163 deletions, almost all in tests and examples. Also carries no `BitSetFragment`. VERDICT: A literal backup copy, named as one. Everything it holds is in `continuous-encode` or the two later branches; the only unique content is a slightly different in-flight test state. Safe to archive-and-delete once the cluster is accounted for; do not mine it separately."}
- {ref: refactor/encode-with-incompletes-direct, tip: fa56ff18a, state: ours, class: open-idea, note: "Stops the encoder scanning the whole offset range. Instead of iterating every relative offset and asking `incompleteOffsets.contains(actualOffset)` for each, hand the encoders the known incompletes directly — RunLength only needs the 0→1 transitions; only BitSet needs the full range. VERDICT: **Not absorbed, and the target is still there verbatim.** `origin/master:.../offsets/OffsetSimultaneousEncoder.java` still carries the TODO this branch attacks — \"*TODO VERY large offset ranges is slow (Integer.MAX_VALUE) — encoding scans could be avoided if passing in map of incompletes which should already be known*\" — plus the second TODO proposing exactly this refactor, immediately above an `invoke()` that still does `range(lengthBetweenBaseAndHighOffset).forEach(...)` over every offset. Recorded in `docs/refactoring.md`. **Genuinely valuable today**: this is on the commit path, and it is a named hot spot for confluentinc#884 (\"PC is 30x slower than the normal consumer\"). The tip is a 21-line spike, so the design is sketched, not done."}
- {ref: continuous-encoding-tests, tip: 56ff2fee8, state: ours, class: open-idea, note: "The working half of the continuous-encoding idea: encode offsets **incrementally as work completes** rather than re-encoding the whole range at each commit, with the BitSet split into fixed fragments (`BitSetFragment` / `BitSetFragmentCollection`) so capacity is ensured at batch-poll time. Commit series `7247f571c \"bitset fragment tests passing\"` through `31dda9185 \"truncate protection for bootstrap phase with no fragments\"` records real serialisation bugs found and fixed (relative-vs-absolute, off-by-one). VERDICT: **Not absorbed** — master has no `BitSetFragment`, no `OffsetEncoderContract`, and `OffsetSimultaneousEncoder.invoke()` still re-encodes the whole range on every call. This is draft confluentinc#46, ranked B5 in `src/docs/development/upstream-pr-analysis.adoc` (\"Aspirational; pairs with #408\"). The branch itself is **unrecorded** — `docs/refactoring.md` cites `continuous-encode` and `-22` but not this one, even though this is where the fragment implementation and its tests actually live. What it would take: it is a full offset-encoding redesign with a wire-format change, so it needs the same care as any encoding change (backward decode of v1/v2 payloads) — but the fragment code is tested and the bug log is in the commit messages."}
- {ref: refactor/continuous-encode-22, tip: 0b98d4ded, state: ours, class: open-idea, note: "The furthest-advanced tip of the continuous-encoding cluster. On top of the BitSet fragments it rewrites the run-length encoder iteratively, and the commit series records the design converging: `5bbffa3da \"far simpler implementation by only tracking positive\"` → `da9135d79/625eac0f4 \"switch back to encoding all info - need to track missing\"` → `0b98d4ded \"split out run length sequence and entry\"`. Explicitly experimental (`START:` on every commit). VERDICT: **Not absorbed** — none of `RunLengthEntry`, `RunLengthSequence`, `BitSetFragment` exists on master. Recorded in `docs/refactoring.md` (with `continuous-encode`) as draft confluentinc#46. **This is the branch to read first** in the cluster: it is a strict superset of `continuous-encoding-tests`, and its commit subjects are an honest log of two rejected designs before the third. Also carries the `Offsets` class, so it doubles as prior art for `refactors/offsets-class`."}
- {ref: feature/health-metrics, tip: 38ed9ade0, state: ours, class: absorbed, note: "First cut at a metrics surface — a `PCMetrics` collector with counters/gauges wired through the state classes and the poller, with no external metrics library. VERDICT: **Absorbed by the micrometer work.** Master has `parallel-consumer-core/src/main/java/bz/stub/parallelconsumer/metrics/PCMetrics.java` and `metrics/PCMetricsDef.java`, `micrometer-core` as a core dependency (`micrometer-core.version` 1.13.15 in the root pom), and the same collection points. It landed upstream as `a5bed3ffd \"PL-79: Feature metrics micrometer (#613)\"`. Master's version is far beyond the draft (registry teardown contract, `removeQuietly`, meter tracking across rebalances)."}
- {ref: feature/micrometer, tip: f31415460, state: ours, class: absorbed, note: "\"Micrometer metrics POC — actually uses a timer and counter\": the health-metrics draft rebuilt on `io.micrometer` primitives. VERDICT: **Absorbed, by the same route as `feature/health-metrics`** — upstream `a5bed3ffd (#613)` shipped micrometer-backed `PCMetrics`, and master's `metrics/PCMetrics.java` imports `io.micrometer.core.instrument.*` including `Timer` and `CompositeMeterRegistry`. This branch is the POC that idea shipped from; nothing on it is missing from master."}
- {ref: features/long-encoding, tip: b2000870e, state: ours, class: open-idea, note: "Adds a **v3** run-length encoding that stores run lengths as `long` instead of `int`: `OffsetEncoding.Version` gains `v3`, with `RunLengthV3(v3, (byte) 'h')` and `RunLengthV3Compressed(v3, (byte) 'i')` — \"switch from encoding run lengths as Integers to Longs to support VERY long continuous run lengths\". The int-to-long *interface* work beneath it is separate. VERDICT: **The v3 encoding is not absorbed; the interface change beneath it is.** Master's `OffsetEncoding` stops at v2 (`BitSetV2`/`RunLengthV2` and their compressed forms) and `RunLengthEncoder.DEFAULT_VERSION = Version.v2` with `case v2 -> Integer.BYTES`; but master *does* have `encodeIncompleteOffset(final long relativeOffset)` and a `RunLengthV2EncodingNotSupported` thrown at `msg(\"Run-length too big for Integer ({} vs max of {})\", …)` — i.e. master has the exact failure mode v3 exists to remove, and no encoding that survives it. This is draft confluentinc#408, ranked B4 in `upstream-pr-analysis.adoc`; the **branch** is unrecorded in `docs/refactoring.md`. Small and self-contained (two enum entries plus a `case v3 -> Long.BYTES` arm), but it is a wire-format addition, so it needs decode-compatibility tests before it can ship."}
- {ref: refactor/minor-changes, tip: 193bbf808, state: ours, class: absorbed, note: "One commit, \"minor: Rename enum to standard pattern\": `State.{unused,running,paused,draining,closing,closed}` → `{UNUSED,RUNNING,PAUSED,DRAINING,CLOSING,CLOSED}`, plus the call sites. VERDICT: **Landed** — `origin/master:.../internal/State.java` declares `UNUSED(0), RUNNING(1), PAUSED(2), DRAINING(3), CLOSING(4), CLOSED(5)` and master's call sites read `State.CLOSED` / `State.RUNNING`. It arrived upstream as `997184d70 \"minor: Fix enum case, tests tweak (#517)\"`. **`docs/refactoring.md` is stale on this in two places**: it lists \"Rename the enum to the standard pattern (public enum rename)\" under *Breaking changes queued for next major version*, and repeats it in the idea bank as \"(breaking; see Breaking changes queued...)\". The rename is already on master, so that queued breaking change no longer exists."}
- {ref: features/least-loaded, tip: 278cc0a5c, state: ours, class: open-idea, note: "Adds a `PCProducerApi.sendToLeastLoaded(ProducerRecord)` user API backed by a `ProduceQueue` VERDICT: Not absorbed. Master has no `PCProducerApi`, `ProduceQueue` or `BrokerProducer`"}
- {ref: features/health-check, tip: 8606377f7, state: ours, class: superseded, note: "21 of its 23 commits are the shared Toxiproxy / broker-disconnect stack (`START: Toxiproxy`, VERDICT: Superseded for the health-check idea. `HealthCheck` is a dangling skeleton -"}
- {ref: refactor/infinite-retry, tip: 80feb470f, state: ours, class: open-idea, note: "Adds `ParallelConsumerOptions.RetrySettings{int maxRetries, FailureReaction failureReaction}` VERDICT: Not absorbed. Master's `ParallelConsumerOptions` has `offsetCommitTimeout`,"}
- {ref: refactor/test-consumer-disconnect, tip: 6a9680740, state: ours, class: open-idea, note: "`refactor/infinite-retry` plus a consumer/broker disconnect-reconnect integration suite - VERDICT: Not absorbed. Master has no `OffsetCommitTest`, no `BrokerDisconnectTest`, and no Toxiproxy"}
- {ref: refactor/controller-extract-base, state: deleted, deleted: 2026-09-03, tip: 540b0b9a5, class: absorbed, note: "Deleted 2026-09-03, owner's call: it was a MARKER for the refactor/control-loop work rather than work itself. No archive tag, and that is the point - its tip is an ANCESTOR of origin/master, zero commits ahead, so every commit stays reachable from master forever and a tag would preserve nothing already permanent. Verified before deleting with git merge-base --is-ancestor. The decomposition it marked is refactor/control-loop; see that entry."}
- {ref: refactor/chaos-broker, tip: 1b9bd385f, state: ours, class: open-idea, note: "`START: refactor into ChaosBroker` - extracts the Toxiproxy plumbing scattered through VERDICT: Not absorbed. No `ChaosBroker` or `PCTestBroker` on master, and no Toxiproxy dependency in"}
- {ref: refactor/chaos-broker-challage-test, tip: c9acb00cd, state: ours, class: open-idea, note: "`refactor/chaos-broker` carried further. Unique tip commit: `chaos broker VERDICT: Not absorbed, same evidence as `refactor/chaos-broker` - master has neither class, and no"}
- {ref: bugs/broker-disconnect, tip: bc620f3b8, state: ours, class: open-idea, note: "The most developed tip of this whole lineage - `ChaosBroker` at its largest, a VERDICT: Not absorbed, and it is already the manifest's recommended starting point:"}
- {ref: refactor/double-ended-queue, tip: 58a2b997d, state: ours, class: open-idea, note: "One commit, `START: Blocking work submission to executor pool instead of block on results`. VERDICT: Not absorbed. No `BlockingExecutor` and no `PCInterruptedException` on master; master still"}
- {ref: refactor/extract-controller, tip: 25db90e38, state: ours, class: open-idea, note: "The God-class decomposition. Pulls the control loop into a `Controller`, the user-function VERDICT: Not absorbed, and the target got worse: master's"}
- {ref: refactor/function-runner, tip: 3fd8caacd, state: ours, class: open-idea, note: "The sub-slice of `refactor/extract-controller` without the `Controller` extraction: VERDICT: Not absorbed - none of these classes exist on master, and `ReactorProcessor` /"}
- {ref: refactor/state-machine, tip: 8f90da8a4, state: ours, class: open-idea, note: "`START: State Machine / closer` on top of function-runner: extracts PC's lifecycle VERDICT: Not absorbed - master keeps lifecycle inside `AbstractParallelEoSStreamProcessor` with an"}
- {ref: refactor/worker-queues, tip: a616de9e9, state: ours, class: open-idea, note: "`refactor/function-runner` pushed further on the pool half only - `PCWorkerPool` grows from 99 VERDICT: Not absorbed; same evidence as function-runner (no `PCWorker*` on master). It is the"}
- {ref: refactor/control-loop, tip: c3a0f28ae, state: ours, class: open-idea, note: "LINKED to docs/refactoring.md, Decompose the God class, registered in the manifest as refactor-thread-model-god-class. This is the tip that got furthest - it compiles, with tests migrated and a review pass - and it cuts along ControlLoop / Controller / StateMachine / PCWorkerPool / WorkMailbox. Naming those matters: the decomposition doc argues about WHETHER to split without recording what a working split actually cut along. refactor/controller-extract-base was a marker for this work and is deleted. The integration branch for the whole decomposition family - merges `refactor/extract-controller` VERDICT: Not absorbed - no `ControlLoop`, `Controller` or `StateMachine` on master. **This is the"}
- {ref: refactor/gpt3-queue-management-with-msg-push, tip: 9ee80ffbf, state: ours, class: spent, note: "A performance spike series on work distribution, on top of `refactor/control-loop`: VERDICT: The experiments recorded their own verdicts and they are negative - the commit immediately"}
- {ref: bugs/fix-incorrect-assume-test, tip: b5d8d2c0e, state: ours, class: open-idea, note: "One functional line. In `offsetCommitsAreIsolatedPerPartition`, changes the guard VERDICT: **Not absorbed, and the defect is live on master.** Master's"}
- {ref: refactor/empty-tests, tip: 5f8b3dbaf, state: ours, class: open-idea, note: "`START: Put back the removed empty tests, to be implemented` - restores four tests that had VERDICT: The removal half landed upstream (confluentinc#493); the restore half did not. Master has"}
- {ref: tests/less-keys-than-threads-broker-test, tip: 9c5cbaef0, state: ours, class: absorbed, note: "Adds `ParallelEoSStreamProcessorTest.lessKeysThanThreads` - KEY ordering, `maxConcurrency(100)`, VERDICT: Absorbed. The unit test is on master verbatim, including the confluentinc#433 javadoc link"}
- {ref: bugs/disabled-tests, tip: 9e5d123ba, state: ours, class: absorbed, note: "`START: Re-enable disabled-tests` - deletes the `@Disabled` annotation from VERDICT: Absorbed. Master's `ParallelEoSStreamProcessorTest` contains **zero** `@Disabled`"}
- {ref: refactor/gpt3-central-queue-direct-pull, tip: 7e775a111, state: ours, class: spent, note: "The continuation of `gpt3-queue-management-with-msg-push`. Adds a central queue facade over the VERDICT: Spent, on its own recorded evidence. The two top commits are the verdict: `Inefficient"}
- {ref: features/consumer-interface, tip: e67833f8d, state: ours, class: open-idea, note: "LINKED to the consumer-API story: astubbs/parallel-consumer#367 (the strategy PR) and its core-alternate-api-facades.md - the adoption ladder, and a KafkaShareConsumer-shaped facade over a classic group. This branch is the 2022 draft of that facade, and it is what MultiTopicTest commented-out assertCommit names in its own source as what it waits for. Read #367 for where the API is going; this branch for what was already built. `big step: introduce fuzzy consumer interface, use interfaces for all APIs` - exposes a VERDICT: Not absorbed. No `ConsumerFacade*`, `PCConsumerAPIStrict` or `ConsumerApiAccess` on master;"}
- {ref: improvements/rebalance-messages, tip: 49e977bf6, state: ours, class: open-idea, note: "Delivers rebalance events to the controller as actor messages instead of mutating shared state VERDICT: Not absorbed - `csid/actors/` does not exist on master and rebalance handling still runs on"}
- {ref: improvements/commit-command-actor, tip: 1c50225e5, state: ours, class: open-idea, note: "`improvements/rebalance-messages` plus the commit seam itself converted to a command actor - VERDICT: Not absorbed. Master still has the two-thread commit seam this was written to remove, and"}
- {ref: improvements/lambda-actor-bus, tip: da7dc92c1, state: ours, class: open-idea, note: "The bus itself, without the rebalance or commit conversions - the \"Micro Actor framework for VERDICT: Not absorbed - no `csid/actors` package on master. This is the *base* of the actor family"}
- {ref: improvements/cache-counts, tip: f99e6b601, state: ours, class: absorbed, note: "Replaces the O(records) scan behind `getNumberOfWorkQueuedInShardsAwaitingSelection` - which at VERDICT: Absorbed, by a different route and a better one. Master's `ProcessingShard` holds"}
- {ref: bugs/prod-tx-manager-retries, state: ours, see: ["docs/inflight/core-241-tx-commit-failure-taxonomy.md", confluentinc#144],
note: "Attached to sweep-2023-tx-failure-taxonomy, and the prototype to start from rather than the older tx-commit-failure branch. Verified 2026-08-20, closing the open question in branch-audit-orphans.md."}
entries:
# ---------------------------------------------------------------------------
# ACTIVE FORK WORK (full entries)
# ---------------------------------------------------------------------------
- id: bug-857-stall-after-rebalance
group: rebalance-stability
summary: Silent stall after rebalance -- the confluentinc#857 family (commit deadlock, rebalance-time commit, drain zombie)
fork:
branches: [bugs/857-paused-consumption-multi-consumers-bug, fix/flaky-partitionstate-committedoffset-it]
prs: [29, 80, 100]
fork_issue: 119
status: in-progress
upstream:
repo: confluentinc/parallel-consumer
prs: [548]
status: merged
last_checked: 2026-08-06
adoc_anchor: part3-cat1-stability
notes: >
confluentinc PR #548 (deadlock between pc-control and pc-broker-poll) is ALREADY
IN this fork: it merged upstream 2023-04-03, its merge commit is an ancestor
of master, and RebalanceEoSDeadlockTest ships with it. Nothing to cherry-pick
-- it is listed here as the upstream half of the same symptom.
Fork state verified 2026-08-04. This is a FAMILY of distinct defects behind
one upstream symptom, not a single fix -- three fork PRs so far:
(1) PR #29 [OPEN, draft, base master-confluent, 57 behind]: the original
synchronized(commitCommand) deadlock between poll thread
(onPartitionsRevoked) and control thread (commitOffsetsThatAreReady),
replaced with ReentrantLock.tryLock(); chaos pass rate ~20%->~80%.
(2) PR #100 [MERGED 2026-08-03]: an unhandled RebalanceInProgressException
from a commit landing mid-rebalance escaped BrokerPollSystem.controlLoop()
and permanently killed the broker-poll thread; the commit is now deferred
and waiters released.
(3) PR #80 [MERGED 2026-08-04, bd717241]: ConsumerManager.shutdownRequested shadowed
BrokerPollSystem.runState, so consumer.poll() was never called while
draining -- a ~10kHz busy-spin plus a rebalance-unresponsive member holding
its whole assignment until eviction. Fixed by deleting the duplicated flag.
Verified independent of #29/#31 (uber-branch composition experiment: all
guards green, zero conflicts).
confluentinc PR #548 addressed the same deadlock as (1) but is CLOSED
(unmerged); related issue #541 now CLOSED. User still weighing a larger
poll+control single-thread refactor to kill the whole bug class.
- id: bug-833-commit-response-timeout
group: rebalance-stability
summary: "\"Timeout waiting for commit response\" is a symptom of a dead broker-poll thread -- report the real cause"
fork:
branches: []
prs: [204]
fork_issue: 177
status: merged
upstream:
repo: confluentinc/parallel-consumer
issues: [833]
prs: []
related: [857, 803, 809]
status: open
last_checked: 2026-08-20
adoc_anchor: part3-cat1-stability
notes: >
ON RELEASE, say on the mirror that the reported message itself CHANGES: anyone
searching for the old "Timeout waiting for commit response PT30S" string will not
match what the fixed version emits, and PT30S was never real anyway (see below).
Verified 2026-08-05 that #100/#108 do fix the reported
TRIGGER (a rebalance-time commit rejection killing the poll thread), and that
the fix is unreleased. But the misleading SYMPTOM was never addressed: every
other way of killing that thread still produced the same message, which names
neither the failing subsystem nor the failure. This work reports the poller's
real exception on the commit-failure path, corrects the timeout the message
quotes (it interpolated a hard-coded 30s constant regardless of configuration,
so the reporter's "PT30S" was meaningless), and makes
ConsumerManager.commitSync's retry budget cumulative rather than per-attempt --
it reset every attempt, so a permanently-failing commit retried forever instead
of surfacing, stranding the poll thread and producing the same symptom from the
broker-down direction.
- id: bug-859-pcmetrics-leak
group: metrics-observability
summary: PCMetrics memory leak -- registeredMeters (List) accumulated duplicate Meter.Id (fix - List to Set)
fork:
branches: [fix/859-metrics-leak-plus-cherrypicks, bugs/859-pcmetrics-leak-v2]
prs: [57]
fork_issue: 120
status: merged
upstream:
repo: confluentinc/parallel-consumer
prs: [892]
status: mixed
last_checked: 2026-07-28
adoc_anchor: part3-cat3-observability
reconciliation:
status: resolved
last_checked: 2026-07-28
note: >
RESOLVED (2026-07-28, investigated the merged diff + fork tree). #892
(priesus, MERGED 2025-10-27) hoists OffsetMapCodecManager to a single `om`
field on PartitionState, created once in the ctor instead of `new` every
commit. That change is ALREADY IN THE FORK -- on master (PartitionState.java,
grep `private final OffsetMapCodecManager<K, V> om;` for the field and
`this.om = new OffsetMapCodecManager<>(pcModule);` for the ctor init) and therefore in PR
#57's base. NO CONFLICT: our #859 fix is complementary and layered on top
-- it USES #892's `om` field, and separately fixes the real leak source in
PCMetrics.java (registeredMeters List -> LinkedHashSet to stop duplicate
Meter.Id accumulation, + a synchronized removal that also prunes the
tracking set). #892 cuts the churn; our fix stops the collection growing.
BUILD-BREAK question: the fork's green, snapshot-published master carries
#892, so the author's 2025-10-28 "broke master build" was the
io.stubbs.truth dependency-availability issue (astubbs, 2026-04-14), not a
code regression. Remaining gap is UPSTREAM-ONLY: upstream merged just #892,
not our tracking-collection fix, so confluentinc#859 stays open (status
mixed); downstream it is fixed by #892 + PR #57 together.
notes: >
Commit-driven leak: registeredMeters (an ArrayList) accumulated a duplicate
Meter.Id on every registration (every commit), even for identical tags --
96% of heap after days. Fork PR #57 fixes it two ways: PCMetrics
List -> LinkedHashSet + prune on removal (the reporter's own suggested fix),
and PartitionStateManager caches the OffsetMapCodecManager instead of a
throwaway per assignment (also closes #233). Touches PCMetrics.java,
PartitionStateManager.java; regression test PCMetrics859Test.java + P1
hardening. PR #57 also bundles cherry-pick #905 (max-shard metric), which is
NOT part of the leak fix. It bundled #893 (PartitionState offset accuracy)
too until 2026-08-24, when that was split out into fork PR #337 so the fix
and its reproduction got their own review; see cherry-pick-893-offset-reset,
which is the carrier of record.
Supersedes closed fork PR #45. confluentinc#892 already fixed the per-commit
OffsetMapCodecManager churn (see reconciliation).
- id: cherry-pick-893-offset-reset
group: rebalance-stability
summary: Accurate committed offset on partition assignment (carried upstream PR)
fork:
branches: [fix/121-offset-accuracy-on-assignment, cherry-pick/893-offset-reset, upstream-pr-893]
prs: [337]
fork_issue: 121
status: merged
upstream:
repo: confluentinc/parallel-consumer
prs: [893]
status: open
last_checked: 2026-08-24
adoc_anchor: part1-group-a-correctness
notes: >
Cherry-pick of upstream contributor PR #893 (sangreal) -- fixes an offset
reset on rebalance AND a silent record-loss mode sharing its root cause,
the second of which no bug report describes. Approved upstream by
rkolesnev 2025-11-17, still OPEN (unmerged there).
Applied-Upstream: no (this IS the upstream PR).
Carried in fork PR #337. It was in #57 until 2026-08-24, when it was split
out so the fix and its reproduction get their own review rather than
riding inside a metrics PR.
Issue #894 ("Offset reset when frequent rebalancing") is named in #893's
own body; this entry recorded issues: [] until 2026-08-04.
Reproduction and diagnosis:
docs/solutions/logic-errors/commit-offset-read-twice-shifts-every-encoded-incomplete-offset.md
- id: cherry-pick-905-max-shard-metric
group: metrics-observability
summary: Max-queued-records-per-shard metric (carried upstream PR)
fork:
branches: [cherry-pick/905-max-shard-metric, upstream-pr-905]
prs: [57]
status: merged
upstream:
repo: confluentinc/parallel-consumer
prs: [905]
status: open
last_checked: 2026-07-28
adoc_anchor: part1-group-b-features
notes: >
Cherry-pick of upstream contributor PR #905 (flashmouse). Small,
self-contained; helps diagnose hot-key shards with orderType.KEY.
Carried downstream, bundled into fork PR #57.
- id: fix-909-stale-container
group: rebalance-stability
summary: Replace stale work container on rebalance (regression test + carry)
fork:
branches: [fix/909-stale-container-replacement]
prs: [31]
status: merged
upstream:
repo: confluentinc/parallel-consumer
prs: [909]
status: open
last_checked: 2026-08-19
adoc_anchor: part1-group-a-correctness
notes: >
confluentinc PR #909 (cserspring) replaces stale containers rather than
rejecting new ones, preventing record drops on rebalance. Upstream PR had no
tests; the fork carry adds four, every one proven RED against the pre-fix
behaviour, one of them driving the defect through the real registration path
rather than around it. Fork PR #31 merged 2026-08-19, with cserspring's
authorship preserved on the fix commit; it also narrows both addWorkContainer
overloads to package-private and documents the three staleness checkpoints in
PartitionState#epochIsStale. A deterministic broker-level reproduction
(RegistrationRaceStaleResidentIT) followed in a separate PR; why chance-based
chaos load could never find the race is recorded in
docs/solutions/logic-errors/909-needs-a-saturated-pipeline-the-third-precondition-2026-08-19.md.
LIKELY ALSO EXPLAINS fork issue 183 (confluentinc#875), assessed 2026-09-01 and
recorded in that issue's thread: its reporter describes the same signature -
one offset never received while neighbours complete, the committed offset pinned
there, lag climbing, a restart seeking back and processing it - and the defective
addWorkContainer is identical in the 0.5.3.1 both were filed against. Not asserted
as a duplicate: it turns on whether that reporter's consumer was rebalancing and
saturated in the window, which only they can answer. Supersedes the
confluentinc#857 attribution the mirror inherited from a third-party comment.
- id: java-17-baseline-kafka4
group: java-baseline-kafka4
summary: Java baseline bump + Kafka 4 support (0.7.x)
fork:
branches: [feat/java-17-baseline]
prs: [53]
status: in-progress
upstream:
repo: confluentinc/parallel-consumer
prs: [866, 920]
status: open
last_checked: 2026-07-28
adoc_anchor: part3-cat5-jdk
notes: >
0.7.x line. The only reason to move off Java 8 is Kafka 4 (kafka-clients
4.x require Java 11 -- target baseline Java 11). PR #53 is a DRAFT holding
a provisional Jabel-removed / release=17 state plus Kafka 4 research docs.
Does NOT address confluentinc#862 (cannot run on Java 24) - that is a runtime
question about what the shipped Java 8 jar can run on, settled by kafka-clients
3.9.1, and it is owned by java-24-security-manager-removal. The two only look
alike because both say "Java". confluentinc PR #866 bumps
Kafka to v4 (NOTE: .adoc previously said v7 -- stale). confluentinc PR #920
(found by the 2026-07-28 sweep) documents the JDK 17 build requirement +
Jabel Java 8 bytecode -- overlaps our Java-baseline framing; compare before
landing our own. Branch is stale: 1 ahead, 57 behind master (2026-08-04).
Also gates fork PR #38 (JUnit 6 needs Java 17, plus an ArchUnit engine that
does not exist yet -- TNG/ArchUnit#1556).
- id: mdc-context-propagation
group: logging-ux
summary: Caller's SLF4J MDC is not propagated into the worker pool or the engine threads
fork:
branches: [feat/mdc-context-propagation]
prs: [205]
fork_issue: 195
status: merged
upstream:
repo: confluentinc/parallel-consumer
prs: []
status: open
last_checked: 2026-08-06
adoc_anchor: null
notes: >
A separate, concrete finding raised by a user inside the confluentinc#907
thread -- distinct from the "is this still maintained?" question that
thread is mostly about. Tracked here rather than only in the mirror
because it carries real fork work; astubbs#195 is the mirror of
confluentinc#907 and holds the discussion.
PC set only its own pcId/offset keys and never called
MDC.getCopyOfContextMap()/setContextMap(), so a caller's trace_id /
request_id was lost crossing into the worker pool, and again crossing
into vert.x / Reactor / Mutiny. Fixed by MdcPropagation +
ParallelConsumerOptions.propagateMdc (default true -- signed off by the
maintainer at merge prep on astubbs#205, so settled; the residual pinning
risk and the reasoning behind the default are on that option's javadoc).
Also fixes a pre-existing leak: whatever the user function put into the
MDC stayed on the pooled thread for the next, unrelated, record.
A backlink comment on confluentinc#907 is worth posting only once this
releases, and should be a reply about the MDC finding specifically --
not a duplicate of the fork-awareness comment.
- id: upstream-pr-915-batch-strategy
group: features
summary: Select batch construction strategy (closes confluentinc#266)
fork: {branches: [], prs: [], status: none}
upstream: {repo: confluentinc/parallel-consumer, issues: [266], prs: [915], related: [551, 560], status: open, last_checked: 2026-07-28}
adoc_anchor: part1-group-b-features
notes: Most valuable user-facing feature in the queue; needs architectural review.
- id: upstream-pr-908-virtual-threads
group: features
summary: Support Virtual Threads (JDK 21+); synchronized -> ReentrantLock
fork: {branches: [], prs: [], status: none}
upstream: {repo: confluentinc/parallel-consumer, issues: [896, 78], prs: [908], related: [299, 862], status: open, last_checked: 2026-08-20}
adoc_anchor: part1-group-b-features
notes: >
Sequence behind the Java baseline branch. The earlier claim that the ReentrantLock
migration may also help confluentinc#862 is REFUTED (2026-08-20): this PR removes
virtual-thread pinning on synchronized, JDK 24 removed pinning anyway, and
confluentinc#862 was a kafka-clients SASL callback calling a Subject API that the
JDK withdrew. Different mechanism entirely. Fork PR astubbs#51 carries this work and
neither blocks nor closes astubbs#181. See java-24-security-manager-removal.
- id: upstream-pr-866-kafka-v4
group: deps-major
summary: "BREAKING: update Kafka to v4"
fork: {branches: [], prs: [], status: none}
upstream: {repo: confluentinc/parallel-consumer, issues: [], prs: [866], related: [], status: open, last_checked: 2026-07-28}
adoc_anchor: part1-group-c-major-deps
notes: Ties into java-17-baseline-kafka4. Title is v4 (the .adoc's "v7" was stale).
- id: upstream-pr-867-vertx-v5
group: deps-major
summary: "BREAKING: update vertx to v5"
fork: {branches: [], prs: [], status: none}
upstream: {repo: confluentinc/parallel-consumer, issues: [], prs: [867], related: [897], status: open, last_checked: 2026-07-28}
adoc_anchor: part1-group-c-major-deps
notes: Duplicate PR #897 (vertx 4.5.7->5.0.5) should be closed in favour of this.
- id: upstream-pr-901-licence-check
group: build-tooling
summary: Fix failing licence check + gitignore (unblocks CI)
fork: {branches: [], prs: [], status: none}
upstream: {repo: confluentinc/parallel-consumer, issues: [861], prs: [901], related: [], status: open, last_checked: 2026-07-28}
adoc_anchor: part1-group-e-housekeeping
notes: Prerequisite/unblocker -- promote to Group A priority.
- id: upstream-pr-security-batch
group: deps-security
summary: Security CVE dependency bumps (kafka-clients, postgresql, assertj, logback)
fork: {branches: [], prs: [], status: none}
upstream: {repo: confluentinc/parallel-consumer, issues: [], prs: [917, 851, 913, 914], related: [], status: open, last_checked: 2026-07-28}
adoc_anchor: part1-group-d-security
notes: >
#917 kafka-clients 3.9.2 (runtime, SECURITY -- found by the 2026-07-28 sweep),
#851 postgresql 42.7.11 (runtime, medium), #913 assertj 3.27.7 (test, low),
#914 logback 1.5.34 (runtime logging, medium). Merge as one batch once green.
- id: upstream-pr-dep-bumps
group: deps-routine
summary: Routine / test dependency bumps
fork: {branches: [], prs: [], status: none}
upstream: {repo: confluentinc/parallel-consumer, issues: [], prs: [855, 899, 900, 897, 869, 898, 854, 877], related: [], status: open, last_checked: 2026-07-28}
adoc_anchor: part1-group-e-housekeeping
notes: >
#855 wiremock v3 (test), #899 junit-platform 6.0.0 (likely-wrong target,
close/pin), #900 testcontainers, #897 vertx dup of #867, #869 threeten,
#898 maven-gpg-plugin, #854 renovate batch, #877 service-bot config.
# ---------------------------------------------------------------------------
# UPSTREAM ISSUES -- high-value opportunities not primary above
# (light tracked entries; long tail deferred -- see note at end)
# ---------------------------------------------------------------------------
- id: upstream-pr-log-noise
group: logging-ux
summary: Trim noisy user-function / RemovedPartitionState logging
fork: {branches: [fix/log-verbosity-batch, fix/168-commit-error-line-keeps-identifiers], prs: [203, 428], fork_issues: [168, 169, 170, 238], status: merged}
upstream: {repo: confluentinc/parallel-consumer, issues: [640, 57, 629], prs: [918, 919], related: [631], status: mixed, last_checked: 2026-09-03}
adoc_anchor: null
notes: >
Found by the 2026-07-28 sweep. #919 trims the user-function error log / moves
full PollContext to DEBUG (fixes #640); #918 trims noisy WARN in
RemovedPartitionState to topic-partition + size + epoch. Low-effort log
cleanup; pairs with upstream issues #629/#631 (adoc Part 3 category 8).
2026-08-07: absorbed upstream #57 ("Reduce debug log output", closed by the
2023-07-07 admin sweep) as the umbrella for this family -- it is the same ask
at lower resolution. Core main sources carry ~224 debug/trace call sites; the
refactor #57 was waiting on (PartitionMonitor -> PartitionStateManager) has
since happened, so its precondition is satisfied. Upstream status now `mixed`:
#640 open, #57 closed-by-sweep.
2026-08-05: the two named lines are fixed on the fork (mirrors astubbs#169 /
astubbs#170) by branch fix/log-verbosity-batch, open as astubbs#203 -- written
independently of #918/#919, which are unmerged upstream and predate this fork's
internals. Both lines now carry a bounded summary
(bz.stub.parallelconsumer.internal.utils.RecordBatchSummary) with the full object
left at DEBUG. The wider #57 umbrella (the ~224 debug/trace call sites) is
untouched, so this entry stays open after astubbs#203 lands.
2026-09-03: astubbs#203 MERGED (2026-09-02) -- this entry had gone on saying
`pr-open` about it, which is the stale-manifest failure docs/upstream.md
describes; corrected here rather than left for a sweep. `pr-open` is now true
of nothing in this entry (203 merged, the 168 branch has no PR yet), so the
status returned to `pr-open` when astubbs#428 opened. Upstream re-checked the same day: #629 and #640 open, #57 closed, so
`mixed` still holds. astubbs#168 /
confluentinc#629 joins the same family on branch
fix/168-commit-error-line-keeps-identifiers: the commit-failure ERROR line in
ConsumerOffsetCommitter keeps every topic/partition/offset and reduces the
per-partition metadata to its length (RecordBatchSummary.summariseCommit), with
the unabridged map moved to DEBUG. #629 moves from `related` to `issues` because
the fork is now acting on it rather than noting it. The deferral WARN siblings in
the same class are handed to astubbs#352 -- see
docs/inflight/bug-deferred-commit-warn-names-no-offsets.md.
2026-09-07: astubbs#428 merged, so no PR in this entry is open and the fork
status is `merged`. Written in the branch rather than after the fact, because
branch content is invisible until it lands and correct the moment it does --
the rule docs/upstream.md states and a gate now enforces. The entry itself is
NOT finished: the #57 umbrella (the debug/trace call sites across core main)
is untouched, and the deferral WARN siblings wait on astubbs#352, so `merged`
describes the fork work that has shipped rather than the family being closed.
- id: issue-402-max-load-factor-log-noise
group: logging-ux
summary: "\"Max loading factor steps reached\" WARN spammed every control loop pass"
fork:
branches: [recut/201-load-factor-noise]
prs: [201]
fork_issue: 155
status: pr-open
upstream:
repo: confluentinc/parallel-consumer
issues: [402]
prs: []
related: [547, 606, 857]
status: open
last_checked: 2026-08-06
adoc_anchor: null
notes: >
Mirrored as astubbs#155. Two halves to the original report: the STALL was
fixed upstream in confluentinc#547/#606 and further in the confluentinc#857
family on the fork (astubbs#119), and is not touched here. This is the LOG
NOISE half only -- checkPipelinePressure() ran the WARN on every control loop
pass with no rate limiting, and a configured messageBufferSize pins the load
factor to its own ceiling so it fired from startup. Fix:
DynamicLoadFactor#isStaticFactor() -> debug for a fixed factor, plus
RateLimiter(30s) and a reworded WARN for a dynamic factor at its cap. No
change to buffering behaviour. The reply to the original reporter is drafted
in docs/inflight/issue-response-155.md and posted by the pre-release sweep,
not at merge.
# ---------------------------------------------------------------------------
# THE 2023 ADMINISTRATIVE SWEEPS
#
# Upstream ran two bulk clearouts before going quiet. Neither was a triage:
# 2023-06-15 eddyv closed 35 unmerged PRs, comment "Closing - Stale."
# (34 of them astubbs'; only #464 had a real reason,
# "superseded by #485")
# 2023-07-07 johnbyrnejb closed 28 issues, comment "Closing Issue", every one
# marked COMPLETED rather than "not planned"
#
# The `completed` state reason is why these never surfaced before: GitHub renders
# them as resolved, so they read as done at a glance and no symptom search finds
# them. Worse, `scripts/upstream-sweep.sh` searches `updated:>=last_swept`, so
# anything last touched in 2023 can NEVER appear in a sweep -- the entire cohort
# was structurally invisible to our own tooling. Seeded by hand on 2026-08-07.
#
# Do not trust the closure state of any 2023-era upstream item. Several of these
# issue bodies claim "Implemented in #NNN" where #NNN was itself swept unmerged
# (e.g. #372 -> PR #390, #319 -> PR #270, #203 -> PR #345, #191 -> PR #346).
# The 2026-08-07 pass verified all 35 swept PR heads reachable, but it only ever checked
# upstream's own refs/pull/<n>/head - it did not ask whether anything on THIS fork contained
# them. The 2026-08-14 containment re-check asked that, and split the cohort: 29 are contained
# by some origin/* branch here, and SIX are contained by no fork ref at all. Those six - not
# the whole cohort - are what the archive tags exist for (their tag and SHA are on the
# matching `branch_accounting` entries above, and the method is in docs/upstream.md). Being contained by a fork branch is not the same as being raised from
# one, and is not permanent: deleting that branch re-orphans the head. Cite branch + SHA, not
# just the PR number - and re-run the containment check rather than trusting this note, which
# is a snapshot.
#
# MIRROR THE WHOLE COHORT, INCLUDING THE ITEMS WE THINK ARE WORTHLESS. The point is
# a clean, known cutoff: "every issue upstream closed administratively is accounted
# for here". Carrying a few items nobody will action costs almost nothing; a set
# filtered by someone's value judgement is no longer a cutoff, and the next person
# cannot tell "not mirrored because it was junk" from "not mirrored because it was
# missed". Fork issues can always be closed later on their merits -- that is a
# decision with a visible record, which pruning before mirroring is not.
# ---------------------------------------------------------------------------
- id: sweep-2023-admin-closure
group: governance
summary: Two upstream bulk closures (2023-06-15 PRs, 2023-07-07 issues) that closed live work as done
fork: {branches: [docs/mirror-2023-admin-sweep], prs: [258], fork_issues: [227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254], status: merged}
upstream: {repo: confluentinc/parallel-consumer, issues: [21, 24, 28, 29, 34, 40, 41, 48, 49, 50, 53, 57, 65, 119, 144, 154, 175, 183, 187, 191, 199, 203, 205, 246, 267, 319, 320, 372], prs: [22, 45, 46, 81, 106, 143, 179, 181, 204, 220, 270, 271, 291, 300, 303, 316, 325, 345, 346, 356, 366, 390, 405, 408, 441, 442, 443, 464, 473, 488, 492, 494, 496, 506, 524], status: closed, last_checked: 2026-08-07}
adoc_anchor: null
# Swept PR heads are pinned as archive/upstream-pr-* tags; the tag/SHA record lives
# once, in `branch_accounting` above, keyed by the branch whose tip each one is.
notes: >
Meta-entry for the cohort; the individual work items follow. All 28 issues were
re-read in full (bodies + all 58 comments) and each verified against fork
source on 2026-08-07 rather than trusted from its thread. Result: 2 genuinely
already fixed (#41, #319), 6 partially addressed (#48, #53, #57, #65, #199,
#203), 20 fully open. Mirrored into the fork tracker under label
`upstream-admin-closed`.
The PR list is exactly the 35 closed on 2023-06-15 and nothing else. Listing a
ref here marks it accounted for, so an unrelated PR added to this cohort would
be hidden from every future audit: confluentinc#66 was carried here in error
(closed 2022-10-19, a different event) and has been removed, which is why the
audit may now report it as untracked.
- id: sweep-2023-already-fixed
group: governance
summary: "Swept issues verified already fixed in fork: #41 offset-scan removal, #319 shutdown CME"
fork: {branches: [], prs: [], fork_issues: [233, 252], status: merged}
upstream: {repo: confluentinc/parallel-consumer, issues: [41, 319], prs: [270], related: [200, 269], status: closed, last_checked: 2026-08-07}
adoc_anchor: null
notes: >
Recorded so nobody re-investigates. #41: findCompletedEligibleOffsetsAndRemove
is gone; PartitionState.incompleteOffsets is a ConcurrentSkipListMap and
getOffsetHighestSequentialSucceeded() is a ceiling() lookup -- exactly the
proposed design. Its own comment still points at upstream #200 for "the
complete correct solution", so the exact variant remains open. #319: the CME
is structurally impossible now -- PartitionMonitor became PartitionStateManager
(#269), partitionStates is a ConcurrentHashMap, and getAssignedPartitions()
collects into a fresh map before any stream. Fixed by a different route than
PR #270, which was itself swept unmerged.
- id: sweep-2023-retry-lifecycle
group: features
summary: Retry expiry, stall detection and scheduled retry -- the unfinished half of the retry epic
fork: {branches: [features/retry-dlq], prs: [], fork_issues: [239, 231, 234], status: none}
upstream: {repo: confluentinc/parallel-consumer, issues: [65, 34, 48], prs: [366], related: [196, 310, 71, 82, 92, 197, 242], status: mixed, last_checked: 2026-08-07}
adoc_anchor: null
notes: >
Epic #65 was closed "completed" with two of five children still open upstream:
#196 (max retries + action on expiry) and #310 (DLQ, already fork-mirrored as
#149). #34 is the stall-detection umbrella; #48 wants a retry-at-time. Fork has
retryDelayProvider and PCRetriableException, but the exception carries no
Duration, so a delay discovered at the throw site cannot be expressed. Decide
the precedence order (exception > provider > default) ONCE across all four.
Draft of both remaining children: PR #366 astubbs/features/retry-dlq @e5bf77c9b.
- id: sweep-2023-api-shape
group: features
summary: "Per-topic handlers and separate consume/produce types -- one breaking API change, not two"
fork: {branches: [], prs: [], fork_issues: [243, 254], status: none}
upstream: {repo: confluentinc/parallel-consumer, issues: [175, 372], prs: [390], related: [50], status: closed, last_checked: 2026-08-07}
adoc_anchor: null
notes: >
#175 (BDeus): ParallelStreamProcessor<K,V> shares one type pair between consume
and produce -- accepted upstream as "a breaking issue for the poll and produce
use case", labelled blocker, never fixed. #372: per-topic processing functions;
its body claims "Implemented in #390" but PR #390 was swept UNMERGED
(astubbs/features/streams @e2f1d53e4, recoverable). These want designing
together: per-topic handlers pay off precisely when topics carry different
types, which is what #175 blocks. Both are breaking -> major release.
- id: sweep-2023-consumer-api-exposure
group: features
summary: seekToBeginning and post-start subscription changes, both blocked on API thread safety
fork: {branches: [], prs: [], fork_issues: [246, 245], status: none}
upstream: {repo: confluentinc/parallel-consumer, issues: [191, 187], prs: [346], related: [186, 520, 782], status: mixed, last_checked: 2026-08-07}
adoc_anchor: null
notes: >
Same blocker as fork mirrors #158 (upstream #520) and #174 (upstream #782):
KafkaConsumer is single-threaded, so any user-facing seek/subscribe must be
marshalled onto the poll thread. Upstream #186 (thread-safe APIs) is still
OPEN. Today PC.subscribe() writes straight to the raw consumer with no lock
while BrokerPollSystem polls it. #191's reporter (fowlerp-qlik) and a second
user (rrva) never got a working example of the shutdown/reseek workaround.
Implementation exists: PR #346 astubbs/features/consumer-interface @e67833f8d,
described upstream as working and used in experimental tests. Whoever picks up
#158 should close #174, #187 and #191 with it.
- id: sweep-2023-null-key-ordering
group: features
summary: "KEY ordering serialises all null-key records into one shard (live defect)"
fork: {branches: [], prs: [], fork_issues: [244], status: none}
upstream: {repo: confluentinc/parallel-consumer, issues: [183], prs: [], related: [], status: closed, last_checked: 2026-08-07}
adoc_anchor: null
notes: >
rjoly-qlik, 2022-01: ~95% null-key order-independent traffic serialised because
KEY ordering treats null as a real key. NEVER RECEIVED A REPLY before being
closed as "completed". Mechanism confirmed in fork source:
ShardKey.KeyWithEquals.equals returns true when both keys are null (with a
matching hashCode branch), so every null-key record in a topic-partition maps
to one shard. Fix: key the unordered case by record offset (already unique
within the partition) behind an option defaulting to today's behaviour --
parallelising silently would be a correctness change for anyone relying on it.
- id: sweep-2023-async-produce
group: features
summary: Consume-process-produce still blocks on producer acks
fork: {branches: [improvements/async-process-send-results-using-actor], prs: [], fork_issues: [230], status: none}
upstream: {repo: confluentinc/parallel-consumer, issues: [29], prs: [356], related: [], status: closed, last_checked: 2026-08-07}
adoc_anchor: null
notes: >
ProducerManager.produceMessages() returns futures, but ParallelEoSStreamProcessor
immediately drains them with futureSend.get(sendTimeout). The source comment
naming PR #356 is still in the tree. Needs work-unit limbo state + back pressure
so producer timeouts do not feed themselves. Interacts with the produce lock in
PERIODIC_TRANSACTIONAL_PRODUCER: async produce changes when a commit cycle may
safely begin. Draft: PR confluentinc#356, branch
improvements/async-process-send-results-using-actor @00f350166 (2026-08-17: the
2026-08-07 note recorded the branch name without its -using-actor suffix and a
SHA, a89f0bce2, that is not the tip; corrected against origin). The conversion
is built on the actor framework -- see sweep-2023-actor-ipc.
- id: sweep-2023-actor-ipc
group: rebalance-stability
summary: "Micro actor / mailbox IPC framework and its call-site conversions (2022 drafts, swept 2023-06-15)"
fork:
branches: [improvements/lambda-actor-bus, improvements/commit-command-actor,
improvements/poller-bus-actor, improvements/actor-scheduled,
improvements/transactions-dont-block, improvements/scheduled-commit,
improvements/remove-commit-queue]
prs: []
status: none
upstream:
repo: confluentinc/parallel-consumer
prs: [325, 524]
related: [356, 200, 488]
status: closed
last_checked: 2026-08-17
adoc_anchor: null
notes: >
Added 2026-08-17: until this entry, confluentinc#325/confluentinc#524 appeared
only inside sweep-2023-admin-closure's bulk PR list, so the branch family was
invisible to every audit. The framework proper (Actor/ActorImpl +
FunctionWithException + Interruptible, io.confluent.csid.actors) is 537 lines
across 4 files whose only PC coupling is the 16-line MultithreadingAPI marker
interface -- structurally separable from the God-class rewiring the branches
also carry. Two unreconciled actor bases exist (poller-bus-actor commit
d391398f1: "needs unifying of the two actor classes"); lambda-actor-bus's
interface is a strict superset of poller-bus-actor's, verified by diffing both
2026-08-17. The async-produce conversion branch is tracked by
sweep-2023-async-produce; transactions-dont-block depends on this framework.
Editorial verdicts under review: docs/refactoring.md "Actor / IPC message bus"
section and upstream-pr-analysis.adoc Group C. upstream remote also carries
refactor/actor-base-fixes (review fixes on the wiring, no csid/actors files;
content contained in origin refs).
- id: refactor-thread-model-god-class
group: rebalance-stability
summary: "Shared-nothing thread model (confluentinc#200) and God-class decomposition (confluentinc#488) -- the branch graveyard, registered"
fork:
branches: [massive-refactor, refactor/state-machine, refactor/extract-controller,
refactor/controller-extract-base, refactor/control-loop,
refactor/infinite-retry, refactor/function-runner,
improvements/interrupt-reason, improvements/rebalance-messages]
prs: []
fork_issue: 142
status: none
upstream:
repo: confluentinc/parallel-consumer
issues: [200]
prs: [488, 270, 271]
related: [186]
status: mixed
last_checked: 2026-08-17
adoc_anchor: null
notes: >
Added 2026-08-17 by the same branch audit as sweep-2023-actor-ipc: the work
group existed only in docs/refactoring.md (which stays the editorial owner --
this entry is the fork<->upstream registration). confluentinc#200 and
confluentinc#186 verified still OPEN upstream 2026-08-17; PRs
confluentinc#488/confluentinc#270/confluentinc#271 closed unmerged in the
2023-06-15 sweep. refactor/controller-extract-base @540b0b9a5 was in no
tracking doc at all until this entry (its sibling refactor/extract-controller
was). Killing the poll/control split would remove the confluentinc#857
deadlock class -- see bug-857-stall-after-rebalance.
- id: sweep-2023-tx-failure-taxonomy
group: rebalance-stability
summary: Transaction commit failures are classified, but not by Kafka's own taxonomy and with no budget
fork: {branches: [bugs/prod-tx-manager-retries, tx-commit-failure], prs: [], fork_issues: [241], status: none}
upstream: {repo: confluentinc/parallel-consumer, issues: [144], prs: [355], related: [112], status: closed, last_checked: 2026-08-20}
adoc_anchor: null
notes: >
SUPERSEDED PREMISE - both the issue and this entry's earlier note claimed one
generic retry loop treating every failure identically. That has been false since
confluentinc#355 (2022-09-29) replaced catch(Exception) with
catch(TimeoutException | InterruptException) plus a classifying comment block;
everything else now fails fast. What is genuinely open: the retry set contradicts
Kafka's own marker in both directions (TimeoutException IS a RetriableException,
InterruptException is NOT and is retried anyway without honouring the interrupt);
arbitrarilyChosenLimitForArbitraryErrorSituation is a count rather than a time
budget, and astubbs#204's offsetCommitTimeout covers only the consumer path, so
transactional mode has no user-visible commit budget; the retry arm can set
committed = true without having committed; and nothing tests any of it in any
module. Fencing also reaches the supervisor by two routes with two types - wrapped
PCInternalRuntimeException from sendOffsetsToTransaction but RAW from
commitTransaction - and astubbs#225 knows only the first. Start from
bugs/prod-tx-manager-retries (RetrySettings/FailureReaction, PCCommitFailedException,
PCTimeoutException), NOT tx-commit-failure, which is a 2021 WIP superseded by
confluentinc#355. That resolves the verify-before-attaching question in