Release candidate qualification
This record is the contract for the next promoted release candidate. It gives the procedure that freezes a candidate, the gates that must pass on that exact candidate, and the proposed list of release blockers. Issue #1401 owns it.
This record does not authorize a release. It does not tag, sign, publish or
promote anything. Releasing is the release procedure, and it
stays unchanged: a candidate that passes every gate here is released by that
procedure, from a vX.Y.Z tag on main.
Status, 2026-10-25. v1.0.6, v1.0.7 and v1.0.8 are released, and all
three contain #1540.
All three pass aspect verify-release with no problems, so the condition of
blocker B1 is met. The proposed next ecosystem candidate is v1.0.8 at
3831a25d, tag object b4f543b4, with the amd64 delivery image
sha256:960d3ad1…. Its protocol dependency is 0.7.0 at 1b282837, its Rust
client 0.7.1 at ba3443d0, and its schema registry 0.4.3 at ac4fe56e. The
draft manifest ecosystem-v1.0.8.json
and the proposed freeze record
candidate-freeze-3831a25d-proposed.json
wait for maintainer review. Freezing is the maintainer’s decision. The CLI,
operator and website components of the draft still carry their baseline
values, and the review must set them. Until a candidate is frozen, no run
here is candidate evidence. The remaining qualification runs are scheduled
with the 1.1 release
qualification.
The eight-gate preflight exposed failures in single-node transaction configuration, CLI admin response handling and topic configuration, audit placement during operator evacuation, and the schema adapter’s test ownership. Those fixes are merged in the website, CLI and broker. Broker #1573 also moves feature validation before recovery writes, so the loaded lifecycle uses the startup-safe v1.0.6 baseline. Every gate must run again on the final candidate; preflight passes do not qualify v1.0.8.
The cloud qualification workflow provides the performance and 72-hour soak workers. Independent pilot acceptance still requires the named human operators and results in the pilot plans.
Release and ecosystem claims
Krabka makes two separate claims, as Releasing and Ecosystem qualification say:
- A broker release is a signed image and a GitHub release for a commit
whose
mainCI run passed. This claim alone does not qualify an ecosystem. - An ecosystem-qualified stack is a broker release whose frozen candidate passed every gate in Candidate gates, with the sibling set that the candidate manifest names.
Describe a stack as ecosystem-qualified only when every gate below passed on
the frozen candidate and every agreed release blocker is closed. A partial
pass, an older run, or a run on another revision is not enough. On
2026-10-25 no 1.x release is ecosystem-qualified. The last qualified stack is
krabka-broker v0.6.1 with the sibling set in
ecosystem-eight-gate-baseline.json.
Freeze a candidate
A candidate is three things that must not move while it is qualified:
- The krabka-broker commit. It is on
main, and itsci.ymlpush run passedgate. - Every sibling revision that the commit’s
[patch.crates-io]block pins. These revisions are compiled into the image. - The amd64 image digest that
deliveryrecorded for the commit, in thedelivery-imageartifact of that run. The artifact expires after 90 days.
Do these steps in sequence:
-
Pick the commit. Its
ci.ymlpush run must besuccess. Get that run’sdelivery-imageartifact:run="$(gh api "repos/krabka-io/krabka-broker/actions/workflows/ci.yml/runs?head_sha=${COMMIT}&event=push" \ --jq '[.workflow_runs[] | select(.conclusion == "success")][0].id')" artifact="$(gh api "repos/krabka-io/krabka-broker/actions/runs/${run}/artifacts" \ --jq '.artifacts[] | select(.name == "delivery-image") | .id')" gh api "repos/krabka-io/krabka-broker/actions/artifacts/${artifact}/zip" >delivery-image.zip unzip -o delivery-image.zip -
Freeze the commit, the pins and the digest. The task checks the digest against the registry, and lists each component of the manifest whose revision is not the pin that the image compiles in:
aspect freeze-candidate --commit "${COMMIT}" \ --delivery-digest delivery-image.digest \ --manifest qualification/ecosystem-eight-gate-baseline.json \ --output candidate-freeze.json -
When the task prints a
DRIFTline, write a reviewed candidate manifest. Start it withaspect check-qualification --new-candidate, and set every component to its pinned revision and to the artifacts built from that revision. The workflow’sbroker_revisionandbroker_digestoverrides replace the broker component only. With drift, they describe siblings that the image was not built from. -
Commit the candidate manifest and the freeze record under
qualification/in one pull request. From that merge on, every gate below runs against these values and no others. -
Rebuild nothing. A fix to a blocker makes a new commit, and a new commit is a new candidate. Start again at step 1, and run every gate again.
The dry run of these steps on 948e3cc8 is in
candidate-freeze-948e3cc8-dry-run.json.
It is not a candidate. It was written by the schema 1 task, which compared
every [patch.crates-io] pin with the manifest, so it lists all ten pinned
siblings as drift. Seven of them, krabka-gateway among them, are patches that
nothing in the dependency graph uses: Cargo.lock keeps them under
[[patch.unused]], and the image does not contain them. The task now records
them as unused_patches and compares only the siblings that the image compiles
in. Those are krabka-protocol, krabka-client-rs and
krabka-schema-registry, and all three still differ from the qualified
baseline manifest. So the next qualification needs a reviewed manifest that
names those three revisions; the broker overrides alone are not correct.
Candidate gates
Each gate must pass on the frozen candidate. “Needs” names what the run needs
that a pull-request runner does not have. The status column is the state on
main on 2026-10-18, and it is not candidate evidence.
| Gate | Workflow and job, or command | Evidence | Status on main, 2026-10-18 |
Needs |
|---|---|---|---|---|
| Required CI | ci. job gate, on the candidate’s push run. It needs cpd, ci, coverage, supply-chain, cargo, wasm, checks, proofs, select, docker and kubernetes. |
The run, and its delivery-image artifact |
Green on 948e3cc8, run 39058863421. Red on f2305998, run 39053924323: a nextest timeout. 045b10d4 is in progress, and two container groups failed to pull images on the remote executor. |
Nothing extra |
| Creusot proofs | ci. job proofs |
The job log | Green on 045b10d4, run 39165644154 |
Docker on the runner |
| Stateright models | ci. job ci, the model targets of bazel test /, and kraft_ and bucket_ |
The job log | Green on 948e3cc8, run 39058863421 |
Nothing extra |
| Full container matrix, with the Kafka 4.3.1 JVM acceptance suites | ci. job docker on a workflow_ of the candidate commit. A dispatch runs every suite (aspect container-suites with no --base). The apache_ suites include jvm_, jvm_, jvm_, jvm_ and jvm_. |
The run | Red. Nightly run 39114726914 on 948e3cc8: jvm_, librdkafka_ and minio_ failed to build, because image pulls on the remote executor were cancelled. The other groups passed. Issue #1493. |
Docker, remote executor |
| GSSAPI | ci. job gssapi, on the same dispatch |
The run | Green in run 39114726914 | Docker Compose |
| Upgrade from the previous release | ci. job upgrade, on the same dispatch |
The run | Red. Cancelled at its 90-minute limit on 2026-10-16, 10-17 and 10-18. It stops after Records delete operation completed. Before that it failed on 2026-10-13 and 10-14. |
Docker, GHCR read |
| Four-hour soak | ci. job soak, on the same dispatch |
The job log | Red. a_ failed on 2026-10-16, 10-17 and 10-18. On all three brokers the log directory rose by about 4.89 MB over the second half, against an allowance of 4,194,304 bytes. |
Docker |
| Criterion regression lane | ci. job bench, on the same dispatch |
The benchmark-regression-evidence artifact |
Green in run 39114726914 | Nothing extra |
| Regression budgets (#1435) | packaging/ and qualify., on the benchmark host. benchmarks. job performance-budget-contract validates the contract only. |
The results record that Performance regression budgets defines | Not run on a candidate. Two calibration runs of rf3-regression-v1 on main measured the spreads, and the first exceeded two variance budgets. In run 39865512647 at fd007630, rf3-regression-v2 pinned_ passed and before_ exceeded the CPU variance budget. The contract is now rf3-regression-v3, which has no run yet. See Performance budget results and #1395. |
benchmarks. dispatch with budget, on a 32-core cloud worker |
| 72-hour soak (#1393) | The soak_ suite with KRABKA_, then krabka-soak-check judge. Performance qualification gives the commands. |
evidence. and verdict. |
Not run. The five-minute self-check is green on 948e3cc8. The 72-hour run has never run (#1393). |
A 16 CPU, 64 GiB, 500 GiB host for three days |
| Ecosystem qualification, eight gates | qualification. with execute=true and the reviewed candidate manifest. The gates are installation, operator-lifecycle, cli-admin, observability-recovery, disaster-recovery, schema-evolution, registry-migration and snapshot-retention. |
A qualification-<run> prerelease, its manifest., report. and SHA256SUMS |
Not run on any 1.x commit. The last run of all eight gates was run 36293960620 on 2026-09-27, for the v0.6.1 baseline. | Docker, Kind, Helm |
| Recovery (#1397) | The disaster-recovery gate above, plus the declared RPO and RTO, classic and diskless, TLS, SASL and ACL cases that #1397 plans |
The gate bundle, and the #1397 record | Planned. #1397 has no evidence yet. | Docker, MinIO |
| Lifecycle (#1396) | The operator-lifecycle gate and the upgrade job above, plus the loaded rolling upgrade, certificate rotation and reassignment on published digests that #1396 plans |
The gate bundle, and the #1396 record | Planned. #1396 has no evidence yet. | Kind, published images |
| Operator acceptance (#1399) | Independent operators run the migration and recovery plans of #1398 without maintainer help | The operator reports that #1399 names | Planned. No operator is named and no evidence exists. | Pilot access, real hosts |
| Support documents (#1400) | The support matrix, measured envelopes and known limitations that #1400 plans, at the candidate commit | The documents at the tagged commit, pinned by aspect verify-release |
Drafted in the support matrix and the measured envelope. No row is candidate yet, because no candidate is frozen. |
Nothing extra |
| Provenance | aspect verify-release --tag <tag> --delivery-digest delivery-image., after the release |
release-verification. |
Red for v1. to v1.. Green for v1., v1. and v1., which carry the #1509 fix. See Provenance verification. |
cosign 3, Docker CLI, gh |
Since 2026-10-18. The status column above is not current. These runs changed it, and none is candidate evidence:
- Required CI passed
gateatv1.0.8in push CI 39518736364. Onmainat315c2985, push CI 40160834355 failedgate:coveragefailedfeature_finalization_test::validate_only_does_not_persistanddynamic_voters_test::remove_voter_shrinks_quorum. - The full container matrix, GSSAPI, the upgrade lane and the four-hour soak
passed at
v1.0.8in dispatch 39519220181, and atv1.0.7in dispatch 39493788635. - The criterion regression lane failed in both dispatches on a measured
verdict: at
v1.0.8,broker/produce_acks/32part/acks_allat 1.16 times thev1.0.5reference, against a 0.113 tolerance; atv1.0.7,log/read/past_end_returns_emptyat 1.79 times. In the nightlies of 10-22 to 10-24 it failed in its harness, because the cargo log named no bench executable, so no comparison ran. - The regression budgets, the eight gates, recovery and lifecycle are in B8,
B5 and B10. Provenance is green for
v1.0.6tov1.0.8.
Rules for the gates:
- Run every gate on the frozen commit and image digest. A gate that ran on another commit gives no evidence for the candidate.
- Keep every failed run. A failure is a blocker until a later run on a new candidate passes, or the maintainer agrees that the item is a known limitation.
- Re-run a failed job once only to show an infrastructure failure, such as the image pull failures of run 39114726914. A second failure is a real failure.
- Do not skip, disable or ignore a test to make a gate pass.
Provenance verification
release.yml does these steps for a vX.Y.Z tag:
- It gets the amd64 digest from the
delivery-imageartifact of the successfulmainpush run, and checks it against the registry withaspect check-delivery-image. - It builds and pushes the arm64 manifest, and joins both children by
digest into the
vX.Y.Zindex. - It signs the index with
cosign sign, and attests the CycloneDX SBOM withcosign attest --type cyclonedxand the provenance withcosign attest --type slsaprovenance. The identity is the keyless GitHub OIDC identity ofrelease.ymlat the ref that ran it. - It runs
cosign verifyandcosign verify-attestationagainst the index, and uploadssbom.cdx.jsonto the GitHub release.
aspect verify-release repeats these checks from outside, against a release
that exists. It also checks the content of the attestations, and pins the
support documents at the tagged commit:
git fetch origin tag v1.0.5
aspect verify-release --tag v1.0.5 \
--delivery-digest delivery-image.digest \
--output release-verification
# A release that a workflow_dispatch from main re-ran:
aspect verify-release --tag v1.0.0 --identity-ref refs/heads/main
# The support documents must be the bytes an earlier record pinned:
aspect verify-release --tag vX.Y.Z --expected-support candidate/release-verification.json
The task fails when any of these is false:
- The index is signed by
release.ymlunder the identity of the ref that ran it. - The index has one amd64 child and one arm64 child.
- The provenance statement is SLSA v1, its subject is the index, and its predicate names the tagged commit, the tag ref, the arm64 child, and the amd64 child as the tested delivery image.
- The SBOM attestation’s subject is the index, and its predicate is the
release’s
sbom.cdx.jsonasset, compared as JSON. - The amd64 child is the digest of the
delivery-imageartifact, when--delivery-digestis given. - Each support document exists at the tagged commit, and matches the record
that
--expected-supportnames, when one is given.
The support documents are README.md, CHANGELOG.md, SECURITY.md,
docs/persisted_formats.md, docs/format-divergences.md,
docs/KIP_MATRIX.md, docs/config-reference.md, docs/releasing.md,
docs/qualification.md, and every file under docs/operations/. The record
gives the SHA-256 of each one. A page added under docs/operations/ later,
such as the #1400 support matrix, is pinned with no change to the task. To
bind the documents to the delivered bytes, keep the candidate’s record, and
check the release against it with --expected-support. Because the tag
names the commit and the provenance names the same commit and the delivered
digests, a pass ties the documents to the image bytes.
Use cosign 3. cosign 2 finds no signature on these releases, because
sigstore/cosign-installer v4 signs with cosign 3, which stores the
signature as an OCI referrer.
Result for v1.0.5
The task ran on 2026-10-18 against v1.0.5 and v1.0.0. The record for v1.0.5
is release-verification-v1.0.5.json.
| Check | v1.0.5 |
|---|---|
| Index | sha256:2a81d1ba38de4e8ffb032fedf67952845185158a7607ac76ba38fa162dc37e50 at commit ac9deff3 |
| Children | amd64 sha256:8c515d33…, arm64 sha256:303ced00… |
Signature, release. |
Pass |
Signature under another identity (refs/) |
Fails, as it must |
amd64 child against the delivery-image artifact of run 38516831673 |
Pass |
SBOM attestation against sbom. (sha256:c123ba49…) |
Pass |
| Provenance | Fail. Attested as https:/ with an empty predicate ({}) |
| Support documents | 58 documents pinned |
v1.0.0, which a dispatch from main released, gives the same result under
--identity-ref refs/heads/main.
The provenance defect is in release.yml. It writes a SLSA v1 predicate
(buildDefinition and runDetails) but attests it with
--type slsaprovenance. cosign parses that type into the SLSA v0.2 schema, so
every field is dropped, and the statement carries no commit, no ref and no
image source. cosign verify-attestation --type slsaprovenance still passes,
because it checks the signature and the type, not the content. A local
cosign attest-blob test with cosign 3.0.2 shows that the type
https://slsa.dev/provenance/v1 keeps the predicate as written. The fix is
blocker B1 below, in
#1509. It does not change the attestations of v1.0.0 to
v1.0.5, so those releases keep an empty provenance predicate. For them, the release run log and the
delivery-image artifact are the provenance evidence.
Result for v1.0.6, v1.0.7 and v1.0.8
The three releases after #1509 pass. The task wrote
release-verification-v1.0.6.json
on 2026-10-20, and
release-verification-v1.0.7.json
and release-verification-v1.0.8.json
on 2026-10-25 with cosign 3.1.4. Each record has "verified": true and an
empty problems list. The v1.0.7 and v1.0.8 records were run with
--delivery-digest.
| Check | v1.0.6 | v1.0.7 | v1.0.8 |
|---|---|---|---|
| Commit | 402edff3 |
eb7e0c6a |
3831a25d, tag object b4f543b4 |
| Index | sha256:ad519537… |
sha256:9d35b99f… |
sha256:1d0dd0d4… |
| Children | amd64 sha256:26603481…, arm64 sha256:37bcdd52… |
amd64 sha256:7a6075d6…, arm64 sha256:31eb3d9e… |
amd64 sha256:960d3ad1…, arm64 sha256:1b91e636… |
| Release run | 39474117467 | 39501119789 | 39523147617 |
Signature, release. at the tag ref |
Pass | Pass | Pass |
Signature under refs/ |
Not recorded | Fails, as it must | Fails, as it must |
amd64 child against the delivery-image artifact |
Not recorded | Pass, push CI 39493754304 | Pass, push CI 39518736364 |
SBOM attestation against sbom. |
Pass, sha256:6b139a85… |
Pass, sha256:5f935388… |
Pass, sha256:adaaa41d… |
| Provenance, SLSA v1, naming the commit, the tag ref and both children | Pass | Pass | Pass |
| Support documents | 62 pinned | 62 pinned | 62 pinned |
All three tags are on main, and all three contain
#1540, the diskless
restore fix.
Blocker list (proposal)
The maintainer agrees this list on #1401. Each item has one class:
- Release blocker: the candidate cannot be promoted, or described as ecosystem-qualified, until the item is fixed and the fix is verified on a new candidate.
- Known limitation: the release can ship with it, and the support documents (#1400) must state it.
- Not relevant: the item does not affect the candidate.
Release blockers
| ID | Item | Source | Reason |
|---|---|---|---|
| B1 | The provenance attestation has an empty predicate. | This record; release. |
The provenance is the link between the signed index, the commit and the tested image. Fix in #1509: attest with --type https:/, and fail the release unless the statement read back names the commit, the ref and both children. Verified when the next release passes aspect verify-release. Condition met. v1., v1. and v1. each pass with no problems: v1.0.6, v1.0.7 and v1.0.8, and Result for v1.0.6, v1.0.7 and v1.0.8. The maintainer closes the item on #1401. A frozen candidate is still verified after its release, with --expected-support against the candidate record. |
| B2 | The four-hour soak fails: log-directory growth is over its allowance on all three brokers. | ci. soak, 2026-10-06 to 10-18; #1507 |
A resource that rises without bound under steady load is the failure this lane exists to find. The growth was soak-verify, the offsets topic and the metadata log, which Kafka’s defaults do not reclaim within four hours, and the soak now rolls the last two every minute. Rolling them exposed two leaks: compaction left the producer snapshots of the segments it merged, and the metadata log never deleted its retired segments. Fixed in #1537, merged 2026-10-19. The four-hour soak passed on its head 2cf5551f (run 39288583006, 14,412 s). Since then it passed at the v1. commit 3831a25d (job 118958685613, 14,411 s), at eb7e0c6a, and in every main nightly from 10-21 to 10-24. It closes when the soak passes on the candidate. |
| B3 | The upgrade lane stops at its timeout after Delete. |
ci. upgrade, 2026-10-16 to 10-18; #1301, #1389, #1508 |
The upgrade from the previous release is a lifecycle gate, and the #1301 confirmation that #1389 needs had never passed on main. The hang was in packaging/, not in the broker. The script read changelog prose about the on-disk format as a declared format break. It then ran HEAD in the foreground on a directory that HEAD opens normally, so HEAD served until the job limit. Fixed in #1527, merged 2026-10-19: only the **Breaking, on-disk format. marker counts, and every step after the HEAD image build has a time limit. The build itself is bounded only by the job’s 90 minutes. The lane passed on main in the nightly run 39237543947 at e0588325, and in the dispatch run 39288583006. Both upgraded v1.0.5’s volume, read the record back with HEAD and found the raised log start. Since then it passed at v1. from v1. (dispatch 39493788635), at v1. from v1. (job 118958685699), and in every nightly from 10-21 to 10-24, which upgrade from v1.. #1508 is closed. It closes when the lane passes on the candidate. |
| B4 | The full container matrix was not green on the latest commits. | #1493, run 39114726914 | Three groups failed on image pulls, so their Kafka 4.3.1 and librdkafka suites have no result. No container test failed in the eleven nightlies from 2026-10-08 to 10-19, and every red group was infrastructure. The remote executor’s Docker Hub token for ubuntu:22. timed out on 10-18 and in dispatch 39177946645, which #1530 fixed: the image now comes from mirror., and an action that cannot start remotely runs locally. mirror. was missing a blob of apache/ on 10-10, and #1358 added the Docker Hub fallback for it. GitHub answered HTTP 500 for aspect-launcher on 10-12, and BuildBuddy was unavailable for gssapi on 10-19. All 13 groups passed in the nightlies of 10-13, 10-14, 10-16 and 10-17, and in dispatch 39288583006 at 2cf5551f, which has #1530. #1493 is closed. Every container group passed at v1., in push CI 39518736364 and in dispatch 39519220181, and in the nightlies of 10-19 and 10-21 to 10-24. It closes when one full-matrix run is green on the candidate. |
| B5 | Ecosystem qualification has not passed on a 1.x commit, and the baseline manifest does not match the pinned siblings. | Freeze a candidate | The stack cannot be ecosystem-qualified without a run of all eight gates on a manifest that names what the image compiles in. The image compiles in three siblings, not ten: the other seven pins are unused patches, and aspect freeze-candidate now leaves them out of the drift. At the v1.0.8 tag commit 3831a25d, aspect freeze-candidate reports the three as krabka-protocol at 1b282837 (0.7.0), krabka-client-rs at ba3443d0 (0.7.1) and krabka-schema-registry at ac4fe56e (0.4.3), against 05e3e32d, c4c113c7 and 904490ad in the baseline. Each of the three is on its repository’s main, so the workflow’s default-branch check accepts it. None of the three ships an artifact, so the reviewed manifest changes three revisions and rebuilds nothing. The draft is ecosystem-v1., with the proposed freeze record candidate-freeze-3831a25d-proposed., which reports no drift against it. Both wait for maintainer review; the draft is not a frozen candidate. The eight-gate preflight 39446231280 on f5c683d9, a release-branch commit three before v1., passed observability-recovery, registry-migration and snapshot-retention. installation failed on COORDINATOR_ in its Go client check, cli-admin on a SASL connection reset, and operator-lifecycle on a timeout waiting on kafkanodepools/. disaster-recovery and schema-evolution failed in their harness before their checks ran: krabka-cli v0.4.4 refused the krabka. topic config, and the schema check looked for a test name that its suite does not have. A preflight is not candidate evidence. The run on the reviewed manifest is scheduled with the 1.1 release qualification. It closes when qualification. passes all eight gates on the frozen candidate with that manifest. |
| B6 | Fetch in the tiered remote band hangs, and the remote log metadata manager stays Not. |
#1448, reproduced on v1.0.5; #1542 | A Fetch with no response is a correctness defect, and the 72-hour tiered path needs its fix. The hang is fixed in #1538. The remote read now serves the archived segment’s own bytes, as Kafka’s Remote does, so a compressed batch is no longer framed by its uncompressed length. A Fetch while the RLMM catches up now answers the retriable REPLICA_. The Not stall did not reproduce in 11 Docker soak runs with the real follower pause, three of them on the #1448 executor. #1542 is closed, to be reopened if Krabka fires. #1555, merged 2026-10-20, fixes the one hazard found: a slow metadata publish held the lock the RLMM consumer needs, so it stalled catch-up on every metadata partition. #1555 also exports per-partition RLMM readiness (krabka_) and adds the Krabka alert, so a recurrence is visible. Verified when the soak’s tiered path, with its follower pause, reads back every record on the candidate and no RLMM stays Not. |
| B7 | The 72-hour soak has never run. | #1551, #1393, PR #1473 | Sustained correctness under faults is a criterion of M26, which the 1.1 release milestone now carries. The harness is merged (#1473, and the broker fixes its trial runs found: #1485, #1487, #1491). The two fixes #1551 waited on are merged: #1553, a restarted controller keeping its leaderships (#1442), and #1555, the RLMM pump stall. A host that meets the contract’s 16 CPU, 64 GiB and 500 GiB is available, and #1551 holds the run plan. No GitHub-hosted runner can take the run: a hosted job stops at six hours. The netem slow-follower fault had never run, because no kernel the repository tested on had sch_; this sandbox’s kernel is built without it (CONFIG_ is not set). The nightly netem job now runs bench/, the self-check with that fault, on a GitHub-hosted runner after loading the module. Its first run passed in dispatch 39369741872 at 3a4d6483: the runner loaded sch_, and the contract passed in about five minutes. The judge fails a fault that was not injected or not cleared, so the qdisc was added in a follower’s namespace and removed again. The run host must also load sch_, or the first slow-follower fault, at 65 minutes, fails the run. It closes when bench/ runs for 72 hours on the candidate and krabka-soak-check judge passes its evidence. The run is scheduled with the 1.1 release qualification. |
| B8 | The regression budgets have not run on a candidate, and the current contract, rf3-regression-v3, has no run yet. |
#1395, PR #1435 | #1401 asks to repeat performance qualification on the candidate. benchmarks. runs both modes on a gcp-ubuntu-24-04-32core worker when dispatched with budget (#1649), one after the other, so they no longer wait for the soak host. Two before_ runs of rf3-regression-v1 on main calibrated the budgets. The first exceeded the records/s and p99 variance budgets, so, as the calibration rule requires, rf3-regression-v2 raised them before any result was published. The first rf3-regression-v2 dispatch, run 39865512647 on main at fd007630, ran both modes. pinned_ passed, with 90 of 90 trials clean, and is published as a rf3-regression-v2 result. before_ against v1. failed its comparison step on excess variance only: the candidate’s CPU per record in 1k-random-lz4-p12-saturate spread 11.6%, against a 10% budget, with no correctness failure, no missing trial and no material regression. So rf3-regression-v3 raised the CPU variance budget to 15%, by the same rule. Performance budget results records every run and its evidence. Neither mode has run under rf3-regression-v3, and no run used a candidate. It closes when before_ against the previous release and pinned_ both pass under the current contract on the candidate, and their records and verdicts are published there. The before_ rerun under rf3-regression-v3 is scheduled with the 1.1 release qualification. |
| B9 | The OMB max-rate RF3 rerun for COORDINATOR_ has not run. |
#1352, #1389, #1394 | #1389 lists it as a release blocker. #1352 found an Offset answered COORDINATOR_ twice in omb-local-2026-10-11 on v1.0.1, where Kafka 4.3.1 had none: the coordinator’s 5 s _ append timed out with one in-sync follower a record short. Two causes found since are fixed on main: a busy partition starved a follower fetch session (#1410), and retired segment files were unlinked under the log lock, stalling appends and follower reads for up to 0.7 s (#1457). The 5 s timeout matches Kafka’s offsets., and Kafka also answers a timed-out offsets append with COORDINATOR_, so the remaining question is whether a follower still stalls that long; ext4 journal stalls on the run host (#1333) cannot be reproduced elsewhere. The rerun needs that host, an AMD EPYC 4344P with three 4 CPU / 10 GiB brokers, and the local Docker OMB setup the run was published from in krabka-io.bench/ cannot stand in: it runs krabka at RF=1 only. It closes when the two max-rate-1-topic-1-partition RF3 trials run on the candidate with no failed commits, or with each failure explained by the replicator and fetch debug logs and matched by Kafka in the same run. The rerun is scheduled with the 1.1 release qualification. |
| B10 | Recovery, lifecycle and operator acceptance have no evidence on a release image or a candidate. | #1397, #1396, #1398, #1399 | Each is a candidate gate. None is planning only any more, and none has passed on the candidate. Loaded lifecycle (#1396): the loaded lifecycle job passed in qualification run 39172925991, v1.0.5 to main at 948e3cc8 and back on four nodes under load, with 0 of 141,918 acknowledged sends lost and an unsupported rollback refused without damage. It does not cover network partitions, tiered or diskless paths under the lifecycle, or the operator-driven path. Secured DR (#1397): v1.0.5 does not pass; its restore refused a growing archive (#1520). On main at f7d824ab, drill 39328090996 judged dr-secured: PASS with RPO 20.0 s and RTO 21.0 s against 60 s and 5 min, but its job stayed red because a restored diskless partition refused writes (#1524). #1540 fixed that and #1525, and no drill has run on an image with it: the drill needs a main delivery image, and none has been published since #1540 merged. Pilot plans (#1398): pilot-acceptance-plans. defines both plans, and every gap issue they filed is closed. What remains are its human actions M1 to M10: naming the operators, pilot access and consent, and accepting the numbers. Independent operators (#1399): an AI agent’s dry run of the runbooks found six defects (#1512, #1514 to #1517, #1529) and several doc gaps, all fixed on main; it is labeled as not an acceptance run. Acceptance needs operators who did not build krabka. It closes when the loaded lifecycle and the DR drill pass on the candidate, and both pilots, or independent acceptance runs labeled as such, are published. Since 2026-10-20: drill 39375286339 judged dr-secured: PASS on the main image of 7301120, which has #1540, with RPO 19,980 ms and RTO 23,839 ms, and all 51 checks passed, the restored diskless partition’s authenticated round trip among them. The loaded lifecycle passed again at f5c683d9, from v1. and back, with 0 of 141,412 acknowledged sends lost (job 118708771194). Neither is a release image or a candidate. The DR drill and the loaded lifecycle on release images, and the operator pilots, are in the 1.1 release milestone and are scheduled with its qualification. |
| B11 | The support matrix and the known limitations name no candidate. | #1400, support matrix | #1401 depends on it, and aspect verify-release pins it. The page is published (#1505), and aspect check-support-matrix fails a row without evidence or a revision. On 2026-10-20 it read: the loaded upgrade and rollback rows are historical at 948e3cc8, secured DR is failing at f7d824ab pending a drill with #1540, the 72-hour and diskless-under-load rows point at #1551, and #1442 and #1448 have left the open defects. Every executed row is historical, because no candidate is frozen. It closes when the candidate revision is set on the page and each row is either candidate, with its check passed on that revision, or an accepted gap. On 2026-10-25 the page cites the v1. dispatch 39519220181 for every row it ran, secured DR is historical at 7301120, the loaded lifecycle rows are historical at f5c683d9, and the main hermetic suites at 315c2985, krabka-operator on Kind and the 1.x eight gates are failing. Every passing row is still historical. |
| F1 | Flake: txn_ creates a topic while its two-voter controller quorum has no leader. |
main 0d435874, job 116614668765 |
a_ asserted that Create succeeds at once, and got NOT_ (41) right after the controller logged not leader; current leader: None. The metadata log directory … has failed errors come after that panic: unwinding dropped the brokers’ temporary directories while they still ran, so they are teardown noise, not the cause. The test now retries NOT_ for up to 30 s, as Kafka’s admin client does, in both of the file’s Create calls. Not reproduced locally: 15 loaded runs of the old test passed. Open parity question: the broker answers NOT_ as soon as the controller has no leader, where Kafka’s broker forwards the request and waits for the next controller. |
| F2 | Flake: diskless_ copies a voter log file that a compaction removed. |
PR #1452 comment | diskless_ panics at voter_ (copy a voter log file: Not). The proposed fix is to tolerate Not in copy_. It is not on main. |
| F3 | Flake: produce_ in the coverage job. |
main 4fdf5f44, job 116715925029 |
a_ fails its check of the log end offset (produce_). No issue or fix exists. |
| F4 | Flake: tiered_ times out at 600 s. |
main f2305998, run 39053924323 |
It made a main gate fail. |
| F5 | Intermittent: a refused rollback changes bytes. The soak_ check an_ fails at soak_. |
netem at f5c683d9; the first attempt of nightly 39758128742 at eb3e01f9 |
While it refused a finalized metadata. 33, the rollback target changed the metadata log, the high watermark, leader-epoch-checkpoint and quorum-state. The target was v1. at f5c683d9 and v1. at eb3e01f9. Root cause: startup checked feature levels in the committed image only, which goes up to the high watermark recovered from its cache file. When that file is below the record that finalized the level, or missing, the check passes. The engine then elects itself and writes, and it refuses the level only when it commits it. Forcing the file below that record reproduces this exactly with v1. under Docker. v1. also checked only after the engine had started, which #1573 fixed in v1.. Fix: the startup guard now also reads every feature level the log holds above the high watermark, and unsupported_ proves a refusal over a stale or missing high-watermark file changes no byte. The fix protects a rollback to a release that carries it. The soak_ check rolls back to the bench/ source, which is v1., so it stays intermittent until that source is a release with the fix. The netem job is not in gate. |
F1 to F4 are blockers to resolve, not documented flakes, because each one is
in a lane that gate requires. F5 is in a lane that gate does not
require, but it checks on-disk safety during a rollback. A fix makes the test deterministic. It does not
skip the test or add a retry.
Known limitations
| ID | Item | Source | Reason |
|---|---|---|---|
| L1 | v1.0.0 to v1.0.5 carry an empty provenance predicate. | Result for v1.0.5 | A signed attestation cannot be changed after release. The signature, the SBOM and the delivery digest still verify. |
| L2 | SASL edge differences from Kafka 4.3.1: idle expiry does not count handler and mute time, PLAIN compares raw bytes, SCRAM c= must equal the GS2 header, a wrong-length proof gets error 58, and an expired delegation token is refused. |
#1390 comment | Disclosed differences in rare error paths. Each one is stricter or more lenient, and none changes a successful authentication. |
| L3 | Java regex edge differences: the compiled-size limit, the message for a repetition with no argument, and surrogate escapes. | #1343, #1389 | #1389 classifies them as documented edge differences. |
| L4 | An override of offsets. is not read, and Offset maps an append error where Kafka answers NOT_. |
#1352, #1388 | Minor and on error paths. The maintainer should decide whether to fix them before the candidate. |
| L5 | A SIGKILL of the active controller can leave a 15-second outage unrecovered in that window (3 of 10 trials). | PR #1452; #1442 | #1452 shows that the window, not the broker, decides the case. State the recovery time an operator can expect. |
| L6 | A dead broker that is never unregistered leaves an offline _ partition. |
PR #1485 | Expected, and visible in the alerts. Document the unregister step. |
| L7 | Evidence gaps: no live harness reads read_ across local eviction, or fails over an RF=3 consumer group. #1388 proposed ten follow-up issues, and none is filed. |
#1388 | The behavior is compared with Kafka’s source, not run. The maintainer should file the ten issues and decide which, if any, are blockers. |
| L8 | Performance follow-ups: the gap to the page cache (#1370), O_DIRECT segments (#1333), and the indicative numbers of #1394. | #1370, #1333, #1394 | Optimizations, not defects. The measured envelope in #1400 states the current limits. |
| L9 | The 200 ms and 400 ms reproduction of #621 still fails. | #621 | A limit of the harness, as #621 records, not a broker defect. |
Not relevant
| Item | Source | Reason |
|---|---|---|
| #1344 is still open. | #1344 | Fixed by #1346 and pinned by #1404. #1389 says it is ready to close. |
| #1442 is still open. | #1442 | The same defect as #1450, which #1455 fixed. The maintainer should close it as a duplicate. The open part is L5. |
Flakes fixed on main: kraft_ timeouts (#1460), cli_ port race (#1454), the multi_ copy flake (#1479). |
The pull requests | Fixed. They stay fixed only if F1 to F4 runs stay clean. |
The stale branch fix/. |
#1389 | No effect on the candidate. |
| The soak judge abandons a recovery at twice its deadline. | PR #1470 | Behavior of the test harness, not of the broker. |