Holborn & St Pancras by-election (8 October 2026)
Vintage holborn-stp-by2026-v0.2 · as of 16 September 2026 · polling day 8 October 2026 · status scored
Labour leads by 23.0 points; 80% interval 16.6 to 29.2.
Lab - runner-up, pp of valid vote (single field, run B headline)
Scored at declaration: Labour won by 12.4 points; the margin landed outside its 80% interval. The result, the scores and the post-mortem are below.
Forecast shares — every line on the register
single SOPN field (15 candidates: 8 simulated lines + 7 explicit zero lines); values = run B (headline) of the Ad1.3 protocol
| Candidate | Ballot description | Mean | 80% interval | P(win) |
|---|---|---|---|---|
| Abdi-Wali | Labour Party | 47.0 | [43.1, 50.9] | >0.99 |
| Polanski | Green Party | 24.0 | [20.9, 27.3] | 0.00 |
| Newman | Reform UK | 15.7 | [14.6, 17.0] | — |
| Stillman | Liberal Democrats | 4.8 | [4.4, 5.2] | — |
| Galloway | Workers Party of Britain | 4.3 | [0.4, 7.9] | 0.00 |
| Cameron | Conservative Party | 3.5 | [3.2, 3.8] | — |
| Brunch | Official Monster Raving Loony Party | 0.5 | [0.4, 0.5] | — |
| Walker | UK Independence Party | 0.2 | [0.2, 0.2] | — |
| Darwood | Independent (no description) | 0.0 | — | 0.00 |
| Fischer | Climate Party | 0.0 | — | 0.00 |
| Johnson | Restore Britain | 0.0 | — | 0.00 |
| Kapoor | Rejoin EU | 0.0 | — | 0.00 |
| Pipaliya | UK VOICE | 0.0 | — | 0.00 |
| Silberman | Communist League | 0.0 | — | 0.00 |
| Spiby-Vann | Christian Peoples Alliance | 0.0 | — | 0.00 |
Explicit-zero lines: Ad3.7 null treatment - explicit 0.0 forecast so s6.1 per-candidate scoring covers all 15
The result
Abdi-Wali (Labour Party), hold. Majority 3,364 (12.36 points of the valid vote).
| # | Candidate | Ballot description | Votes | Share |
|---|---|---|---|---|
| 1 | Abdi-Wali | Labour Party | 12,292 | 45.17% |
| 2 | Polanski | Green Party | 8,928 | 32.81% |
| 3 | Cameron | Conservative Party | 1,922 | 7.06% |
| 4 | Newman | Reform UK | 1,612 | 5.92% |
| 5 | Stillman | Liberal Democrats | 924 | 3.40% |
| 6 | Johnson | Restore Britain | 692 | 2.54% |
| 7 | Galloway | Workers Party of Britain | 314 | 1.15% |
| 8 | Kapoor | Rejoin EU | 236 | 0.87% |
| 9 | Brunch | Official Monster Raving Loony Party | 87 | 0.32% |
| 10 | Spiby-Vann | Christian Peoples Alliance | 63 | 0.23% |
| 11 | Walker | UK Independence Party | 51 | 0.19% |
| 12 | Fischer | Climate Party | 51 | 0.19% |
| 13 | Pipaliya | UK VOICE | 23 | 0.08% |
| 14 | Silberman | Communist League | 9 | 0.03% |
| 15 | Darwood | Independent (no description) | 7 | 0.03% |
Source: Returning Officer, London Borough of Camden, declaration page https://www.camden.gov.uk/holborn-and-st-pancras-by-election-2026-results (sha256 1cd90be9f1f4c718…), transcribed 2026-10-09T06:13:41Z
Forecast against result
Run B of v0.2, the headline, against the declared shares of the valid vote. Residual is actual minus forecast, in points; σ is the residual in units of the line’s implied standard deviation (80% band ÷ 2 × 1.2816). Zero lines carry a point forecast and no interval (Ad3.7).
| Line | Forecast mean | 80% interval | Actual | Residual | σ | In band |
|---|---|---|---|---|---|---|
| Abdi-Wali | 47.00 | [43.06, 50.85] | 45.17 | −1.83 | −0.60 | yes |
| Polanski | 24.01 | [20.94, 27.25] | 32.81 | +8.80 | +3.58 | no |
| Newman | 15.73 | [14.55, 16.97] | 5.92 | −9.81 | −10.39 | no |
| Stillman | 4.78 | [4.42, 5.15] | 3.40 | −1.38 | −4.85 | no |
| Galloway | 4.29 | [0.37, 7.88] | 1.15 | −3.14 | −1.07 | yes |
| Cameron | 3.50 | [3.24, 3.78] | 7.06 | +3.56 | +16.90 | no |
| Brunch | 0.47 | [0.44, 0.51] | 0.32 | −0.15 | −5.49 | no |
| Walker | 0.22 | [0.20, 0.24] | 0.19 | −0.03 | −1.92 | no |
| Darwood | 0.00 | point (zero line) | 0.03 | +0.03 | — | no |
| Fischer | 0.00 | point (zero line) | 0.19 | +0.19 | — | no |
| Johnson | 0.00 | point (zero line) | 2.54 | +2.54 | — | no |
| Kapoor | 0.00 | point (zero line) | 0.87 | +0.87 | — | no |
| Pipaliya | 0.00 | point (zero line) | 0.08 | +0.08 | — | no |
| Silberman | 0.00 | point (zero line) | 0.03 | +0.03 | — | no |
| Spiby-Vann | 0.00 | point (zero line) | 0.23 | +0.23 | — | no |
| Margin (Lab-runner-up) | 22.98 | [16.58, 29.15] | 12.36 | −10.62 | — | no |
| Turnout (reporting prior, % of electorate) | 38.0 | [28.0, 48.0] | 38.76 | +0.76 | — | yes |
Coverage: 2 of 8 simulated lines inside their 80% bands; 0 of 7 zero lines; 3 of 17 scored quantities in all.
Scores
- Winner: forecast Labour, actual Labour — correct. P(hold) as pinned 1.0000 — near-degenerate, flagged as pinned (§6.2); a 1.0000 call carries no calibration information. Binary Brier 0.00000.
- Runner-up: forecast Polanski, actual Polanski — correct.
- Margin: forecast 22.98 [16.58, 29.15], actual 12.36 — outside the 80% interval. Margin bucket: P(margin ≥ 10.0) 0.9941 as pinned; the modal bucket realised.
- Turnout: reporting prior 38.0 [28.0, 48.0], actual 38.76 — inside the interval; the prior moved no share.
- Coverage: 3 of 17 scored quantities inside their 80% intervals.
- Scoring pass:
by-elections-2026-10-08· scored 11 October 2026 at 13:30 · ledger row 45 · 15 lines scored · modelholborn-stp-by2026-v0.2· frozen 7 October 2026 at 12:00 · snapshot md5d143a5890e831388e238e72e8226942d - The interval scores (Winkler, α = 0.2) and the scoring functions as pinned are in the settlement and scoring record.
- Ledger note: Holborn and St Pancras by-election — scored; snapshot_md5 committed post-result (2026-10-10, PR #388 bd49c87, INF-150 ruling 2026-10-10): pre-result evidence is the live-DB pin of row 18 at 2026-10-07T12:13:33Z and the branch push of 578cf4a at 2026-10-07T12:20Z
Probability of a Labour hold
Probability of a Labour hold: above 0.99 under the model’s spread. That spread is too narrow for a by-election; the number is near-degenerate, is recorded as such in the calibration ledger, and is published rather than adjusted.
Where the forecast stands
- Constituency polls used: none published as of 15 October 2026.
- Register: collapsed at SOPN on 15 September 2026 — the sole collapse trigger. 15 candidates.
- Polanski is the sole focal challenger; Galloway stands on a line carved from the 2024 Feinstein block (Ad.3).
- National-swing term: per-party on non-focal lines from v0.2; the focal line moves only through the consolidation term (Ad.1).
- Final freeze: the last vintage at or before 12:00 UK on Wednesday 7 October is the scored forecast (Ad.4).
The recorded market
Betfair prices are recorded for a post-hoc comparison only — they are never a model input. Final pre-poll recorded figure: 93% Labour hold (midpoint basis, 8 October 2026 at 06:39, 8,260 captures).
How to read this
This is a pre-registered forecast: the structure and priors were frozen before any number was computed, and every change since is a dated addendum that removes nothing. It is scored at declaration against the frozen vintage, on the record, whatever the result.
Vintage history
| Vintage | Date | Tag | Role |
|---|---|---|---|
| v0.1 | 1 September 2026 | freeze/holborn-stp-by2026-v0.1 | prior-only branch mixture (PARTIAL headline) |
| v0.2 | 16 September 2026 | freeze/holborn-stp-by2026-v0.2 | single field, run B headline — the forecast of record |
The lineage is append-only: a new vintage is a new row, and this page always renders the newest row of record — no frontend change is needed when one lands.
Provenance
- Spec lineage:
freeze/holborn-stp-by2026-spec-v0.1→freeze/holborn-stp-by2026-spec-v0.1-ad1→freeze/holborn-stp-by2026-spec-v0.1-ad2→freeze/holborn-stp-by2026-spec-v0.1-ad3→freeze/holborn-stp-by2026-spec-v0.1-ad4→freeze/holborn-stp-by2026-spec-v0.1-ad5 - Vintage:
freeze/holborn-stp-by2026-v0.2· forecast row id 18 · 500,000 draws · seed 20260901 · common random numbers across vintages · headline run per Ad1.3 - Nowcast read: nowcast-v2.7 (model_registry is_current; Ad1.5)
- The frozen document: raw markdown (served byte-identical to the committed file) · the committed file on GitHub · sha256
f2683affe96b4a570c70c6f863bbc0c074f28eba6b73998e89375ba6391f87c5 - Scored record: ledger row 45 (
by-elections-2026-10-08) · residuals under the same pass · settlement and scoring record on GitHub - The post-mortem: raw markdown (served byte-identical to the committed file) · the committed file on GitHub · sha256
20519e6595971f2dd70f0ee544873c5faf2b8166e6f9c406deb12e1a6eccb5cc
Post-mortem — what we said, what happened
forecasts/byelections/holborn-and-st-pancras-2026-10-08-postmortem.md — reproduced without alteration · sha256 20519e6595971f2dd70f0ee544873c5faf2b8166e6f9c406deb12e1a6eccb5cc · GitHub
# Holborn & St Pancras by-election: what we said, what happened
**Contest:** Holborn & St Pancras, Thursday 8 October 2026. **Forecast of record:** vintage `holborn-stp-by2026-v0.2`, formed 16 September 2026, frozen under Addendum 4. **Scored:** 11 October 2026, scoring version `by-elections-2026-10-08`.
> Bracketed fields are filled by CC from the INF-151 artifacts only (scored `calibration_ledger` row, `calibration_residuals`, `by_election_results`, `by_election_result_parties`). No other edits to this text; wording changes go back to Chat.
## In one paragraph
We said Labour would hold the seat with a lead of 23 points over Zack Polanski, 80% interval 16.6 to 29.2, and put the probability of a Labour hold above 0.99 while flagging that number as too confident for a by-election. Labour held the seat. Sagal Abdi-Wali won by 12.4 points. The winner and the runner-up were right. The margin was outside our 80% band, and so were five of the seven party lines we simulated. The forecast was right about the result and wrong about the shape of it. This document says where, by how much, and what changes.
## The result
| Candidate | Description | Votes | Share |
| -- | -- | -- | -- |
| Abdi-Wali | Labour Party | 12,292 | 45.17 |
| Polanski | Green Party | 8,928 | 32.81 |
| Cameron | Conservative Party | 1,922 | 7.06 |
| Newman | Reform UK | 1,612 | 5.92 |
| Stillman | Liberal Democrats | 924 | 3.40 |
| Johnson | Restore Britain | 692 | 2.54 |
| Galloway | Workers Party of Britain | 314 | 1.15 |
| Kapoor | Rejoin EU | 236 | 0.87 |
| Brunch | Official Monster Raving Loony Party | 87 | 0.32 |
| Spiby-Vann | Christian Peoples Alliance | 63 | 0.23 |
| Fischer | Climate Party | 51 | 0.19 |
| Walker | UK Independence Party | 51 | 0.19 |
| Pipaliya | UK VOICE | 23 | 0.08 |
| Darwood | Independent | 7 | 0.03 |
| Silberman | Communist League | 9 | 0.03 |
Labour majority 3,364 (12.36 points). Valid votes 27,211; 108 rejected; turnout 38.76%. Source: Camden Council declaration, transcribed with its page hash into the repository (`backtrack/hd/holborn/scoring/declared_result_2026-10-08.json`).
## Forecast against result
Run B of the v0.2 vintage, the headline. Error is forecast minus actual, in points of valid vote.
| Line | Forecast mean | 80% interval | Actual | Error | Inside band |
| -- | -- | -- | -- | -- | -- |
| Labour (Abdi-Wali) | 47.00 | [43.06, 50.85] | 45.17 | +1.83 | yes |
| Green (Polanski) | 24.01 | [20.94, 27.25] | 32.81 | −8.80 | no |
| Reform (Newman) | 15.73 | [14.55, 16.97] | 5.92 | +9.81 | no |
| Conservative (Cameron) | 3.50 | [3.24, 3.78] | 7.06 | −3.56 | no |
| Liberal Democrat (Stillman) | 4.78 | [4.42, 5.15] | 3.40 | +1.38 | no |
| Workers (Galloway) | 4.29 | [0.37, 7.88] | 1.15 | +3.14 | yes |
| Restore (Johnson) | 0.00 (null line) | — | 2.54 | −2.54 | — |
| Margin, Labour − runner-up | 22.98 | [16.58, 29.15] | 12.36 | +10.62 | no |
| Turnout (reporting only) | 38 | [28, 48] | 38.76 | — | yes |
Winner: Labour, forecast probability 1.0000 (flagged near-degenerate at publication). Runner-up: Green, forecast probability 1.000. Margin bucket: canter (≥ 10 points), forecast 0.994, realised at 12.36.
## What the scores say
* Winner identity: correct. Log loss 0.0000. The probability was published as >0.99 with the §6.2 flag; it is scored as recorded, not as we would now set it.
* Runner-up identity: correct.
* Margin: central 22.98, actual 12.36, error +10.62. The result lies 4.2 points below the lower 80% bound. Interval score (Winkler, α = 0.2): 54.744.
* Coverage: 2 of 8 simulated lines inside their 80% bands (Labour and Workers).
* Turnout: prior 38 [28, 48], actual 38.76. The prior moved no share; it was reporting only.
## Where the error came from
In order of size.
**1. The challenger line.** The Green line was 24.0 against 32.8. The term that carries by-election consolidation behind a challenger (spec §2(d)) was pre-registered at N(+10.9, 8.9) from the June contests. Addendum 3 (16 September) cut its coefficient to one third for this field: halved because the block it drew from had been split by Andrew Feinstein's withdrawal, then two thirds of the remainder to the focal line. On the carved Green base of 19.9 the full prior puts the line at about 31; with the Green national movement added, about 35. That is arithmetic on the base lines, not a simulation run. The damping was a ruling made blind, before any number was computed, and it cost about seven points. The run we recorded as a diagnostic — run C, which applies the national delta to the focal line as well — put Labour at 45.1 against 45.2 and the margin at 18.0 with a band [11.8, 23.9] that contains the result. We flagged that convention at v0.2 as a possible double count. It was not.
**2. The locals.** The May 2026 Camden result (Labour 32.8, Green 27.1, Camden People's Alliance 3.2, borough-wide) was a better prior for the challenger than the 2024 result plus swing. The spec gave the locals no weight. On 17 September we recorded the gap between our conditional (0.998) and the market (about 0.70) as a difference in what was being modelled, not an error in the price: the market priced direct Labour-to-Green switching, which the model has no term for. The result says that channel was real and about eight points wide.
**3. The swing convention on small lines.** Addendum 1 applied each party's national movement since 2024 as a uniform additive shift on the non-focal lines (run B, the headline). The vintage document flagged this as a known limitation for Reform, whose +8.7-point national rise was added to a 6.1-point local base. Run B had Reform at 15.7 and the Conservatives at 3.5. The result was 5.9 and 7.1. The comparator run A, which moved only the Labour line, had 7.1 and 8.3 — within 1.3 points of both. Across the four by-elections we have scored this parliament (Makerfield, Aberdeen South, Arbroath, Holborn) we have now understated the Conservative line and overstated the Reform line in every one.
**4. The carve.** Feinstein's 2024 vote (18.9) was split on his endorsement: 60% retained, two parts to Polanski and one to George Galloway. Galloway took 1.2. The block went to Polanski, or stayed at home, almost whole. A candidate with no local line and no local organisation gets about one point; the carve gave him four.
**5. Null lines.** Restore Britain was given an explicit zero: no 2024 line, no national series. It took 2.5, having taken 6.8 in Makerfield four months earlier.
**6. Spread.** Two of eight simulated lines inside their 80% bands. The flag on P(hold) said the model's spread was too narrow for a by-election. It is too narrow on every line, not only on the headline.
## What held
* Winner, runner-up and margin bucket.
* Labour's own share: 47.0 [43.1, 50.9] against 45.2.
* Turnout: 38 [28, 48] against 38.8.
* Publishing margin-led, with P(hold) flagged rather than adjusted. The flag was the right call; so was leaving the number alone.
* The vintage was pinned before polling, and the forecast file and its sha256 are unchanged from 17 September. See the freeze note below for what was not done in time.
## The market, read afterwards
Betfair prices are recorded for comparison only and never enter the model. The first capture, on 3 September, had Labour last traded at 1.40 — about 70% with the book's margin removed. On 6 October the recorded figure was 94%. On polling-day morning it was 93% (midpoint basis). The last price before polls closed was 1.03. The market settled Labour at 02:14 UTC on 9 October, with £264,839 matched across 8,856 captures.
On the probability, the market was better calibrated than we were: 0.93 is closer to a fair reading of a 12-point hold than 1.00. On direction, the model was right from 1 September and the market moved more than 20 points toward it. We record both and claim neither as skill. This is one contest, and the market's move coincided with Labour's national recovery and the Greens' difficult final week. The market priced a channel we lacked; we were overconfident on a direction that turned out right.
## A synthetic instrument, scored
Before the cut-off we pre-registered a synthetic polling instrument on this contest, recorded and not used. It is not a poll and we do not publish it as one. It places language-model respondents on a 240-cell frame of the constituency (age, sex, qualification, 2024 vote), raked from the census and the 2024 result, and aggregates their answers. Four arms: two on a local 14-billion-parameter model, two on an API model, each with and without a context pack of national polling and local facts dated 30 September. Snapshots were hashed and committed on 30 September (local) and 2 October (API), before the 7 October cut-off. Spec `HOLBORN_SILICON_SHADOW_SPEC.md` v0.1, frozen blind.
Scores against the declaration, with the forecast of record for comparison:
| Arm | Labour | Green | Con | Reform | Lib Dem | Margin (actual 12.4) | MAE, 15 lines | Runner-up |
| -- | -- | -- | -- | -- | -- | -- | -- | -- |
| Forecast of record (v0.2) | 47.0 | 24.0 | 3.5 | 15.7 | 4.8 | 23.0 (+10.6) | 2.18 | correct |
| API, with context | 37.4 | 21.5 | 4.3 | 8.8 | 13.5 | 16.0 (+3.6) | 3.11 | correct |
| API, no context | 35.6 | 18.2 | 5.7 | 7.6 | 19.2 | 16.5 (+4.1) | 3.60 | wrong |
| Local, with context | 43.4 | 5.6 | 10.4 | 11.1 | 5.7 | 32.3 (+19.9) | 3.90 | wrong |
| Local, no context | 46.2 | 5.6 | 14.4 | 3.1 | 6.2 | 31.9 (+19.5) | 4.07 | wrong |
| Actual | 45.2 | 32.8 | 7.1 | 5.9 | 3.4 | 12.4 | — | Green |
**Reading.** Every arm called the winner. The API arms beat the forecast of record on the margin and lost on the lines: they placed Labour eight to ten points low and the Liberal Democrats ten to sixteen points high, and the errors cancelled. A margin that is right for the wrong reasons is not skill. The local arms put Polanski at 5.6 against 32.8 and are unusable on a challenger line. The context pack moved the API arm three points toward the result on Polanski and six points toward it on the Liberal Democrats. Cost of the four arms: £1.64 in API calls and about three pence of electricity.
**Known limitations of this run.** Listed so a reader can see what it tests and what it does not.
* A first instrument, specified blind, with no scored event to calibrate against.
* The frame has four axes. It has no tenure, ethnicity, religion or ward, and no turnout-propensity weighting beyond a single turnout item. A proper post-stratification frame is the programme's next build.
* The local model is a 14-billion-parameter model at 4-bit quantisation, the largest the hardware runs. About 78% of its cells returned an identical answer distribution: it did not distinguish one respondent from another. That is a known failure of small models, and the flag that catches it fired as designed.
* The API model is a small, fast variant with reasoning off. Four of 720 cells in the context arm were lost to rate limits.
* The context pack predates the final week, including the Green conference motion of 4 October, and no constituency poll existed to anchor it.
* No pollster house-effect correction is stored for this instrument, so none was applied.
The programme's value bar is to beat an MRP on the same anchor and a swing model on a real election, with an ablation arm on every run. One event cannot pass or fail it. The next scored event sets the verdict; these results go into it as recorded.
## The freeze
Addendum 4 set the scored vintage as the last at or before 12:00 UK on 7 October, with its snapshot hash committed before 07:00 UK on 8 October. The vintage was pinned in the database at 12:13 UTC on 7 October and the branch carrying the pin was pushed at 12:20 UTC. The hash itself was not committed before polling: the hashing step could not canonicalise the row's candidate object and stopped for a ruling while the decider was away. The hash was committed after the result, under a ruling of 10 October that scores against it and records the gap here. The pre-result evidence is the database pin and the branch push; the committed forecast document and its sha256 (`f2683aff…`) are unchanged from 17 September. We state this because the point of pre-registration is that readers can check it, and on this contest the check is weaker than it should be.
## What changes
These are intentions, recorded now. Each lands as a dated addendum or a new spec before it is used, and never during a contest.
1. The focal line carries the national delta (run C's convention), and the consolidation prior is applied undamped for a party-leader challenger.
2. A locals-derived prior for the challenger line where the most recent locals show the challenger second across the seat.
3. Non-focal lines move multiplicatively or on the logit scale, with a regional delta where one exists, not a GB additive shift.
4. Differential turnout enters the shares; the turnout prior itself stays.
5. No null lines for a party with a declared result in any by-election this parliament.
6. The freeze path is rehearsed end-to-end on a synthetic row before the decider is unavailable, as the poll path was.
## Provenance
* Forecast of record: `freeze/holborn-stp-by2026-v0.2`, `byelection_forecasts` row 18, 500,000 draws, seed 20260901, nowcast-v2.7 read. Document sha256 `f2683affe96b4a570c70c6f863bbc0c074f28eba6b73998e89375ba6391f87c5`.
* Spec lineage: `freeze/holborn-stp-by2026-spec-v0.1` → `-ad1` → `-ad2` → `-ad3` → `-ad4` → `-ad5`.
* Declaration: Camden Council returning officer's page; transcript with page sha256 in `backtrack/hd/holborn/scoring/declared_result_2026-10-08.json`.
* Scored ledger row: `contest_id = holborn-and-st-pancras-2026-10-08`, `scoring_version = by-elections-2026-10-08`, row id 45; residuals in `calibration_residuals`.
* Market series: Betfair market 1.261869476, recorder captures 3 September to 9 October 2026, delay-key prices.
* Synthetic instrument: `HOLBORN_SILICON_SHADOW_SPEC.md` v0.1, tag `freeze/holborn-silicon-shadow-v0.1`; snapshots and md5 sidecars under `backtrack/hd/holborn/`; scoring record `backtrack/hd/holborn/scoring/scoring_2026-10-09.{json,md}`; `calibration_ledger` rows 40–43, `scoring_version = silicon-shadow-v0.1`, contest type `silicon_shadow`. Recorded, not used.
---
## Appendix — copy for the /by-elections index (CC pastes verbatim)
**Scored-forecasts line, append:** `Holborn & St Pancras ✓ (Lab >0.99 — margin band missed)`
**"What the by-elections tell us", append after the June paragraph:**
Holborn & St Pancras (8 October 2026) was the first routine vacancy in a safe Labour seat with a challenger from the left. Labour held by 12.4 points. We had the winner and the runner-up right, the margin 10.6 points too wide, and the Conservative line understated for the fourth contest in four. The post-mortem is on the Holborn page.
**Summary table, new column "Holborn":** turnout 38.8% · Con vote share 7.1% · Lab–Reform gap +39.3pp.
**Results block (same shape as Makerfield):** Labour hold — majority 3,364 (12.4%) · turnout 38.76% · rows from `by_election_result_parties`.
The frozen vintage document, verbatim
forecasts/byelections/holborn-and-st-pancras-2026-10-08-v0.2.md — reproduced without alteration.
# Holborn & St Pancras by-2026 — v0.2 vintage (SOPN-collapse, prior-only) — 2026-09-16 **Version tag:** `holborn-stp-by2026-v0.2` · **Formed:** 2026-09-16 (INF-48 session) **Governing spec:** `HOLBORN_STP_BY2026_SPEC.md` v0.1 + Ad.1 + Ad.2 + **Ad.3**, tag `freeze/holborn-stp-by2026-spec-v0.1-ad3` (merge `1da8704`, blob `4f64412c`) — Ad.3 committed and tagged **before** this engine pass (ruling condition (i)); implemented exactly as written. **Engine:** `analysis/holborn_stp/holborn_stp_v02_model.py` · seed **20260901** (dated-seed convention, unchanged from v0.1) · **500,000 draws** · CRN — v0.1's term streams (a, c, k) drawn in v0.1's exact order, **one new stream g appended** (Workers entry variance, Ad3.8); stream identity with v0.1 asserted in-engine, and the v0.1 engine re-run before this pass reproduced `holborn_stp_v01_results.json` byte-identically. Run differences are structural, never sampling noise. **Election date:** 2026-10-08 (Ad.2; rows from Ad.2 onward carry the real date). **Prior-only:** the §5 gate is unfired — `constituency_polls` (id 290) = 0 rows, checked 2026-09-16; no published VI poll known (Ad.3 pre-registration statement). **Market-blind:** no price, odds, or implied probability entered any input path. **Results of record:** this file + `holborn_stp_v02_results.json`. Byte custody: directory is scoped `* -text`. --- ## Register collapsed — residual R realised; headline no longer PARTIAL SOPN published 2026-09-15 (Camden Council; 15 candidates; Feinstein not on the paper). The field falls to **R** per the 2026-09-16 STOP report; the 2026-09-16 ruling (Ad.3) defines its treatment. All subsequent vintages are **single-field** on the SOPN set. The v0.1 PARTIAL label is resolved: the residual is no longer an unsimulated branch — it is the field. --- ## 1. Inputs of record **Field (Ad3.1/Ad3.7):** 8 simulated lines — Lab, Green (Polanski, **focal**), **Workers (Galloway, carved)**, Con, Reform, LD, OMRLP, UKIP; **7 explicit zero lines** — Climate, Rejoin EU, UK VOICE, Communist League, CPA, Restore Britain, Darwood (Ind); exits to abstention — Feinstein remainder (0.4 of block), Islam (Ind), SEP, Kumar (Ind), Smith (Ind). **Carve (Ad3.4):** Feinstein block 18.94 pp (7,312 votes) → retention 0.6 = 11.37 pp (4,387.2), split **2:1 Polanski:Galloway** on the endorsement: Polanski transfer **7.58 pp** (2,924.8) onto the Green line; Workers line **3.79 pp** (1,462.4). Remainder 7.58 pp exits per §2(ii). Renormalised bases: Lab 54.08 · Green 19.92 · Workers 4.19 · Con 7.95 · Reform 6.79 · LD 6.40 · OMRLP 0.46 · UKIP 0.21. **Terms (spec §2 + Ad.3), single field:** | Term | Value | Applied to | |---|---|---| | (a) vacancy | N(−1.5, 2.0) pp | Lab, all runs | | (b) national swing | per-run delta map below (uniform additive, Am.A1/Ad1.1) | see runs | | (c) succession bounce | N(+3.0, 4.0) pp | Lab, all runs | | (d) consolidation | N(+10.9, 8.9) pp floored at 0, **coefficient 1/3** (damped ×0.5, focal's 2/3 share — Ad3.5) | Green (Polanski), sole focal | | Workers entry | N(0, 3.0) pp on the carved base, line truncated at 0 (Ad3.4) | Workers only | | (e) turnout | central 38, 80% [28, 48] — **reporting only** | share-neutral | **Nowcast vintage (2026-09-16, SNAPSHOT, strict `<`, nowcast-v2.7 per Ad1.5 — `model_registry` is_current verified; n=26, oldest 2026-06-29, house effects off)** vs GE-2024 GB baselines: | Party | Nowcast | GE24 GB | Δ (pp) | Run A | Run B | Run C | |---|---:|---:|---:|---|---|---| | Lab | 25.6 | 34.7 | **−9.1** | applied | applied | applied | | Con | 19.9 | 24.4 | −4.5 | — | applied | applied | | Reform | 23.4 | 14.7 | +8.7 | — | applied | applied | | LD | 10.8 | 12.5 | −1.7 | — | applied | applied | | Green | 11.1 | 6.9 | +4.2 | — | — (focal, (d)-only) | applied (diagnostic) | | SNP | 2.8 | 2.6 | +0.2 | — | — (no line) | — (no line) | Workers, OMRLP, UKIP: no nowcast series — no (b) delta in any run (Ad3.6). Zero (b)-floor events in all runs. Workers truncation clipped 8.1% of draws (the ruled truncation at 0, not an Ad1.1 floor event). **Mechanics:** restrict + carve → renormalise → apply pp terms → clip at 0 → renormalise (spec §2 (i)–(iv)). **Canter boundary unchanged: margin ≥ +10 pp.** --- ## 2. Run outputs (Ad1.3 protocol, focal = Polanski) *One MC pass per run; the three runs share the CRN streams and differ only in the term-(b) delta map. Run B is the headline regardless of what C shows (Ad1.3).* ### Run A — comparator: Lab-only (b), frozen §2(b) as v0.1 · P(Lab hold) **1.0000** | Line | Mean | 80% | P(win) | |---|---:|---|---:| | Lab | 48.22 | [44.19, 52.16] | 1.0000 | | Green (Polanski, focal) | 24.64 | [21.48, 27.96] | 0.0000 | | Workers (Galloway) | 4.40 | [0.38, 8.08] | 0 | | Con | 8.29 | [7.65, 8.96] | 0 | | Reform | 7.08 | [6.53, 7.65] | 0 | | LD | 6.67 | [6.16, 7.21] | 0 | | OMRLP · UKIP | 0.48 · 0.22 | | 0 | Margin 23.58 [17.02, 29.90] · canter 0.9948 · runner-up Green 1.000 ### Run B — **HEADLINE**: Ad1.1 per-party on non-focal lines · P(Lab hold) **1.0000** | Line | Mean | 80% | P(win) | |---|---:|---|---:| | Lab | 47.00 | [43.06, 50.85] | 1.0000 | | Green (Polanski, focal, (d)-only) | 24.01 | [20.94, 27.25] | 0.0000 | | Workers (Galloway) | 4.29 | [0.37, 7.88] | 0 | | Con | 3.50 | [3.24, 3.78] | 0 | | Reform | 15.73 | [14.55, 16.97] | 0 | | LD | 4.78 | [4.42, 5.15] | 0 | | OMRLP · UKIP | 0.47 · 0.22 | | 0 | Margin 22.98 [16.58, 29.15] · canter 0.9941 · runner-up Green 1.000 *(Reform's +8.7 delta on a 6.14-pp base is the Ad1.7 known limitation — recorded, not adjusted.)* ### Run C — diagnostic: per-party including the focal line · P(Lab hold) **0.9998** Lab 45.08 [41.27, 48.80] · Green 27.12 [24.15, 30.24] (P(win) 0.0002) · Workers 4.11 [0.35, 7.57] · Con 3.36 [3.12, 3.61] · Reform 15.09 [14.00, 16.23] · LD 4.58 [4.25, 4.93] · margin 17.95 [11.75, 23.94] · canter 0.9475. --- ## 3. Headline (run B — single field, NOT PARTIAL) | Quantity | Value | |---|---| | **P(Labour hold)** | **1.0000** (4 dp; near-degenerate, flagged per §6.2 — P(upset) < 5×10⁻⁵) | | P(canter: margin ≥ 10) | 0.9941 | | P(contested hold: 0 < margin < 10) | 0.0059 | | P(upset: challenger wins) | 0.0000 (4 dp) | | Lab share | 47.00, 80% [43.06, 50.85] | | Margin (Lab − runner-up) | 22.98, 80% [16.58, 29.15] | | Runner-up | Green (Polanski), 1.000 | --- ## 4. Decomposition (Ad1.3/Ad3.8) vs v0.1 PARTIAL headline of record | Effect | Definition | ΔP(hold) | ΔLab mean | ΔMargin | ΔP(canter) | |---|---|---:|---:|---:|---:| | **Candidate-set effect** | A(v0.2) − v0.1 (R-carve sits inside this effect) | **+0.0535** | +3.47 | +4.30 | +0.2116 | | **Convention effect** | B − A (Ad1.1 alone) | 0.0000 | −1.22 | −0.60 | −0.0007 | | **Focal-line sensitivity** | C − B (diagnostic; cannot change Ad1.1 in-arc) | −0.0002 | −1.92 | −5.03 | −0.0466 | The v0.1 → v0.2 move is almost entirely the candidate-set collapse: the hinge branch **B2 (Feinstein stands without Polanski, 0.38 weight, the only branch whose 80% margin interval crossed zero) did not realise**. The Ad1.1 convention costs Labour 1.22 pp of mean share and nothing measurable in win probability. The double-count question (C − B): applying the focal's national delta on top of (d) would move the margin −5.03 pp and P(canter) −0.0466 — recorded as an Ad1.3 finding for the post-mortem, not a re-ruling. --- ## 5. Sensitivity lines (Ad3.5 — base-line arithmetic only, no MC pass; reported, not adopted) | Split Polanski:Galloway | Transfer (pp 2024) | Workers carve (pp 2024) | Green base (renorm) | Workers base (renorm) | |---|---:|---:|---:|---:| | **2:1 (adopted)** | 7.58 | 3.79 | 19.92 | 4.19 | | 1:1 (bracket) | 5.68 | 5.68 | 17.82 | 6.28 | | 3:1 (bracket) | 8.52 | 2.84 | 20.96 | 3.14 | The (d) coefficient would move with the ratio under the same mechanic; it is not recomputed (Ad3.5). --- ## 6. CRN proof + turnout Streams sha256/16: a `e6eae8fa4db4f093` · c `629d947102a5f0be` · k `bdc72985e4cd42df` · **g `824894b907fab0a3` (appended)**. In-engine assertion: a/c/k byte-identical to a fresh generator run of v0.1's draw sequence; v0.1 engine re-run 2026-09-16 reproduced its tracked JSON byte-identically (git diff empty). Run A thereby reproduces v0.1's Lab-only draws at stream level (Ad3.8). Turnout: reporting prior 38% [28, 48] of electorate; conditional map **degenerate at this vintage** (share-neutral §2(e)); stated, not silently skipped. --- ## 7. Row of record + revision protocol `byelection_forecasts` row, model_version `holborn-stp-by2026-v0.2`, status `live`, `frozen` FALSE, `election_date = 2026-10-08` (Ad.2 — no pre-writ sentinel). Insert migration `supabase/migrations/20260916170000_holborn_stp_by2026_v02_vintage.sql`, applied at/after merge under merge-and-report with a rolled-back trial insert first. Annotated vintage tag `freeze/holborn-stp-by2026-v0.2` on the merge commit (Clacton vintage-tag naming). The v0.1 row (id 16) is untouched — append-only. Revisions per spec: weekly vintage refresh owned by the weekly check; first constituency poll → §4 protocol (the §5 gate has then run; v0.3 pre-poll freeze per Ad1.3 runs B only); all appends, never edits.