chore: checkpoint all prior work for clean state

Captures all uncommitted work from ha-config-bootstrap,
ha-heartbeat-liveness, and associated spec/tooling updates:

- src: ha.c, ha.h, cluster.c, config_repl.c, myapp.c, raft.c —
  heartbeat liveness, RDHUP integration, committing phase fixes
- tests: test_ha_role.c, test_config_repl.c, test_ha_rdhup_integration.c,
  test_p1_integration.c, test_p3_hardening.c, scheduler test
- specs: election-iomgr-refactor, ha-heartbeat-liveness,
  ha-peer-connection-reuse, raft-library (new); ha-config-bootstrap
  and election-iomgr-refactor task/research updates
- tooling: .wolf/ state, ha/data cluster fixtures, raft/raft.tla,
  src/build symlink, xce-build skill update
This commit is contained in:
Rongsong Shen 2026-06-04 13:04:16 +00:00
parent 15bd291bdd
commit e31673dd88
66 changed files with 122422 additions and 860 deletions

View file

@ -114,12 +114,19 @@ int raft_on_vote_request(raft_state_t *s, int from_idx, uint64_t term,
return RAFT_DENY;
}
/* Step 2: term upgrade — update term, clear vote, step down to FOLLOWER */
/* Step 2: term upgrade — update term, clear vote, step down to FOLLOWER.
* If we were LEADER, notify the HA FSM so it updates ha->role.
* Without this, the HA FSM stays in CTRL_PRIMARY_COMMITTING and
* eventually promotes to PRIMARY via the committing timeout → split-brain. */
if (term > s->term) {
int was_leader = (s->role == RAFT_LEADER);
s->term = term;
s->voted_for = -1;
s->voted_for_term = 0;
s->role = RAFT_FOLLOWER;
if (was_leader) {
s->cbs->on_become_follower(s->ctx, s->term, from_idx);
}
}
/* reply_term reflects our (possibly updated) current term from here on */