Coarse ballots and the tie ladder — what a three-star election does to STAR's tiebreakers¶
Level: 301 · deep dive
One line: shrink the range voters actually use — 0/1/2 instead of the full 0–5 — and ties stop being exotic; over a million such elections, counted across the Equal Vote methods and classified one by one, produced no tie category this library did not already have a lesson for, but they did show that a coarse ballot quietly shortens the ladder, so the lot decides both more often and one rung earlier.
Companion to Why build "silly" tie elections?, which maps the branches by hand for single-winner STAR. This page is the machine version of the same question, widened to Bloc, proportional STAR, Ranked Robin and Approval — and it is what finally answered the "is that map complete?" the older page left open.
The experiment¶
Ties are the corner this library teaches from, and on a full 0–5 ballot they are rare enough that every tie case here had to be designed. Drop the scale voters use to three values and you no longer have to design anything: three ballots over three candidates collide constantly. Same election rules, same engine, the corners just get crowded.
That is not only a testing trick. The literature that supports 0–5 in the first place does not obviously support six levels: as the wider-scale page records, Hillinger — reading the same convergence across grading, product ratings and opinion scales — would hand a general electorate a three-level ballot and reserve five or six for expert committees. So "what does STAR do on a three-value ballot" is a live design question, not a stress test.
The sweep is tie_taxonomy_sweep.py. It enumerates profiles (exhaustively where the space is small enough, sampled where it is not), counts each one, reduces every tie to a signature, and looks that signature up in a table of the categories this repo teaches. A signature with no entry prints under UNMAPPED — which is the entire point. It reads two engine surfaces and never re-counts anything:
- the machine-readable result contract (
--json), whosetiebreaks: []is a positive claim that no rung fired; and starvote's own round narration atverbosity=2, captured in process — the only surface that names the deterministic rungs on a multi-winner count.
Comparing the two is itself a check, and it is how the finding at the bottom of this page turned up.
python STARVote_LH_tabulation_engine/tools_adam/tie_taxonomy_sweep.py
The result: no new categories¶
445,154 elections counted. 275,412 tie events. Zero unmapped.
Three to four candidates, three to six voters, one to three seats, on the two coarse scales {0,1,2} and {0,1,5}, through STAR, Bloc STAR, Allocated Score, SSS, RRV, Ranked Robin, Approval, and Choose-One as a control. Ties were dense — better than one tie event per two elections — and every one of them reduced to a signature the table below already had a lesson for.
Four categories in the map went unreached, and all four are the same category wearing different hats: the five-star rung, at both STAR loci and both Bloc loci. That is not a hole in the search. It is the next section arriving early: a coarse scale cannot reach that rung, and an exhaustive check says why — on a {0,1,5} ballot the smallest profile that can even pose the question needs eight voters, because the rung fires only when two candidates tie on total score while holding different numbers of 5s, and 5-plus-ones arithmetic does not allow that any sooner. A separate full-scale run (--scores 0,1,2,3,4,5) walks into both inside its first 20,000 elections.
Every tie the sweep produced landed in a category that already has a page. That is a negative result, and negative results are worth stating plainly: it does not prove the taxonomy is complete, it says that a search this shape did not dent it. What it does support is a narrower and more useful claim — coarsening the ballot changes how often each branch is taken, not which branches exist.
| ID | Tie category | Where the lesson lives |
|---|---|---|
| S-F1 | STAR scoring tie → head-to-head (matchups won) picks the finalists | the ladder set · matchups won vs. preference votes |
| S-F2 | STAR scoring tie → five-star rung picks the finalists | BV2180, the ice-cream ladder |
| S-F3 | STAR scoring tie → dead rung → lot picks the finalists | the dead rung |
| S-R1 | STAR runoff tie → higher total score wins | BV830 |
| S-R2 | STAR runoff tie → five-star rung wins | dead-rung case 04 |
| S-R3 | STAR runoff tie → dead rung → lot wins | jfk7pd |
| B-F1 · B-F2 · B-F3 | the same three finalist rungs, inside a Bloc seat | Bloc tiebreaks · tied at every rung |
| B-R1 · B-R2 · B-R3 | the same three runoff rungs, inside a Bloc seat | BV750 |
| P-1 | STAR-PR / SSS / RRV: a tie on the round's weighted total → straight to the lot | tiebreak ladders § STAR-PR |
| R-1 · R-2 · R-3 | Ranked Robin Copeland tie → 1st Degree, 2nd Degree, lot | degrees of ties · the dead heat |
| R-4 | Bloc Ranked Robin: the last seat ties → lot | RR tiebreaks |
| A-1 · A-2 | Approval: a tie for the win, or on the seat cut line → candidate priority order | approval indeterminacy · multiwinner Approval |
| C-1 · C-2 | Choose-One: a tie for first, or on the SNTV cut line → lot | the dead-tie lunch |
| X-1 | multi-winner: candidates tie above the cut line — the set is safe, the order is not | the silent tiebreak |
| X-2 | a winner elected with zero support — nobody scored anybody | the zero-support election |
| X-3 | a tie the engine's report narrates that the JSON contract does not list | the result contract |
| X-4 | a rung eliminates part of the tied group and the survivors carry on | matchups won vs. preference votes |
Three of those are shapes rather than rungs — X-1, X-2 and X-4 can happen under any method — and they are the entries that were hardest to reach by hand. X-4 in particular is the branch the older map called "the branch symmetry cannot test": it needs three or more candidates tied and a rung that separates some of them, which a rotation-symmetric probe can never build, because a symmetric profile separates all or none.
What a coarse ballot actually changes¶
Same shape of election every time — three candidates, four voters, 20,000 profiles per row (the {0,1} row is smaller because the whole space is only 330 profiles, so that row is a complete census rather than a sample). The only thing varying is which score values voters are allowed to use on a ballot whose declared maximum is still 5.
Scoring-round ties — which rung settled the finalists
| Voters use | Scoring ties | → head-to-head | → five-star | → lot | lot's share |
|---|---|---|---|---|---|
{0,1} |
114 of 330 (34.5%) | 0 | 0 | 114 | 100% |
{0,1,2} |
4,734 of 20,000 (23.7%) | 1,136 | 0 | 3,598 | 76.0% |
{0,1,2,3} |
3,522 (17.6%) | 1,298 | 0 | 2,224 | 63.1% |
{0,1,2,3,4} |
2,822 (14.1%) | 1,225 | 0 | 1,597 | 56.6% |
{0,1,2,3,4,5} |
2,368 (11.8%) | 1,077 | 567 | 724 | 30.6% |
Automatic Runoff ties — which rung settled the seat
| Voters use | Runoff ties | → score | → five-star | → lot | lot's share |
|---|---|---|---|---|---|
{0,1} |
114 of 330 (34.5%) | 0 | 0 | 114 | 100% |
{0,1,2} |
6,092 of 20,000 (30.5%) | 2,630 | 0 | 3,462 | 56.8% |
{0,1,2,3} |
5,722 (28.6%) | 3,575 | 0 | 2,147 | 37.5% |
{0,1,2,3,4} |
5,714 (28.6%) | 4,229 | 0 | 1,485 | 26.0% |
{0,1,2,3,4,5} |
5,909 (29.5%) | 4,657 | 646 | 606 | 10.3% |
Two monotone trends, and the second is the interesting one.
Ties get commoner as the ballot gets coarser — 11.8% of full-scale elections have a scoring tie, 34.5% of approval-shaped ones do. No surprise: fewer distinct values, more collisions.
But when a tie does happen, the lot decides far more often. On the runoff, the lot buys the seat in 10% of full-scale ties and 57% of {0,1,2} ties — nearly six times as often. And the mechanism is not "coarse ballots are vaguer". Look at the five-star column: it is exactly zero on every row that omits the 5.
The rung that dies¶
STAR's second tiebreaker counts ballots at the maximum of the scale — fives, not fours. The dead rung page states this for the case where the tied candidates happen to hold no 5s. The sweep makes the stronger version visible: if the electorate never uses the top of the scale, the rung is not occasionally dead, it is structurally absent, and STAR's three-rung ladder is a two-rung ladder for that election. The {0,1,2,3,4} row is the cleanest proof — a five-level ballot, plenty of granularity, and still not one tie in 20,000 elections reached the five-star rung, because nobody scored a 5.
Which raises the question the tables cannot answer: is the top of the scale 5, or is it whatever the ballot says it is?
starvote takes the maximum as a parameter, so both readings are runnable. Here are four ballots, read twice — once as a 0–5 ballot on which voters were merely coarse, and once as a genuine 0–2 ballot:
Ada,Ben
1,2
1,2
1,0
2,1
# maximum_score=5 — "a 0–5 ballot, coarsely used"
[Automatic Runoff Round] Ada 2, Ben 2 → tied
[Automatic Runoff Round: 1st tiebreaker] Ada 5, Ben 5 → still tied
[Automatic Runoff Round: 2nd tiebreaker] most votes of score 5: Ada 0, Ben 0
→ DEAD RUNG. The lot elects Ada.
# maximum_score=2 — "a genuine 0–2 ballot"
[Automatic Runoff Round] Ada 2, Ben 2 → tied
[Automatic Runoff Round: 1st tiebreaker] Ada 5, Ben 5 → still tied
[Automatic Runoff Round: 2nd tiebreaker] most votes of score 2: Ben 2, Ada 1
→ Ben wins. No lot, no banner.
Identical votes. Different winner — and, more to the point, a different kind of decision: under one reading the ballots settle it, under the other the lot does. Nothing about the electorate changed; what changed is the number the ballot paper declares as the top.
This one is LH-only by construction: BetterVoting has no scale parameter, and this repo's own YAML CLI pins the maximum at 5 as a teaching guardrail, so the second run is a library call rather than a case file. It is the mirror of that page's question: widening the scale changes who advances; narrowing it changes who breaks the tie.
The other end: coarse, but at the top¶
Coarse does not have to mean low. Run the same sweep on scales that keep the 5 and drop the middle — {4,5}, {3,4,5}, {0,4,5}, {0,5}, and the degenerate {5} — and the picture inverts. 272,012 elections, still zero unmapped, and this time every one of the 25 categories in the map was reached, including the four the coarse-low sweep could not touch: with 5s everywhere the five-star rung fires constantly (1,043 scoring ties and 828 runoff ties settled by it, plus 1,517 and 1,772 inside Bloc seats).
So the two halves of the experiment answer different halves of the question:
| Sweep | Elections | Unmapped | Categories reached | What it is good for |
|---|---|---|---|---|
coarse-low — {0,1,2}, {0,1,5} |
445,154 | 0 | 21 of 25 | ties are dense, and the lot decides them |
top-heavy — {4,5}, {3,4,5}, {0,4,5}, {0,5}, {5} |
272,012 | 0 | 25 of 25 | ties are dense and the ballots still settle them |
| constructed shapes — the next section | 340,620 | 0 | 25 of 25 | ties by design rather than by collision |
| total | 1,057,786 | 0 |
That is worth stating as a claim about STAR rather than about the sweep: the five-star rung is the part of the ladder that depends on the electorate's habits, not on the electorate's size. Two publics can be equally indecisive and land in completely different places — one where the votes finish the job, one where the lot does — purely on whether the top of the scale gets used. {0,5} is the case with a name: an approval-shaped STAR ballot, where every candidate gets either full support or none — what a strategically-pressured electorate drifts toward — and on a plain draw it keeps the rung alive. (Tighten it further, to one 5 and the rest 0, and you have true bullet voting, which is a shape rather than a scale and behaves quite differently — see the next section.)
Building ties on purpose — six ways, and what each one costs the ladder¶
--scores narrows the values a voter may use. A shape constrains how the ballots relate to each other, which is the other half of the space and the half where the classic probes live. All six are in the tool (--shapes bullet flat rotation mirror clone), all six are published or folklore constructions, and — the headline again — none of them found a category the map does not have. What they differ in is efficiency and depth: how often they tie at all, and how far down the ladder the tie gets before something settles it.
Three candidates, four voters, single-winner STAR, full 0–5 scale unless the row says otherwise. Rows marked (whole space) are exhaustive rather than sampled.
| Shape | What the electorate looks like | Elections | Scoring ties | Runoff ties | Of those → lot |
|---|---|---|---|---|---|
random |
a plain draw — the baseline | 2,000 | 11.8% | 31.1% | 16.2% |
bullet |
every voter maxes one candidate, zeroes the rest | 35 (whole space) | 48.6% | 22.9% | 100% |
flat |
every voter scores the whole field the same | 126 (whole space) | 100% | 100% | 100% |
rotation |
Moulin's witness — k voters per cyclic rotation | 76 (whole space) | 100% | 47.4% | 100% |
clone |
one candidate's column copied onto another | 2,000 | 55.0% | 60.5% | 87.6% |
mirror |
each ballot paired with its reflection | 2,000 | 100% | 100% | 32.4% |
mirror, scores {0,5} |
the same, on a symmetric two-value scale | 2,000 | 100% | 100% | 100% |
Run as a sweep in its own right — all five shapes, three and four candidates, three to six voters, one and two seats, on {0,1,2} and the full scale — the constructed profiles produce 340,620 elections, zero unmapped, and all 25 categories. They are the densest tie source in the tool by a wide margin (107,685 PR-round lot ties alone), and they are the only run that reaches every category without needing a top-heavy scale, because flat and mirror manufacture the score ties that let the five-star rung matter.
rotation reports the same rates at three voters and at six — k voters per rotation changes the size of the electorate, not its symmetry, which is the point Moulin's construction is making. One member of that family is now a live public election: BV2285 vx89hj, the three rotation ballots 4,0,0 / 0,4,0 / 0,0,4, with BetterVoting's own draw recorded in its export — so the shape this flag generates by the dozen can be checked once against a tabulator nobody here wrote (the case).
The mirrored electorate is the interesting one, because it ties everything and still lets the ballots decide two times in three. Reflecting a ballot through the middle of the scale does three things at once, and they are worth separating:
- it flips every preference, so each pair of ballots contributes one preference each way — the Automatic Runoff ties by construction, in every election, always;
- it equalises every total, since a value and its reflection sum to the same constant for whoever holds them — so the score rung ties too, always;
- but it does not equalise the five-star counts. Over one pair, candidate X collects a 5 from the original ballot when
Xscored 5 and from the reflection whenXscored 0, so X's count is (their fives) + (their zeros) — a number that still differs between candidates. That rung does the deciding, on 68% of them.
Narrow the scale to {0,5} and that last line collapses: now every score is either a 5 or a 0, so (fives) + (zeros) is simply the ballot count, identical for everyone. The rung dies and the lot takes all of them.
Which is the same dead rung as the section above, reached from the opposite direction. There, nobody used the top of the scale. Here, everybody uses it, symmetrically — and STAR cannot tell those two electorates apart, because the rung it would use to tell them apart is the one both of them disabled.
The bottom of the scale¶
Push coarseness to its limit — every voter scores every candidate 0 — and you get the shape at the very bottom of the taxonomy: the zero-support election, three ballots and five nominees counted six ways. Every method elects the first name on the lot, which tells you nothing; what the six reports do not agree on is how loudly they admit it, from Choose-One appending , by lot to the winner line down to Approval's one-line note. That folder is the X-2 witness, worked out.
What the sweep found in our own code¶
A sweep whose job is to look for unlisted tie shapes will also, if it is honest, look at whether the reporting of the listed ones is intact. It was not.
The result contract defines an empty tiebreaks: [] as a positive claim that the ballots alone decided — that is the field that catches a right-winner-wrong-path result, and the reason the contract is worth more than 567 winner-only answer keys. A fix in 2026-08-21 had taught the builder to report the lot. But a runoff tie broken by a deterministic rung fires no lot event and belongs to neither of the builder's replays, so it was reported by nothing at all. Running the sweep against both surfaces at once made that visible immediately: thousands of single-winner STAR elections whose printed report said, in full, "Automatic Runoff Round: First tiebreaker — the highest-scoring candidate wins", and whose JSON said tiebreaks: [].
Then the same question, asked of the committed corpus rather than of generated profiles: 16 real cases in this library were making that false claim, twelve at the score rung and four at five-star. Among them:
| Case | Its whole subject | What the JSON said |
|---|---|---|
bv830_vb3xv2_no_condorcet_tie_score |
a runoff tie resolved by score | tiebreaks: [] |
tie_break_04_runoff_five_star_breaks |
a runoff tie resolved by five-star | tiebreaks: [] |
BV_Library_star_runoff_tie_score_resolves |
the name is the finding | tiebreaks: [] |
Files named for the rung the machine-readable result declined to mention. The fix is the mirror of the replay that already existed: resolve_runoff() walks STAR's second ladder — preference round, then total score, then the scale-maximum count, then the lot — through starvote's own round functions, so it cannot disagree with the count, and it is pinned in both directions (rounds.runoff.tied and a stage: "winner" entry must agree, so a swallowed tie and an invented one both fail). Schema 1.2.0; the full account is in the contract's versioning section.
And the part that should sting. This repo files a fair number of bugs against BetterVoting, several of them about exactly this — tie-break transparency, a tieBreakType that says random when nothing tied, an IRV tie broken without being flagged. So the frozen BV exports were the obvious control. Across the eight STAR races in the corpus whose Automatic Runoff was an exact tie, BetterVoting named the rung every time — score, five_star, random — and agreed with this engine on all eight once you account for its documented escalate-to-the-worst-rung reporting. The engine we audit had the disclosure. The contract we built to audit it did not.
And the comparison is only possible because of the fix. Take BV2180, the ice-cream ladder: its scoring round reaches the five-star rung and its runoff is then settled by score. BetterVoting reports one value per race, escalated to the worst rung — five_star — which before 1.2.0 sat opposite a contract that listed the five-star finalists tie and nothing about the runoff at all. The two would have read as agreeing, by accident, on half the story. Now the contract lists both rungs and the escalation reconciles for a stated reason, which is the difference between a cross-check and a coincidence.
Two blind spots survive, and the sweep measures both rather than asserting them away:
- Bloc and PR rungs below the lot are still invisible to the contract. Those rungs run inside
starvote's counting functions, which report nothing back, and there is no replay for them that would not amount to re-deriving the count. The sweep flags each occurrence as X-3, so the size of the gap is a number rather than a caveat. - Ranked Robin reports a single-winner dead heat twice, once as
copeland_leadersand once asseat_cutoff— at one seat those are the same tie seen from both sides. Harmless for a conformance diff that compares tied sets and outcomes; wrong if anyone counts entries.
Running it yourself, and what not to conclude¶
# the default sweep: 3-4 candidates, 3-4 voters, scales {0,1,2} and {0,1,5}
python STARVote_LH_tabulation_engine/tools_adam/tie_taxonomy_sweep.py
# the degenerate probe on its own
python STARVote_LH_tabulation_engine/tools_adam/tie_taxonomy_sweep.py --all-zeros
# top-heavy scales, which is where the five-star rung lives
python STARVote_LH_tabulation_engine/tools_adam/tie_taxonomy_sweep.py --scores 4,5 --scores 0,4,5
# the constructed shapes, alone or together
python STARVote_LH_tabulation_engine/tools_adam/tie_taxonomy_sweep.py --shapes mirror rotation clone
# one witness case file per category, written out
python STARVote_LH_tabulation_engine/tools_adam/tie_taxonomy_sweep.py --witness-dir /tmp/witnesses
The honest limits, since the headline is a negative result:
- Small elections only. Three to six voters, three or four candidates, one to three seats. Ties are dense there and vanishing anywhere else, which is the point — but a category that only appears at scale would not show up.
- Sampled, not exhaustive, above a few thousand profiles. Every row of the scale tables above is either a complete census (
{0,1}, and thebullet/flat/rotationshapes) or a fixed-seed sample of the same size, so the rows are comparable to each other; none of them is a proof. mirrorcan put values on the ballot you did not ask for. A reflection is closed inside--scoresonly when that set is symmetric about its own midpoint:{0,5}and the full scale are,{0,1,5}is not — reflecting a 1 there gives a 4. So a rung the mirrored sweep reaches on an asymmetric set may have been reached by the extra values rather than by the symmetry. The tool says so in its own docstring; the tables above use symmetric sets only.- RCV-IRV and STV are out of scope. This is the Equal Vote method set. IRV's elimination tie is a genuinely different animal — it strikes mid-count and changes every round after it — and it has its own pages: parallel universe tiebreaking, batch elimination, the load-bearing tiebreak.
- "No unmapped categories" is a statement about this search, not a theorem. The one thing it does license: the v1 map drawn by hand for single-winner STAR extends to Bloc, proportional STAR, Ranked Robin and Approval without needing a new branch — which is what that page's own "natural extensions later" note was asking.
See also¶
- Ties & tie-breaking — the topic hub · Ties Are Forced · Why build "silly" tie elections?
- The zero-support election — the X-2 witness, six methods on three blank ballots
- Tiebreak ladders — every method, every engine · the result contract
- Unorthodox STAR — a scale wider than 0–5 — the same knob turned the other way