--- id: "bug-538" status: "fixed" status_updated: "2026-09-24" status_note: "" component: "controller" severity: "unknown" timestamp: "2026-06-14" last_seen: "2026-09-19T09:00:00Z" occurrences: 1 files: ["src/controller/ha.c"] tags: ["ha", "election-safety", "rdhup", "config-bootstrap", "Req2.8", "Req10.5", "voter-only-guard"] related: [] legacy: true --- # bug-538: config-less controller (my_config_tag==0) became PRIMARY after RDHUP and pushed empty config… ## Description config-less controller (my_config_tag==0) became PRIMARY after RDHUP and pushed empty config, breaking replication on a live 3-node cluster ## Environment _Not recorded (migrated from buglog.json)._ ## Reproduction _Not recorded (migrated from buglog.json)._ ## Root cause ha_on_primary_ctrl_fd_rdhup did not apply the no-config voter-only guard that ha_start_election_async has; after primary RDHUP it set CTRL_ELECTING, allocated elect_ctx and called raft_on_leader_lost even for tag=0 nodes. Two tag=0 nodes granted each other (freshness gate only denies LOWER tag; tag0==tag0 granted), electing a config-less primary. ## Fix Added an election-safety guard in ha_on_primary_ctrl_fd_rdhup after the WAL-truncate block and before elect_ctx alloc/hook/raft_on_leader_lost: if my_config_tag==0 && candidates_count>1, log + set role=CTRL_STANDBY and return (stays passive voter). Mirrors ha_start_election_async. Single-node (n_peers==1) unaffected. ## Verification _Not recorded (migrated from buglog.json)._ ## References _Not recorded (migrated from buglog.json)._