You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Update (2026-08-08): the first half of this landed in #286. The chart can now
render a replicated range — data.topology: replicated picks leader/follower/standalone,
the leader gets a followers list of per-pod headless FQDNs, and the followers get a lease block. Option (1) below is DONE.
Two things remain, and they are different sizes, so they are split:
The chart deploys three independent standalone ranges, not one replicated range. Three replicas are three separate logs, which is why --durability quorum is refused outright — "Quorum durability requires a configured replica set" — and why a pod nobody produced to stays empty. scripts/k8s-smoke.sh asserts both, so the behaviour is pinned rather than incidental.
That means the deployment shape which exercises replication, fencing, promotion, and the whole #240 epoch arc is not reachable from the chart at all. Everything that arc fixed is currently only exercised by the live-chaos harness.
The blocker the chart cited is gone
The template said:
Replicated ranges under co-location wait on follower-side epoch propagation upstream.
That landed in #239 (lease_watcher.rs — followers learn granted epochs without a restart), and the rest of the recovery arc landed as #240's stack. DataNodeConfig already supports role: leader with a followers list, role: follower, and a lease block that is explicitly valid on followers. The engine is no longer the constraint.
The constraint that is real
role is a static per-node config field, and a StatefulSet renders one config per ordinal. So a replicated range means:
ordinal 0 → role: leader, with a followers list naming the other ordinals' headless FQDNs
ordinals 1..n → role: follower, each with a lease block so it adopts granted epochs
That renders fine. What does not work is failover: when metadata grants the range to a different node, the new holder needs role: leader and the old one needs role: follower, and nothing re-renders a ConfigMap in response to a lease change. The live-chaos harness handles this by restarting the promoted node with a new config (scenario 09 does exactly that), which is a harness move, not an operator one.
Make the role dynamic in the binary — every node starts as a candidate and its role follows the lease, rather than being fixed at config time. This is the shape Kubernetes actually wants, and it would make the chart's job trivial. It is also the larger change, and it interacts with node: vtop-node ignores SIGTERM, so every orderly stop is a crash stop #280 (a departing leader releasing its lease).
Leave it standalone and keep replication exercised only by live-chaos.
(2) is where this should end up. (1) is worth having in the meantime, because without it nothing in Kubernetes ever exercises the replication path.
Also worth testing while here
Cross-namespace. The chart parameterises the namespace and every peer FQDN includes it, so two releases in different namespaces should be independent by construction — but "should be" is what this whole exercise keeps disproving. A second release in another namespace, both streaming, neither seeing the other's records, belongs in the smoke test as a variant.
Update (2026-08-08): the first half is done and verified live
#293 landed it. scripts/k8s-smoke.sh now deploys the replicated topology as a third shape and asserts the things only that shape can prove:
[k8s-smoke] producing with QUORUM durability, which a standalone range refuses
[k8s-smoke] quorum produce accepted 60 records
[k8s-smoke] follower 1 has durably applied all 60 records
[k8s-smoke] follower 2 has durably applied all 60 records
[k8s-smoke] replication verified in Kubernetes: quorum durability works and both followers hold the data
The assertions are deliberately the INVERSE of the standalone ones — quorum succeeds where it is refused, and a follower nobody produced to holds everything instead of staying empty — because that is what proves the topology took effect rather than merely being accepted. Both followers are checked, since quorum only proves a majority acked (with three replicas, the leader plus one), and it reads local_committed_offset, what the follower has FSYNCED, not next_offset.
Getting there needed three bugs fixed, all in #293: the topology rendered invalid YAML and had never once worked; a replicated install needs meta create-topic and register-node per node, which nothing documented; and nothing followed a Raft leader redirect (#292), so two of three replicas failed closed permanently.
What remains under this number is option (2) alone: failover still needs an operator.role is fixed at render time, so when metadata grants the range elsewhere nothing re-renders the ConfigMap. That interacts with #280 (a departing leader releasing its lease) and the two probably belong in the same milestone.
The chart deploys three independent standalone ranges, not one replicated range. Three replicas are three separate logs, which is why
--durability quorumis refused outright — "Quorum durability requires a configured replica set" — and why a pod nobody produced to stays empty.scripts/k8s-smoke.shasserts both, so the behaviour is pinned rather than incidental.That means the deployment shape which exercises replication, fencing, promotion, and the whole #240 epoch arc is not reachable from the chart at all. Everything that arc fixed is currently only exercised by the live-chaos harness.
The blocker the chart cited is gone
The template said:
That landed in #239 (
lease_watcher.rs— followers learn granted epochs without a restart), and the rest of the recovery arc landed as #240's stack.DataNodeConfigalready supportsrole: leaderwith afollowerslist,role: follower, and aleaseblock that is explicitly valid on followers. The engine is no longer the constraint.The constraint that is real
roleis a static per-node config field, and a StatefulSet renders one config per ordinal. So a replicated range means:role: leader, with afollowerslist naming the other ordinals' headless FQDNsrole: follower, each with aleaseblock so it adopts granted epochsThat renders fine. What does not work is failover: when metadata grants the range to a different node, the new holder needs
role: leaderand the old one needsrole: follower, and nothing re-renders a ConfigMap in response to a lease change. The live-chaos harness handles this by restarting the promoted node with a new config (scenario 09 does exactly that), which is a harness move, not an operator one.Options, roughly in order of honesty
(2) is where this should end up. (1) is worth having in the meantime, because without it nothing in Kubernetes ever exercises the replication path.
Also worth testing while here
Cross-namespace. The chart parameterises the namespace and every peer FQDN includes it, so two releases in different namespaces should be independent by construction — but "should be" is what this whole exercise keeps disproving. A second release in another namespace, both streaming, neither seeing the other's records, belongs in the smoke test as a variant.
Update (2026-08-08): the first half is done and verified live
#293 landed it.
scripts/k8s-smoke.shnow deploys the replicated topology as a third shape and asserts the things only that shape can prove:The assertions are deliberately the INVERSE of the standalone ones — quorum succeeds where it is refused, and a follower nobody produced to holds everything instead of staying empty — because that is what proves the topology took effect rather than merely being accepted. Both followers are checked, since quorum only proves a majority acked (with three replicas, the leader plus one), and it reads
local_committed_offset, what the follower has FSYNCED, notnext_offset.Getting there needed three bugs fixed, all in #293: the topology rendered invalid YAML and had never once worked; a replicated install needs
meta create-topicandregister-nodeper node, which nothing documented; and nothing followed a Raft leader redirect (#292), so two of three replicas failed closed permanently.What remains under this number is option (2) alone: failover still needs an operator.
roleis fixed at render time, so when metadata grants the range elsewhere nothing re-renders the ConfigMap. That interacts with #280 (a departing leader releasing its lease) and the two probably belong in the same milestone.