Live-fresh off-primary committed: primary stamps committed_lsn/config_tag onto each HA heartbeat (OP_nop + the existing-but-unused HeartbeatMsg body); standby monotonically refreshes last_known_committed_* (reconcile-free, term-guarded). Removes the controller-status Req 10 staleness caveat. Vote-floor formula unchanged; safety rests on term-guard + monotonicity (design Security). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
6.9 KiB
Requirements Document
Introduction
This feature makes a standby controller's knowledge of the cluster's committed position stay current from the primary's heartbeats, rather than only being refreshed when the standby (re)joins the primary. Today a standby learns the committed position (committed log position and committed configuration version) only at a join / failover handshake; between joins that knowledge goes stale, and a standby that has applied replicated entries can still report a committed position of zero. The heartbeat already flows continuously between primary and standbys, so it is the natural carrier for a fresh committed marker.
With this feature, the serving primary includes its current committed position in every heartbeat, and each standby uses it to keep its own known committed position up to date — within roughly one heartbeat interval — without waiting for a re-join. This directly removes the staleness caveat documented by the controller-status feature (whose ctrlstatus query reports a standby's known committed position): a standby's reported committed position becomes near-real-time instead of join-stale or zero.
The propagated committed marker is advisory — it exists for observability and standby state freshness only. It must not change how the committed position is produced, advanced, replicated, or persisted, and it must not feed any correctness-critical decision (log truncation, election/vote safety). Existing heartbeat liveness and failover behavior must be unaffected.
Full discovery context (problem, approach, scope, boundary candidates, upstream/downstream, constraints) is in
.kiro/specs/ha-heartbeat-committed-propagation/brief.md.
Boundary Context
- In scope: the serving primary advertising its current committed position (committed log position + committed configuration version) on each heartbeat; a standby consuming that value to keep its own known committed position current; monotonic (never-regressing) update of that known position; graceful handling of heartbeats that carry no usable committed value; preserving all existing heartbeat liveness/failover behavior.
- Out of scope: how the committed position is produced, advanced, replicated, or persisted (owned by the commit engine / durability); the join/failover handshake that already seeds the standby's committed knowledge (unchanged, remains the initial source); the catch-up streaming trigger (remains acknowledgement-driven, not heartbeat-driven); the
ctrlstatusreporting/rendering of the committed position (owned by controller-status, which already reads the standby's known committed position); any change to how a node truncates its log or evaluates vote freshness. - Adjacent expectations: relies on the existing heartbeat channel and timing (the primary already emits heartbeats and standbys already receive them) and on the existing committed-position semantics, both consumed unchanged. The downstream consumer is the controller-status
ctrlstatusquery: once a standby's known committed position is heartbeat-fresh, that query reflects it with no change to controller-status. Vote-freshness evaluation may read the standby's known committed position as part of its floor, but this feature must not let a heartbeat-borne value lower or weaken that floor.
Requirements
Requirement 1: Heartbeat-borne committed position propagation
Objective: As an operator, I want a standby's known committed position to refresh from the primary's heartbeats, so that it reflects the live cluster committed state without waiting for the standby to re-join.
Acceptance Criteria
- While a node is the serving primary, when it emits a heartbeat, the Controller shall include in that heartbeat the primary's current committed log position and committed configuration version.
- When a standby receives a heartbeat that carries a committed position, the Controller shall update the standby's known committed position (committed log position and committed configuration version) from the values in that heartbeat, subject to the monotonicity rule in Requirement 2.
- While a standby is continuously receiving heartbeats from a serving primary, the standby's known committed position shall reflect the primary's committed position within one heartbeat interval, without requiring a re-join handshake.
Requirement 2: Monotonic, non-regressing committed knowledge
Objective: As an operator, I want a standby's known committed position to never move backward, so that observed committed progress stays stable and trustworthy across heartbeats.
Acceptance Criteria
- When a standby receives a heartbeat whose carried committed log position is greater than the standby's current known committed log position, the Controller shall advance the known committed position to the carried value.
- If a standby receives a heartbeat whose carried committed log position is less than or equal to the standby's current known committed log position (for example a delayed or out-of-order heartbeat, or a newly started or lagging primary), then the Controller shall leave the standby's known committed position unchanged.
- The standby's known committed configuration version shall be advanced together with the known committed log position and shall never be regressed independently.
Requirement 3: Advisory-only — no effect on correctness-critical paths
Objective: As a maintainer, I want the heartbeat-borne committed value used only for observability and standby state freshness, so that it cannot weaken durability or election-safety guarantees.
Acceptance Criteria
- The Controller shall not use a heartbeat-borne committed position to truncate, discard, or otherwise modify any write-ahead log entry.
- The Controller shall not use a heartbeat-borne committed position to lower or weaken the durability-backed freshness floor used when granting votes.
- The Controller shall not change how the committed position is produced, advanced, replicated, or persisted as a result of propagating it on heartbeats.
- While a node is the serving primary, the Controller shall continue to use and report its own authoritative committed position; a heartbeat-borne committed value shall be consumed only by non-primary nodes.
Requirement 4: No regression to heartbeat liveness behavior
Objective: As an operator, I want existing heartbeat liveness and failover behavior to be unchanged, so that adding committed propagation does not destabilize the cluster.
Acceptance Criteria
- The Controller shall preserve existing heartbeat liveness detection, missed-heartbeat tolerance, and proactive-heartbeat timing behavior unchanged when committed propagation is added.
- If a received heartbeat carries no usable committed position (for example a zero or absent value), then the Controller shall process it as a liveness heartbeat exactly as before and shall leave the standby's known committed position unchanged, without error.