# Zambia 2026 — pre-registered headline-pair selection rule + attribution aliases

**Date declared:** 2026-07-16 (before the T-7 lock; Zambia presidential election 2026-08-13, so
T-7 auto-lock ≈ 2026-08-06 — this is declared **21 days pre-lock**).
**Market:** `zm_national` (Zambia 2026 presidential, 14-candidate ECZ field; first-round two-way
*leader* headline + n-way companion).
**Status:** PRE-REGISTRATION. The rule and alias map below are declared now and **bind at the T-7
lock**. This file is anchored (SHA-256 + OpenTimestamps + git; see `calibration/ANCHORS.md`); any
revision is a NEW dated file, never an edit of this one.

## What changed and why

A coverage diagnostic on 2026-07-16 (`docs/ZM_STANCE_DIAGNOSTIC_2026-07-16.md`) found the two-way
"decided" pool reading **4 accounts** against **82** accounts that actually held a supportive/opposed
stance. Two upstream causes, both fixed here:

### 1. Headline-pair selection: ENGAGED VOLUME, not net favorability

**Old rule (v1):** the two-candidate headline pair was `sorted(head_to_head, key=favorability)[:2]`
— the two candidates with the highest **net** supportive/(supportive+opposed) ratio.

**Problem:** favorability is a *ratio*, blind to volume. A fringe candidate with a single
all-supportive post scores favorability 1.0 and outranks a frontrunner whose large footprint is
mixed (net-negative). On the live zm dome this handed the "headline pair" to **Howard Kunda**
(1 decided post) and **Fred M'membe** (4), while **Hakainde Hichilema** (47 supportive / 59 opposed)
and **Brian Mundubile** (46 / 64) — the actual frontrunners, engaged by dozens of accounts — were
excluded. `n_decided_accounts` counts only accounts decided about the top-2 pair, so it collapsed to
~4.

**New rule (v2 — `HEADLINE_PAIR_RULE` engaged_volume, `sonar/social/analytics.py`
`build_head_to_head_headline`):** the pair is the two candidates with the most **engaged volume** —
unique accounts holding a supportive/opposed (decided) stance about that candidate. Tie-break by
favorability, then candidate name (both deterministic).

**Why volume, not favorability:** the headline is meant to name *the race* — the two candidates the
electorate is actually arguing about. That is a question of how many distinct people took a side, not
of who has the cleanest sentiment ratio among a handful of mentions. Volume is also far harder for a
single loud account to move (it is a distinct-account count, and the 5% impact-share ceiling still
applies to the shares within the pair).

**Two-candidate races are unaffected (AZ / SC inertness — required proof).** With two candidates the
pair is always both; the only freedom is which is entity_a (the leader). For a real two-way the
higher-volume candidate is also the higher-favorability one, so the order is preserved. Verified live
against prod on 2026-07-16, byte-identical before/after:

| market | entity_a | entity_b | headline_share_a | locked_share_a | decided | ESS |
|---|---|---|---|---|---|---|
| us_arizona | Andy Biggs | David Schweikert | 92.6 | 91.9 | 508 | 6.73 |
| us_sc | Alan Wilson | Pamela Evette | 85.2 | 81.3 | 84 | 9.60 |

Both rows are identical under v1 and v2. No AZ or SC stored lock value moves.

### 2. Candidate aliases + party-to-candidate map

Attribution matched only bare candidate NAMES (all 14 had `aliases=()`), so nickname-only posts
("bally", "HH"), the apostrophe-broken surname ("M'membe" → tokens `m`,`membe`), and **party-only**
posts (UPND / Tonse / PF / Socialist Party / Citizens First) attributed to nobody and were never
stance-scored — 67% of race-relevant posts carried no stance. Aliases + a party→candidate map are now
declared in `sonar/markets/zm_national.py` and consumed by `build_attribution`.

Web-verified nicknames and party affiliations (2026-07-16):

- **Hakainde Hichilema — UPND**; nicknames **"HH"** (initials) and **"Bally"** (slang for father;
  "Bally will fix it" youth slogan). Source: [Hakainde Hichilema — Wikipedia](https://en.wikipedia.org/wiki/Hakainde_Hichilema).
- **Brian Mundubile — Tonse Alliance** (vehicle party FDD; NRPUP), merged with the **PF-Pamodzi**
  faction (Makebi Zulu, his running mate) into the **Tonse–Pamodzi** banner. PF is mapped to
  Mundubile as the surviving-faction candidate — a deliberate, contestable call (a post attacking the
  PF legacy is not necessarily pro-Mundubile; the stance classifier still decides direction). Edgar
  Lungu is **not** in the field. Sources:
  [2026 Zambian general election — Wikipedia](https://en.wikipedia.org/wiki/2026_Zambian_general_election),
  [Alliance politics — SARDC](https://sardc.net/en/southern-african-news-features/alliance-politics-take-centre-stage-as-zambia-heads-to-august-polls/).
- **Fred M'membe — Socialist Party** (running as the **People's Pact**). Aliases "Mmembe"/"Membe".
  Source: [2026 Zambian general election — Wikipedia](https://en.wikipedia.org/wiki/2026_Zambian_general_election).
- **Harry Kalaba — Citizens First (CF)** / CF Orange Alliance. Source:
  [Former CF official urges Kalaba and M'membe to back Mundubile — Lusaka Times](https://www.lusakatimes.com/2026/06/30/former-cf-official-urges-kalaba-and-mmembe-to-back-mundubile/).

The remaining 10 candidates carry surname + distinctive party-name aliases only (no nickname
evidence); their party abbreviations that risk English-word collisions (e.g. "OPP") are omitted.

## What binds at the lock

At the T-7 auto-lock (≈2026-08-06) the headline **pair** is selected by the v2 engaged-volume rule
and the attribution map above is in force. The instrument of record remains the impact-weighted
two-way leader share; the pre-registered weighting variants
(`calibration/zm_weighting_variants_2026-07-15.md`) are unchanged and still render beside it. This
file changes *which two candidates* the headline names and *which posts attribute*, not the share
math or the 21-decided lock gate.
