All notable changes to Grim Arithmetic are documented here.
Compatibility bump only; no changes to the underlying mortality math.
- Verified against Foundry VTT v14.364.
Repository-facing polish; no changes to the underlying mortality math.
- Renamed the release archive from
grim-arithmetic-v<version>.zipto a stablemodule.zip(the version stays in the release path), so the download count can be tracked accurately atop the README (KHT-130). - Added Latest Release, Downloads, Foundry Verified, and License badges to the top of the README (KHT-130).
First release using updated CI process. No other material changes.
Release candidate focused on decluttering and unifying the three windows; no changes to the underlying mortality math (KHT-129).
- Encounter Forecast: shows only the selected tactics profile's description instead of all five; keeps the vital "not modeled" caveat inline and collapses the rest; moves the high-risk warning below the statistics; adds a "Forecast Completed" status chip; the run button toggles to Cancel while running; light dividers separate the result tables.
- Encounter Danger Board: the version now sits as small text under the title; a single-line risk-band legend (Grim → Low) with thresholds sits above the lists; removed the redundant header instruction line; each row shows the risk label before the percentage; the window starts wider; tighter row spacing.
- Unified typography across all three windows on Foundry's native Signika body font with Modesto Condensed titles, replacing the previous mix of fonts.
- Optimized spacing, sizing, and semantic box colors throughout.
Release candidate building on v0.7.2-rc1; no changes to the underlying mortality math.
- The Encounter Forecast's Biggest Threats table now lists enemies from most to least dangerous, sorted by their share of total damage descending; enemies showing the same percentage are ordered alphabetically by name (KHT-126).
- The Encounter Forecast's Most Likely to Drop table now lists party members from most to least at risk, sorted by their chance of being downed descending; party members showing the same percentage are ordered alphabetically by name (KHT-127).
Release candidate. Three usability fixes on top of v0.7.1; no changes to the underlying mortality math.
- The Grim Arithmetic settings section is now GM-only — regular players no longer see any module options (KHT-118). The GM-facing options carry clearer descriptions of what each one does.
- Hover help across all three windows now waits a beat (750ms) before appearing, so tooltips no longer flicker continuously while scanning down a list of values (KHT-120).
- The risk-rating tooltip now spells out the full ladder — Low, Guarded, Dangerous, Severe, Grim, with the chance-of-being-downed band for each — instead of just "Low → Grim" (KHT-121).
Builds on v0.7.0's ApplicationV2 migration with internationalization groundwork, on-hover help across every window, clearer tactics options, and a real CI/release pipeline. No changes to the underlying mortality math.
- The GM-facing UI is now translation-ready. The three settings, all window titles, and every static label, heading, button, and tooltip across the Encounter Danger Board, Pair Detail, and Encounter Forecast load from a bundled language file (
lang/en.json). English ships in the box, with no visible change for English users.
- On-hover descriptions on every labeled metric, control, and table header across all three windows — e.g. "Any PC down", "TPK risk", "Recovery checks per run", "MAP", "Damage swing", "Dying if downed" (KHT-108).
- The Encounter Forecast lists an inline definition for each tactics profile (Random Legal, Spread Damage, Focus Fire, Predator, Boss Cinematic) above the selector, and tactics labels read more clearly (KHT-111).
- Verified against Foundry VTT v14.363.
- Removed the unknown
system/templatesmanifest keys that triggered a Foundry package warning. - Added GitHub Actions CI (lint + tests + build on every push/PR) and a tag-driven release workflow; published the
docs/reference set on GitHub.
Release candidate adding internationalization (i18n) scaffolding so the GM-facing UI can be translated, plus developer tooling. No visible text changes for English users.
- All UI chrome now loads strings from a language file (
lang/en.json) through Foundry's localization system: the three settings, the three window titles, and every static label, heading, button, and tooltip across the Encounter Danger Board, Pair Detail, and Encounter Forecast windows. English ships in the box, and the module is now translation-ready. - Engine-generated caveats and risk labels remain English for now and are tracked for a follow-up pass (KHT-112).
- Added GitHub Actions:
test.yml(lint + tests + build on every push/PR) andrelease.yml(tag-driven release with automatic prerelease detection for-rctags). - Published the
docs/reference set (install, testing, release, arithmetic) on GitHub; release packaging now bundleslang/.
Release candidate adding inline definitions for the Encounter Forecast's tactics profiles, plus label polish.
- The Encounter Forecast window now shows a bulleted list defining each tactics profile (Random Legal, Spread Damage, Focus Fire, Predator, Boss Cinematic) directly above the Tactics Profile dropdown. Definitions are driven by the engine's existing
TACTICS_PROFILE_DESCRIPTIONS, so they stay in sync with simulation behavior. - Capitalized the second word of each multi-word tactics label and the word "Profile" in the control heading.
- Bumped verified Foundry compatibility to v14.363.
Release candidate adding on-hover descriptions across all three GM windows so the dense PF2e mortality metrics explain themselves.
- Every labeled metric, control, and table header in the Encounter Forecast, Encounter Danger Board, and Pair Detail windows now carries a
data-tooltipdescribing what it means — e.g. "Any PC down", "TPK risk", "Recovery checks per run", "Hero Point saves", "MAP", "Damage swing", "Dying if downed". - Uses Foundry v13+'s native
data-tooltiptooltip system, so no extra JavaScript or CSS is required and the panel context builders are unchanged.
- Removed the unknown
systemandtemplateskeys frommodule.jsonthat triggered a Foundry package warning. Thepf2esystem requirement is already declared viarelationships.systems, and templates are loaded at runtime through each panel's ApplicationV2static PARTS.
v0.7.0 migrates Grim Arithmetic's three windows off the deprecated V1 Application framework so Foundry v13+ no longer logs a console deprecation warning, plus a small set of UX fixes against the V2 dark window theme.
- Pair Detail and Encounter Forecast windows are bounded (640 / 720) and resizable, with
.window-contentset tooverflow-y: autoso long content scrolls inside the window instead of being clipped below the viewport. - In-content headers simplified: Pair Detail shows
Pair Detail, Encounter Forecast showsEncounter Forecast(the fullGrim Arithmetic — <panel>label stays in the window chrome title bar). - Pair Detail labels (form
<label>, summary<dt>) inherit the V2 window's primary text color instead of the hard-coded dark brown that read as muddy orange on the dark window background. - Encounter Danger Board:
Encounter Forecastbutton moved beforeDetail Selection + Target, both buttons re-cased to title-case.
- Encounter Danger Board, Pair Detail, and Encounter Forecast now extend
foundry.applications.api.HandlebarsApplicationMixin(ApplicationV2). - V1
defaultOptionsgetter → V2static DEFAULT_OPTIONS(window/position/classes/actions sub-objects). - V1
getData()→ V2_prepareContext(). Return shapes (DangerBoardPanelData,MortalityPanelData,ForecastPanelData) are unchanged, so all 322 unit tests pass without modification. - V1
activateListeners(html)jQuery bindings replaced by:- V2 declarative
static actionsmap for all buttons (data-action="openDetailPair","openDetailSelection","openForecast","refresh","run","cancel"). - Native
addEventListener('change', …)inside_onRenderfor the<select>controls in Pair Detail (six selects) and Forecast (tactics profile), since the V2 actions map is click-only.
- V2 declarative
- Forecast: V1
close()override replaced by V2_preClose()so the in-flight Monte Carlo worker handle is still cancelled when the window is dismissed mid-run. - Static
instancesingletons preserved forPairDetailPanelandForecastPanel; cross-panel openers (openForPair,openForSelection,open) keep the same signatures sosrc/main.tsAPI and the toolbar entrypoint insrc/ui/token-controls.tsdid not need changes. - Templates updated: button
data-grim-*attributes swapped todata-action="…";<select>data-grim-control/data-grim-forecast-controlattributes preserved.
Bugfix release surfacing the Phase I-A safety-net stats that v0.6.0 was already computing but never displaying, plus a more robust PF2e Heal-spell extractor for real-world prepared-caster actors.
- Added a "Heals per run / Recovery checks per run / Hero Point saves" row under the headline metrics so GMs can see whether PC healing, recovery checks, and Hero Point death prevention actually fired during the simulation (KHT-105).
- Prepared casters:
extractHealCapabilitynow walksspellcastingEntry.system.slots.slotN.prepared(the canonical PF2e v6+ shape) and counts un-expended preparations whoseidreferences a Heal spell item, instead of only reading aslotsRemainingfield that real PF2e prepared casters do not populate. This is the root-cause fix for "Mira's heals never fire." - Spontaneous casters: when an entry's
prepared.value === 'spontaneous'and Heal is in its spell list, the entry's per-rankvalue(remaining slots) is counted as Heal-castable. - Item access now prefers
actor.itemTypes.<type>(PF2e's pre-filtered arrays) over walkingactor.items, with the latter as a fallback. Removes one class of "items collection looked empty" failure modes. - Legacy item-level
slotsRemainingfallback retained for completeness so existing synthetic fixtures still pass.
- When the Debug logging module setting is enabled, the encounter setup builder logs each PC's extracted healing capability (Battle Medicine, Heal cantrip, Heal spell slots, Medicine modifier, Medicine DC).
- The PF2e adapter additionally emits a verbose
extraction probelog per PC dumping item-type counts, every Heal spell found, and the raw slot/prepared structure for each spellcasting entry — so future shape mismatches between Grim Arithmetic and the PF2e system can be diagnosed from a console paste without source access.
- Removed two dead identifiers (
ITERATION_CHOICES, an unusedtotalIterationsparameter) that were trippingnpm run lint.
- Foundry v13+ logs a console deprecation warning for the V1 Application framework. The warning is non-fatal until Foundry v16; the three panels (Encounter Danger Board, Pair Detail, Forecast) will be migrated to
ApplicationV2in v0.7.0 (KHT-106). - A
"message channel closed before a response was received"console error reported in some sessions traces to a browser extension'schrome.runtime.onMessagelistener, not Grim Arithmetic. The module uses zero Chrome extension APIs (KHT-107 — closed as external).
v0.6.0 introduces a Monte Carlo encounter simulation engine, a Forecast panel, and Phase I-A PC survival mechanics. The following summarizes the main changes across all rc releases.
- New pure-TypeScript Monte Carlo engine with seeded determinism (
mulberry32PRNG +xmur3hash). - Five tactics profiles: random-legal, spread-damage, focus-fire, predator, boss-cinematic.
- Round orchestrator aggregates any-PC-down, TPK, mean/median rounds-to-first-down, per-PC down/death/HP, per-enemy damage share and top target.
- Web Worker integration keeps the Foundry UI responsive during 1k–10k iteration runs; synchronous fallback for headless/Vitest.
- Engine guardrails:
MAX_ITERATIONS = 10000, cooperative abort, and per-client toggle (defaults on). - Default round cap lowered from 10 to 5 to keep no-action simulation in a plausible range.
- New ~800w Forecast window opened from the Encounter Danger Board header.
- Headline metrics (Any PC down, TPK risk, Expected first down) with active tactics profile name + description.
- Per-PC table rows with down %, death %, and mean first-down round.
- 95% confidence intervals on all proportion and continuous metrics, computed from sampling variance.
- Pessimism banner when any-PC-down ≥ 80%, framing results as an upper bound.
- Simplified UI: fixed 5,000 iterations, removed seed input, default tactics changed to Spread damage.
- PCs now take 2 Strikes per turn against the most-dangerous standing enemy in the simulation.
- PF2e adapter extracts PC Strikes from
actor.system.actionswith equipped-weapon fallback. - Healing: Battle Medicine (Medicine check vs DC, proficiency-scaled heal, crit-fail collateral), Heal spell 1/2/3-action variants, Heal cantrip with heightened scaling. Heal on a dying target clears dying per PF2e.
- Recovery checks: dying PCs roll DC 10+dying at the start of their turn; degree-of-success steps dying by −2 / −1 / 0 / +1.
- Hero Point death prevention: when a PC would die, they spend a Hero Point to drop to dying 0 at 0 HP (one survival per iteration per PC).
- PC tactics substitutes Strikes for heal actions when an ally is dying (emergency full-turn heal) or below 40% HP (top-up 1-action heal + 1 Strike).
SimulationResult.safetyNetaggregates (meanHealsPerIteration,meanRecoveryChecksPerIteration,heroPointSurvivalRate) surface in the UI.
- Forecast assumption block rewritten to reflect the active PC model.
- Fixture snapshots regenerated across all five tactics profiles (13 snapshots).
docs/ARITHMETIC.mdupdated with the Monte Carlo pipeline, tactics profiles, seeding rules, and the "not modeled" scope.
Still not modeled (deferred to later milestones):
- Shield Block and Champion reactions (Liberator/Redeemer/Paladin)
- Spells beyond Heal / save-based threat modeling
- Persistent damage
- Attacks of opportunity, movement/reach/LoS, initiative-altering abilities
- Permanent-death probability
- Quick-scenario presets, A/B compare, quantile/distribution view
- UI split: the Token Controls skull button now opens an Encounter Danger Board as the main window. The single-PC vs single-enemy detail view lives in a separate Pair Detail popup (one reusable instance).
- Read PC and hostile NPC tokens from the active combat encounter without requiring individual token selection.
- Compute pairwise immediate down-risk for every supported (PC × hostile × Strike) triple by reusing the existing
immediateDownRisk()engine. - Danger board shows "Most endangered PCs" and "Most dangerous enemies" formatted as
PC vs Enemy Attack — XX% Label. Each row has a Detail button that opens the Pair Detail window for that exact pair. - A top-level "Open detail for selected PC + targeted enemy" button preserves the v0.4.x select-and-target workflow.
- Catch per-pair errors so one bad Strike does not poison the whole encounter board.
- Add a
MAX_PAIRS = 200performance guardrail that short-circuits to a skipped board with a clear caveat instead of freezing Foundry on very large scenes. - Graceful errors if a referenced token is no longer on the canvas (combat ended or scene changed).
- Remove the previous combined
MortalityPaneland its template. - Update
docs/ARITHMETIC.md,docs/TESTING.md, andBACKLOG.mdto match the split UX.
- Mark the module manifest as verified against Foundry VTT v14.361 after initial server smoke testing.
- Update README and testing/install docs to describe v13 minimum plus v14.361 verified status.
- No runtime code changes were required for the initial v14.361 smoke test.
- Read PF2e immunities, weaknesses, and resistances from
system.attributes, which is where current PF2e character data exposes them. - Keep legacy top-level IWR fallback for older or fixture-like data shapes.
- Include IWR fields in sanitized debug capture when present.
- Extract simple PF2e resistances, weaknesses, and immunities from actor data.
- Extract primary Strike damage type when available.
- Apply matching resistance, weakness, and immunity to exact normal/crit damage distributions.
- Show the applied damage adjustment note in the panel.
- Keep ambiguous/unknown damage types conservative: no adjustment is silently applied.
- Add MIT license for public/open-source distribution.
- Add Foundry manifest URL and versioned download URL fields.
- Add release packaging script that builds a direct-install Foundry zip.
- Add release-package metadata tests.
- Update release docs with manifest URL install and GitHub Release workflow.
- Add wounded/doomed dying-severity output.
- Add doomed-adjusted death threshold flagging.
- Add Hero Point prevention assumption messaging.
- Keep permanent death probability explicitly out of scope.
- Replace average-only down-risk with exact damage probability mass functions for supported formulas.
- Add damage range, average damage, and swinginess output.
- Use exact cumulative distributions across modeled Strike sequences.
- Add module version display, refresh/recalculate, enemy Strike selector, clearer errors, fixture hardening, and sanitized debug capture.
- Initial GM-only selected-PC vs targeted-enemy immediate down-risk panel.