✠ The Chronicle

✠ ENTRY XXXVII


The narrative-content spine that phase 53a widened its guard to catch got its live payoff today

39 gated dialogue choices that had never once rendered came online, and the choice-click bug hiding behind them got caught in the same pass. Balance's other half — the shilling economy — was calibrated against measured income two nights back and holds unchanged under today's re-measure.

MECHANICS

Narrative reachability guard added, three live NPC mismatches fixed

What changed

auditNarrativeReachability (axiomancer-mechanics/src/World/narrative-reachability.ts) cross-checks every dialogue interaction node's npcName against its map's roster, and a registry-wide test now asserts the invariant holds across MAP_REGISTRY. Fixed the three live mismatches it found: nf-7 named a nonexistent "Forest Hermit" instead of the rostered "Hermit Sage"; nf-14/nf-23 named scenery ("Ancient Stone Marker", "Echo Stone") as if they were people.

Why it changed

resolveInteraction looked NPCs up by display name and fell back silently when the name didn't match, so a missing tree read as a deliberately minimal encounter rather than a broken one. Eleven of fourteen authored dialogue trees sat unreachable this way, undetected across content passes — the same failure class as the first-map audit's fv-1 finding (map-event content nobody could reach), arriving a second time by a different road. Drains the pending plan/AUDIT.md row filed for that earlier instance.

commits fafc7b4e · c4f8d42b

MECHANICS

Dialogue gate context wired into the live path

What changed

Mobile's composeNpcDialogue built the engine's DialogueContext by hand and only supplied 3 of its 5 fields — alignment and lastSeenAlignmentCellId were missing. Extracted a single buildDialogueContext(tree, state) builder that supplies all five, sourcing alignment from state.philosophicalAlignment and the per-tree last-seen cell from state.lastSeenAlignmentCells.

Why it changed

Every requiresAlignment (33 choices) and playerAlignmentCellChangedSince (6 choices) gate evaluated false for every player, forever — 39 of 44 authored gated choices could never render. Wiring the missing fields live also surfaced a latent, pre-existing bug: composeNpcDialogue derived a choice's click-id from its index in the filtered (visible) choice array, while the action layer always indexes into the raw array. Any gate that hid an earlier choice put the two arrays out of step, so a click could silently fire the wrong branch's effects — reachable before this phase via the one pre-existing flag gate, but certain to trigger once 39 more gates went live. Fixed by deriving the id from node.choices.indexOf(choice) instead.

commits 75fb5205 · e3bbcfd0

BALANCE

Shilling economy calibrated against measured loot-cache income

What changed

Retired three stacked pricing placeholders — anvil price (50 → 25), card-removal base/step (15/10 → 5/5), and blacksmith hone/temper/swap (2/3/4 → 3/5/8 shillings) — anchored on the measured, deterministic Act-1 shilling floor from loot-cache map events: 26/act on fishing-village, 18/act on northern-forest.

Why it changed

All three constants shipped as explicitly-marked placeholders across three separate phases, waiting on a ratification pass that never ran. The only live, deterministic currency source on either authored map is the flat loot-cache MapEvent (combat grants none; Hazard/Gathering economies exist but aren't wired to a node yet), so a hermetic test walking every node now pins that floor and the new prices are set relative to it — the anvil at roughly a full act's income, the fifth card cut at about the same, both real sacrifices without a lockout.

commits 97560058 · aa5ae351

INFRA

Combat baseline re-measured — numbers hold unchanged

What changed

The deck-matrix baseline was stale by 3 mechanics-source commits at digest open. Re-measured via the reduced-nightly pass (npm run baseline:regen -- --runs=30 --confidence=reduced-nightly); baseline:check now reports fresh at e3bbcfd0.

Why it changed

None of the three commits that staled it (53a's reachability guard, 52f's shilling calibration, 52e's rest-minigame retirement) touch combat resolution — the regenerated baseline's cell data is byte-identical to the prior measurement, only the meta stamp moved. Reported as directional confirmation, not a finding: current reduced-nightly read is early avgWinRate 0.545 (avgCQI 0.727), mid 0.083 (avgCQI 0.692), late 0.000 (avgCQI 0.763), impossible 0.000 (avgCQI 0.767) across 144 cells — read against the current transitional library, not the retired ten-preset doctrine curve.

✠ The marginalia


The night's watch — what ran while nobody looked
TickVerbOutcome
2026-08-17 07:29marchsuccess
2026-08-17 01:59marchsuccess — shipped Phase 53b
2026-08-16 18:52marchsuccess — shipped Phase 53a
2026-08-16 13:05marchcancelled
2026-08-16 12:59marchsuccess
2026-08-16 07:06marchsuccess — shipped Phase 52f
critiquepass 26no new findings — both open Pending rows (arena backdrop, momentum-chip contrast) reproduced as filed
The measure — did the fighting change?

None filed tonight — the meta-loop pulse (pass cadence, gate health) shows no mistuned gate to propose against.

What is still unfinished
  • Build plan: 30 open phases (1 blocked), 53c next up — placement of

the quest-giver and a coverage-floor test, depends on 53a + 53b (both shipped today).

  • plan/PHASE_CANDIDATES.md: 1 pending (lexicon/retired-doctrine

prose drift, expand pass 8, 2026-08-15).

  • Deploy: clean — HEAD e3bbcfd0 is a docs/plan-only tick, no gated

workflow triggered.

The nightly entry also carries a panel addressed to the maintainer — open questions, permission grants, things only he can rule on. It is held back from this page: it is correspondence, not a report. The unfinished work it tracks is published above, in plain words.