npm run sim:r1 sweeps the Reinforcements rate that was adopted on 15 Sep,
against a metric that did not exist then. The verdict is
tools/sim/battle/REINFORCEMENTS.md; the criterion is
PREREGISTRATION-R1.md, committed in its own commit before
reinforcements.mjs existed, because the same session built the instrument,
ran it and read the result.
The finding. The Crossing as canon writes it leaves the Shadow absent for a
full Turn in 31% of battles, and momentarily absent in 49% — while the
Oathband wins 74.6% of those same battles in a median 7 Turns. A win-rate
measurement structurally cannot see an empty board, which is why this does not
contradict the 15 Sep pricing ("reinforcement is not the difficulty lever").
The two measure different things, and the metric is what decided the finding.
Of five rates at 10,000 battles an arm, only light — 2 faces of two Foes,
4 of one, 6 of none, first rolled Turn 2 — clears both bounds: **4.3%
collapse, 37.9% overrun, 1.66 Pilgrims OOA**. Everything heavier breaches
overrun; the 15 Sep rate misses the collapse target at 10.1%. The
selection rule ("leanest clearing both bounds, ties to lower OOA") was
committed with the criterion, before any data, because with six variants and
five metrics some variant wins on some reading.
Turn 2 beats Turn 1 for a reason the brief did not anticipate: median first
contact is Turn 3, so a Turn-1 arrival lands before the sides have met and
merely enlarges the starting force — 4.0 points of overrun for 0.7 of collapse.
The brief was overtaken, and answered against itself. It pre-authorised
building a separate abstract Trial model on the premise that nothing plays
Trials Turn by Turn. campaign.mjs does not, but crossing.mjs does, and
already implemented every mechanic the brief listed as needing building — plus
the reinforcement rule Keith had already ruled on. The engine was extended
instead, and its defaults did not move: `--reinforce-variant adopted
--arrival ahead` reproduces all four committed baselines numerically, so every
figure in NATURES.md still stands.
Three of the brief's "fixed inputs (decided)" contradicted canon and are
recorded in the report rather than quietly resolved: the **First Road premade
Oathband does not exist** (Breaker and Hunter are Shadow Champions, Stalwart is
absent from the corpus, Wayfarer is a word on the name generator); there is **no
Move stat and the brief omits Valour; and "week 1 (Renown 0)" is wrong** —
canon starts 4 Pilgrims at Renown 4 — and changes nothing, because ⌊4/10⌋ = 0
and both arms are byte-identical at 4.80 Foes. That null is a clean
demonstration of recorded canon gap #3, "Doom below 10 adds no Foes".
New: reinforcements.mjs (rates and arrival geometry as data, on the
natures.mjs pattern), reinforcements-report.mjs (the sweep),
reinforcements.test.mjs (22 mutation tests — a collapse rate is only
meaningful if the metric can be driven to a known value), and the npm scripts
sim:battle, sim:r1, sim:r1:test. Collapse derives from foesOnBoard,
signal 1 of the 2.6 pre-registration, so no new signal was invented and
--summary-json's contract is untouched; --outcome-json is a separate
emitter.
Also corrected: reinforce() was headed // PROPOSAL, off by default, which
had been untrue since the 15 Sep ruling adopted it and turned it on — a stale
marker in the file CLAUDE.md names as the worked example of the derivation
convention.
Reported against itself. On open-ground overrun reaches 41.7%, past the
bound, and is in the table rather than dropped. The brief's "22 Sep playtest
(1 OOA)" has no in-repo source and is not treated as a measurement. And two of
the brief's three archetypes are not delivered: the Vigil and the Reckoning
need an invented Oathband policy that would itself determine the collapse rate
it was built to measure, so they are named as the follow-up with their own
pre-registration rather than guessed at.
A correction, and a bug found by reading the Decision Log. Keith ruled on
23 Sep that reinforcement resolves the Shadow Generation table in full, "roll
twice" included, "however deep it goes" — citing a Turn-2 quadruple arrival as
what made a Trial memorable. reinforce() did not do that: it read "Roll
twice" as ONE reroll rather than TWO results, and dropped the slot entirely on a
second 'twice', so a quadruple arrival was unreachable. rollShadowForce() at
deployment had always been correct, so **the same canon table was resolved two
different ways depending on which end of the battle you were at.** Fixed, pinned
by a test (figures per arrival now measures 1.20, the deployment figure
shadow-nature-packages.md states), and every arm re-measured. The
recommendation did not change; the figures moved up to a point, and two of them
are already printed in canon and in the Decision Log row for Keith to correct.
Also corrected in the report: the brief's two-phase Reckoning was not an
invention — it is Settled 13 Jul 2026 in the Decision Log, just never written
into the-reckoning.md (In Canon: NO), so the synced mirror was stale rather
than the brief wrong. And the Moor readiness audit the brief cited does
exist, in the Decision Log, DONE 22 Sep; it just is not Plan row 5.5.
Still owed, and not doable from this container: the mirror is two chapters
short. Reinforcements on the Moor (22 Sep) and Reinforcements (24 Sep) are
both in the Rules database and neither is synced. There is no NOTION_TOKEN
here, so npm run sync and npm run sync:campaign are owed on a machine that
has one.
PR [#39](https://github.com/iamkeithmason/pilgrimage/pull/39).