Skip to content

feat(conformity): lint finds placement, quorum and durability rules no cluster can meet - #430

Merged
bmscomp merged 1 commit into
mainfrom
feat/conformity-preflight-8b
Oct 20, 2026
Merged

bmscomp merged 1 commit into
mainfrom
feat/conformity-preflight-8b

Conversation

@bmscomp

@bmscomp bmscomp commented Oct 20, 2026

Copy link
Copy Markdown
Owner

PR 8b of the conformity pre-flight (plan D1: the core 21 checks). kates conformity lint's incoherence stage gains 11 checks, plus the two-pass engine that #420 held back for them.

Errors

No cluster can pass these, so check stops with exit 2 before it calls the API.

Code Fires when
zones-unreachable zones needs more zones than count allows pods (each counted zone hosts a pod, and every pod must be in one)
skew-unreachable no allowed count and zones split with an allowed skew (skew 0 needs zones to divide pods; 2 zones fix the parity)
pernode-cannot-place-count perNode cannot place the pods that zones, skew or kafka.rackAwareness (source cr) require on a node
config-value-kafka-refuses with source: brokers, a validated key admits no value Kafka accepts, such as min.insync.replicas: {max: 0}
sensitive-config-from-brokers with source: brokers, a password-type key, whose value Kafka never returns

Warnings

Code Fires when
controller-quorum-even controllers.count admits only even counts
controller-quorum-zone-loss no allowed count and zones keep a KRaft majority through the loss of one zone
replication-factor-exceeds-brokers a replication factor needs more brokers than brokers.count allows
min-isr-not-below-rf a min ISR is at or above its replication factor or the broker count
isr-lost-with-one-zone losing the zone with the most replicas drops below min ISR
unclean-election-required unclean.leader.election.enable must be true on more than one broker

The replication-factor and min-ISR checks read spec.topics.replicationFactor and minInsyncReplicas (#419) as well as kafka.config.

Two passes

When a rule an error depends on is tolerated (severity warn, or an active waiver), the check can still pass. The engine then reports rule-never-passes, a warning that names each tolerated rule. Each finding lists the rule ids it read and gets its own verdict, so a tolerated controllers rule does not soften a hard brokers error (TestTwoPassJudgesEachFindingAlone).

Where this differs from the 8b brief and the draft

  • Findings carry their rule ids, so b60c2ee's per-run touched set is gone. That set named every tolerated rule a check had read, including rules unrelated to the finding.
  • Numbers are float64, not big.Rat. Rounding is monotone, so a check can only fire less often, never falsely. rat/rats wait for 8c's quantity checks.
  • The 766-line durability draft became 267 lines. Left out:
    • Java BigDecimal and Unicode-digit emulation: a non-ASCII value is taken as accepted;
    • the source-cr and default.replication.factor < 1 warning forms of config-value-kafka-refuses;
    • per-key consequence messages;
    • 4 checks outside 8b's scope.
  • perNode oneOf is read as its least-to-greatest range (a shortcut: comment marks this). It can only fire less often.
  • The rule-never-passes catalogue entry is now triggered through zones-unreachable with a waived zones rule, because b60c2ee's trigger used an 8c check.

Tests

  • TestCatalogue: every check fires on its trigger and not on its near miss. TestEveryCatalogueRuleIsRegistered now passes both ways, with rule-never-passes counted when a two-pass check is registered.
  • TestSkewFitsMatchesEverySplit compares the skew maths with brute force over every split up to 14 pods.
  • Shipped examples still lint clean. Pathological references (unbounded counts, skew near 10000) lint in about 10 ms.
  • Local runs, all passing:
    • in cli: go test ./..., go vet ./..., golangci-lint run --new-from-rev=origin/main ./... (0 issues), govulncheck, scripts/check-cli-style.sh and scripts/check-cli-compat.sh;
    • in kates: ./mvnw test -Dquarkus.grpc.codegen.skip=true -Dquarkus.http.test-port=0.

Docs: one sentence in the book's conformity check section says that a tolerated rule that can never pass gives a warning, not an error.

…o cluster can meet

kates conformity lint's incoherence stage gains 11 checks, and the
two-pass engine PR #420 held back for them.

Errors, which no cluster can pass, so check stops with exit 2:
- zones-unreachable: more zones than the pod count allows.
- skew-unreachable: no allowed count and zones split with an allowed skew.
- pernode-cannot-place-count: perNode cannot place the pods that zones,
  skew or kafka.rackAwareness require on a node.
- config-value-kafka-refuses: with source brokers, a value Kafka never
  accepts for the key.
- sensitive-config-from-brokers: with source brokers, a password-type key,
  whose value Kafka never returns.

Warnings:
- controller-quorum-even and controller-quorum-zone-loss;
- replication-factor-exceeds-brokers, min-isr-not-below-rf and
  isr-lost-with-one-zone, which read spec.topics as well as kafka.config;
- unclean-election-required.

When a rule an error reads is tolerated (severity warn, or an active
waiver), the check can still pass, so the error becomes a
rule-never-passes warning. Each finding names the rules it read and gets
its own verdict, so a tolerated controllers rule does not soften a hard
brokers error.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant