feat(raft-commit-safety): raft_advance_commit Figure-8 current-term rule (tasks 3.1-3.3, 6.1)

AdvanceCommitIndex (raft.tla:259/270, closes G4): leader-only (-EPERM); Max(agreeIndexes)
= highest N with a quorum ((n_peers/2)+1) of match_index>=N, self counted as log_len;
scan log_len downward. CURRENT-TERM RULE: advance commit_index to N only when
on_get_entry_term(N)==s->term, else HOLD (Figure-8 safety — never commit a previous-term
entry on replication count alone; a later current-term commit indirectly commits it).
Monotonic; fires on_commit_advanced once per strict advance; commit_index<=log_len.

3.3: raft_on_append_entries_reply left untouched — verified it never advances commit
(separation, Req 2.6). 6.1: sim commit-driver helper raft_sim_advance_commit added.

Req 6.3 two-phase indirect-commit transition covered end-to-end by task 7.1 (sim).
ASAN green (230 tests).
This commit is contained in:
Rongsong Shen 2026-06-21 23:27:12 +00:00
parent 3ba6f03a9e
commit 195f660f9a
5 changed files with 350 additions and 4 deletions

View file

@ -389,6 +389,17 @@ void raft_sim_partition(raft_sim_cluster_t *c, int node_idx, int isolated)
c->nodes[node_idx].partition = isolated;
}
void raft_sim_advance_commit(raft_sim_cluster_t *c, int node_idx)
{
if (node_idx < 0 || node_idx >= c->n)
return;
/* Library decides whether the commit index advanced; on a strict advance the
* node's on_commit_advanced (sim_on_commit_advanced) updates commit_index /
* commit_advanced_count. The -EPERM off-leader return is intentionally
* discarded — tests read the per-node mirror, not this status. */
(void)raft_advance_commit(&c->nodes[node_idx].state);
}
/* Two log entries are identical iff their term, length, and payload bytes
* (over the recorded length) all match. */
static int sim_entry_identical(const raft_sim_entry_t *a,