{"abstract":"A candidate with more entries from an older term receives a vote over the voter's newer history.","category":"Distributed coordination","checks":7,"contract":"State is [current term,voted candidate or None], local log is [last term,last index], and requests are [election term,candidate,last log term,last index]. Newer terms clear the vote even if the candidate is rejected. Grant only in current term to an up-to-date log and an unclaimed or same vote. Return [term,voted candidate,grant decisions]. This is a voting-rule model, not a consensus implementation.","evaluation_group":"model-e8e00a50a6a39368","failed_approach":"Fixing log comparison while keeping a vote across newer election terms prevents legitimate elections.","family":"dist-election-term-log-freshness","id":"FA-096","implementations":{"attempt":{"sha256":"34c0e9c1c9d9e800124c3603845c03d9a65bda6762996c0ee2668a30b79bdacf","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\n\nN = 1\nobservations = []\ndef solve(state, local_log, requests):\n    term, voted = state\n    grants = []\n    for request_term, candidate, last_term, last_index in requests:\n        term = max(term, request_term)\n        allowed = request_term == term and (last_term, last_index) >= tuple(local_log) and voted in (None, candidate)\n        if allowed:\n            voted = candidate\n        grants.append(allowed)\n    return [term, voted, grants]\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\nt = N+10\ncheck('longer old-term log rejected', solve([t, None], [N+2, N], [[t, 'a', N+1, 100*N]]), [t, None, [False]])\ncheck('new term clears old vote', solve([t, 'old'], [N, N], [[t+1, 'new', N, N]]), [t+1, 'new', [True]])\ncheck('newer log term beats length', solve([t, None], [N, 100*N], [[t, 'a', N+1, 1]]), [t, 'a', [True]])\ncheck('one candidate per term', solve([t, None], [N, N], [[t, 'a', N, N], [t, 'b', N, N]]), [t, 'a', [True, False]])\ncheck('same candidate retransmission', solve([t, 'a'], [N, N], [[t, 'a', N, N]]), [t, 'a', [True]])\ncheck('old election term ignored', solve([t, None], [N, N], [[t-1, 'a', N+2, N]]), [t, None, [False]])\ncheck('rejected new term still advances', solve([t, 'old'], [N+2, N], [[t+1, 'a', N, N]]), [t+1, None, [False]])\nprint(json.dumps({\"observations\": observations, \"passed\": all(x[\"passed\"] for x in observations)}, ensure_ascii=False))\nraise SystemExit(0 if all(x[\"passed\"] for x in observations) else 1)\n"},"broken":{"sha256":"16a4485ab58a73a1a2166fe677231f88812ee7887d7cbbe2dba40c74d1264231","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\n\nN = 1\nobservations = []\ndef solve(state, local_log, requests):\n    term, voted = state\n    grants = []\n    for request_term, candidate, last_term, last_index in requests:\n        if request_term > term:\n            term, voted = request_term, None\n        allowed = request_term == term and last_index >= local_log[1] and voted in (None, candidate)\n        if allowed:\n            voted = candidate\n        grants.append(allowed)\n    return [term, voted, grants]\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\nt = N+10\ncheck('longer old-term log rejected', solve([t, None], [N+2, N], [[t, 'a', N+1, 100*N]]), [t, None, [False]])\ncheck('new term clears old vote', solve([t, 'old'], [N, N], [[t+1, 'new', N, N]]), [t+1, 'new', [True]])\ncheck('newer log term beats length', solve([t, None], [N, 100*N], [[t, 'a', N+1, 1]]), [t, 'a', [True]])\ncheck('one candidate per term', solve([t, None], [N, N], [[t, 'a', N, N], [t, 'b', N, N]]), [t, 'a', [True, False]])\ncheck('same candidate retransmission', solve([t, 'a'], [N, N], [[t, 'a', N, N]]), [t, 'a', [True]])\ncheck('old election term ignored', solve([t, None], [N, N], [[t-1, 'a', N+2, N]]), [t, None, [False]])\ncheck('rejected new term still advances', solve([t, 'old'], [N+2, N], [[t+1, 'a', N, N]]), [t+1, None, [False]])\nprint(json.dumps({\"observations\": observations, \"passed\": all(x[\"passed\"] for x in observations)}, ensure_ascii=False))\nraise SystemExit(0 if all(x[\"passed\"] for x in observations) else 1)\n"},"fixed":{"sha256":"b2cfee3b3e4f5c92611279b43ba6619c8fd4481fd2600c236519bcc448d3f558","source":"\"\"\"Failure Map reference implementation. Python standard library only.\"\"\"\nimport json\n\nN = 1\nobservations = []\ndef solve(state, local_log, requests):\n    term, voted = state\n    grants = []\n    for request_term, candidate, last_term, last_index in requests:\n        if request_term > term:\n            term, voted = request_term, None\n        allowed = request_term == term and (last_term, last_index) >= tuple(local_log) and voted in (None, candidate)\n        if allowed:\n            voted = candidate\n        grants.append(allowed)\n    return [term, voted, grants]\ndef check(label, actual, expected):\n    observations.append({\"check\": label, \"actual\": actual, \"expected\": expected, \"passed\": actual == expected})\nt = N+10\ncheck('longer old-term log rejected', solve([t, None], [N+2, N], [[t, 'a', N+1, 100*N]]), [t, None, [False]])\ncheck('new term clears old vote', solve([t, 'old'], [N, N], [[t+1, 'new', N, N]]), [t+1, 'new', [True]])\ncheck('newer log term beats length', solve([t, None], [N, 100*N], [[t, 'a', N+1, 1]]), [t, 'a', [True]])\ncheck('one candidate per term', solve([t, None], [N, N], [[t, 'a', N, N], [t, 'b', N, N]]), [t, 'a', [True, False]])\ncheck('same candidate retransmission', solve([t, 'a'], [N, N], [[t, 'a', N, N]]), [t, 'a', [True]])\ncheck('old election term ignored', solve([t, None], [N, N], [[t-1, 'a', N+2, N]]), [t, None, [False]])\ncheck('rejected new term still advances', solve([t, 'old'], [N+2, N], [[t+1, 'a', N, N]]), [t+1, None, [False]])\nprint(json.dumps({\"observations\": observations, \"passed\": all(x[\"passed\"] for x in observations)}, ensure_ascii=False))\nraise SystemExit(0 if all(x[\"passed\"] for x in observations) else 1)\n"}},"limitations":" This reproducer isolates one failure mechanism. Results cover the supplied fixtures. Variants within a family share a test contract and should remain grouped when constructing evaluation splits. Related mechanisms with a shared evaluation_group must also remain together; these controlled models are not independent production incidents.","method":"Deterministic executable model with adversarial boundary fixtures.","provenance":{"created_by":"Failure Map","dependencies":"Python standard library","family":"dist-election-term-log-freshness","generated_at":"2026-09-29T14:36:50.454387+00:00","license":"CC0-1.0","python":"3.12.14","seed":1,"split":"open-access"},"relevance":"Models two interacting durable election invariants: freshness by log term and one candidate per election term, including term advancement on rejected requests.","repair":"Advance term and clear prior-term vote first; compare (last log term,last log index) lexicographically before granting.","root_cause":"Log length is compared without prioritizing the last log term, and vote state is not scoped to election term.","sha256":"c5dc01051c335042f4298886033411be8f74a4550649d3435ef314119c363588","title":"Election votes prefer a longer but older log · case 01","variant":1,"variant_policy":"Five numbered records share a model and may reuse boundary fixtures.","verification":{"attempt":{"elapsed_ms":35.821,"exit_code":1,"observations":[{"actual":[11,null,[false]],"check":"longer old-term log rejected","expected":[11,null,[false]],"passed":true},{"actual":[12,"old",[false]],"check":"new term clears old vote","expected":[12,"new",[true]],"passed":false},{"actual":[11,"a",[true]],"check":"newer log term beats length","expected":[11,"a",[true]],"passed":true},{"actual":[11,"a",[true,false]],"check":"one candidate per term","expected":[11,"a",[true,false]],"passed":true},{"actual":[11,"a",[true]],"check":"same candidate retransmission","expected":[11,"a",[true]],"passed":true},{"actual":[11,null,[false]],"check":"old election term ignored","expected":[11,null,[false]],"passed":true},{"actual":[12,"old",[false]],"check":"rejected new term still advances","expected":[12,null,[false]],"passed":false}],"passed":false,"stderr":"","stdout":"{\"observations\": [{\"check\": \"longer old-term log rejected\", \"actual\": [11, null, [false]], \"expected\": [11, null, [false]], \"passed\": true}, {\"check\": \"new term clears old vote\", \"actual\": [12, \"old\", [false]], \"expected\": [12, \"new\", [true]], \"passed\": false}, {\"check\": \"newer log term beats length\", \"actual\": [11, \"a\", [true]], \"expected\": [11, \"a\", [true]], \"passed\": true}, {\"check\": \"one candidate per term\", \"actual\": [11, \"a\", [true, false]], \"expected\": [11, \"a\", [true, false]], \"passed\": true}, {\"check\": \"same candidate retransmission\", \"actual\": [11, \"a\", [true]], \"expected\": [11, \"a\", [true]], \"passed\": true}, {\"check\": \"old election term ignored\", \"actual\": [11, null, [false]], \"expected\": [11, null, [false]], \"passed\": true}, {\"check\": \"rejected new term still advances\", \"actual\": [12, \"old\", [false]], \"expected\": [12, null, [false]], \"passed\": false}], \"passed\": false}\n"},"broken":{"elapsed_ms":35.703,"exit_code":1,"observations":[{"actual":[11,"a",[true]],"check":"longer old-term log rejected","expected":[11,null,[false]],"passed":false},{"actual":[12,"new",[true]],"check":"new term clears old vote","expected":[12,"new",[true]],"passed":true},{"actual":[11,null,[false]],"check":"newer log term beats length","expected":[11,"a",[true]],"passed":false},{"actual":[11,"a",[true,false]],"check":"one candidate per term","expected":[11,"a",[true,false]],"passed":true},{"actual":[11,"a",[true]],"check":"same candidate retransmission","expected":[11,"a",[true]],"passed":true},{"actual":[11,null,[false]],"check":"old election term ignored","expected":[11,null,[false]],"passed":true},{"actual":[12,"a",[true]],"check":"rejected new term still advances","expected":[12,null,[false]],"passed":false}],"passed":false,"stderr":"","stdout":"{\"observations\": [{\"check\": \"longer old-term log rejected\", \"actual\": [11, \"a\", [true]], \"expected\": [11, null, [false]], \"passed\": false}, {\"check\": \"new term clears old vote\", \"actual\": [12, \"new\", [true]], \"expected\": [12, \"new\", [true]], \"passed\": true}, {\"check\": \"newer log term beats length\", \"actual\": [11, null, [false]], \"expected\": [11, \"a\", [true]], \"passed\": false}, {\"check\": \"one candidate per term\", \"actual\": [11, \"a\", [true, false]], \"expected\": [11, \"a\", [true, false]], \"passed\": true}, {\"check\": \"same candidate retransmission\", \"actual\": [11, \"a\", [true]], \"expected\": [11, \"a\", [true]], \"passed\": true}, {\"check\": \"old election term ignored\", \"actual\": [11, null, [false]], \"expected\": [11, null, [false]], \"passed\": true}, {\"check\": \"rejected new term still advances\", \"actual\": [12, \"a\", [true]], \"expected\": [12, null, [false]], \"passed\": false}], \"passed\": false}\n"},"fixed":{"elapsed_ms":41.937,"exit_code":0,"observations":[{"actual":[11,null,[false]],"check":"longer old-term log rejected","expected":[11,null,[false]],"passed":true},{"actual":[12,"new",[true]],"check":"new term clears old vote","expected":[12,"new",[true]],"passed":true},{"actual":[11,"a",[true]],"check":"newer log term beats length","expected":[11,"a",[true]],"passed":true},{"actual":[11,"a",[true,false]],"check":"one candidate per term","expected":[11,"a",[true,false]],"passed":true},{"actual":[11,"a",[true]],"check":"same candidate retransmission","expected":[11,"a",[true]],"passed":true},{"actual":[11,null,[false]],"check":"old election term ignored","expected":[11,null,[false]],"passed":true},{"actual":[12,null,[false]],"check":"rejected new term still advances","expected":[12,null,[false]],"passed":true}],"passed":true,"stderr":"","stdout":"{\"observations\": [{\"check\": \"longer old-term log rejected\", \"actual\": [11, null, [false]], \"expected\": [11, null, [false]], \"passed\": true}, {\"check\": \"new term clears old vote\", \"actual\": [12, \"new\", [true]], \"expected\": [12, \"new\", [true]], \"passed\": true}, {\"check\": \"newer log term beats length\", \"actual\": [11, \"a\", [true]], \"expected\": [11, \"a\", [true]], \"passed\": true}, {\"check\": \"one candidate per term\", \"actual\": [11, \"a\", [true, false]], \"expected\": [11, \"a\", [true, false]], \"passed\": true}, {\"check\": \"same candidate retransmission\", \"actual\": [11, \"a\", [true]], \"expected\": [11, \"a\", [true]], \"passed\": true}, {\"check\": \"old election term ignored\", \"actual\": [11, null, [false]], \"expected\": [11, null, [false]], \"passed\": true}, {\"check\": \"rejected new term still advances\", \"actual\": [12, null, [false]], \"expected\": [12, null, [false]], \"passed\": true}], \"passed\": true}\n"}},"verified":true,"visibility":"public"}