Alpha Release Notes

Angel Snack Patch Notes

Current game version: 0.1.0-alpha.24. 25 published releases, latest 0.1.0-alpha.24.

Back to game

Angel Snack 0.1.0-alpha.24 Patch Notes

Release date: 2026-09-16

Stage: alpha

Package version: 0.1.0-alpha.24

These notes are gathered from the release fragments in docs/patch-notes/unreleased/.

Gameplay

  • Add staged Act III encounter formations: Added four staged Act III mainline encounter formations: Ward Court's removable protector, River Triage's lowest-Life heal, Idol Battery's adjacent charge and lightning impact, and Toll Priest's zero-damage one-turn Energy drain. Each formation keeps its escorts on ordinary attacks. Idol Battery does not yet add a source-linked idol damage bonus. Formation clones normalize inherited traits; Ward Court is the sole formation carrying WARDING.
  • Act 2 now teaches four recurring combat lessons through escalating encounter families.: Act 2's mainline now revisits four recognizable enemy formations in stronger versions. Break fortified lines, prioritize mixed hunting parties, respect a mauler's warned impact and recovery, and interrupt attendants before their delayed healing lands; ordinary battles remain in the rotation between these lessons.
  • Act II optional minibosses now open behind finite formations with learnable support cycles.: Radomir and the Pale Conjurer now begin their optional Act II fights behind two defenders. Defeated defenders stay dead, while each miniboss follows a readable fixed cycle that heals or wards whichever allies remain.
  • Make the Act 2 boss court and telegraphs more readable: Sepulcher Devourer now follows a learnable burrow-to-impact rhythm, keeps one finite Burial Attendant instead of a sprawling court, and gains clearer difficulty-tier variations for its summon-board and Guard-break pressure.

Balance

  • Fix rewardInvestedSkillBiasEnabled's biased reward slot being inert: it now draws from all invested skill cards (not just the current pool tier window) and picks with a tier-weighted seed (50/30/20 by tier), and the sim's autoplay chooser now actually scores the option instead of ignoring it.: Under the rewardInvestedSkillBiasEnabled flag (still default off), a card reward's second option is meant to follow a skill you've already invested a point in. It was quietly never firing in practice, because the offer only looked at cards still in that reward's current tier window — by the time an early investment paid off, its card had usually rotated out. That slot now looks at every card behind your invested skills, weighted toward the ones you invested earliest, and the autoplay pilot now actually takes it when it's a comparable option instead of ignoring it.

UI

  • Make Lightning Charge and Bladework combat forecasts explicit: The hero inspector now explains Lightning Charge's current stacks, its 3-Energy turn-end decay, and exactly when its next qualifying life-damage instance will deal double damage. Battlemaid Sarina now shows Bladework progress in enemy inspection and target readouts, with a clear whole-party warning when Sword Dance is ready to cleave.

Fixes

  • Smoothed played-card spotlight effects during combat: Played-card spotlight blooms now stay fluid during repeated combat actions, especially on high-refresh mobile and desktop displays, while retaining the same glow and timing. Resting hand cards also give their rules more readable room without changing their gameplay text.

Tech

  • Measure Act III encounter-family mechanics in simulations: Simulations now preserve realized healing, Guard, charge-to-impact, Energy toll, WARDING, and defeat-order measurements for fully tagged encounter families, without counting hypothetical scoring branches.
  • Sim history rows now carry buildSnapshot + acquisitions (TELEMETRY-SCHEMA §8d) — final deck/charms/equipment and an ordered acquisition event log — plus scripts/run-build-divergence-report.js to read them.: Internal sim-telemetry addition — no player-facing change. Fleet balance-run history rows now record each run's final deck/charms/equipment and an ordered log of how every card/charm/item was acquired, enabling a new build-provenance divergence report.
  • Add the approved Game Design Vision (seven pillars, ROG-1906) and point every design philosophy doc at the pillars it serves: New docs/design/GAME_DESIGN_VISION.md (owner-approved 2026-09-16, ROG-1906): the global statement of how the game plays — seven pillars P1–P7, the five-act arc, tensions, non-goals, reviewer verdicts, and the owner-decisions log. Indexed first in docs/design/README.md and named in SYSTEMS-OVERVIEW.md as the reference the Design column is judged against. Sixteen existing design docs carry a > Serves GAME_DESIGN_VISION.md pillar(s): … line so the pillar a system serves is visible from the doc itself. No gameplay change.

Angel Snack 0.1.0-alpha.23 Patch Notes

Release date: 2026-09-15

Stage: alpha

Package version: 0.1.0-alpha.23

These notes are gathered from the release fragments in docs/patch-notes/unreleased/.

Gameplay

  • Act 1 now teaches four recurring combat lessons through escalating encounter families.: Act 1's mainline now teaches four recurring combat lessons through escalating enemy formations: hunt dangerous ranged attackers, shut down affliction support, sequence around thorny protectors, and remove summoners before they fill the board. Later versions build on formations you have already defeated while ordinary battles remain in the mix.

Balance

  • Amazon Dodge starts as Dodge + Guard; one point in Dodge adds Fade to every copy.: Dodge is simpler to start and worth investing in. It now grants Dodge 1 and 12 Guard for 1 energy — the Heal and the extra draw are gone, so the opening deck reads as one clear defensive action. Put a single point into Dodge and every copy you own gains Fade 1, at the same cost: a way to slip out of a dangerous target's attention on a card you were already playing. Further points add Guard, and at rank 5 the upgraded Dodge+ keeps the Fade on top of its bigger Guard. Runs already in progress keep the old Dodge exactly as it was.
  • Flag-gated (default off): the second card option of a regular-clear card reward can favor cards backing skills the run has already invested rank in.: When the invested-skill reward bias is enabled, the second card option after a regular clear is drawn from cards whose skill you have already put a point into (when one is eligible and not yet at its copy limit), so early tree investment more often meets the card that makes it matter. The first option and the rest of the offer are unchanged, and the flag ships off until the fleet A/B reads it (ROG-1878).
  • Warlock Miasma starts leaner; one point unlocks the Chaos-spell prime.: Miasma now deals poison damage and applies Poison for 1 energy, but no longer gains Guard or draws a card — and no longer primes your next Chaos spell — until you put a point into it. One rank in Miasma unlocks the Chaos-spell prime on every copy you own, and direct damage keeps climbing with further investment. Miasma never gains Guard or draws again at any rank of investment — that combination now costs the same one point of investment Bash, Dodge, and Prayer/Cleansing already ask for. Runs already in progress keep the old Miasma exactly as it was.
  • Paladin Prayer and Cleansing start leaner; one point unlocks Prayer's Draw or Cleansing's Guard.: Prayer now heals and gains Guard for 1 energy, but no longer draws until you put a point into it — one rank in Prayer unlocks Draw 1 on every copy you own, and Guard keeps climbing with further investment. Cleansing narrows to a straight heal at rank 0; a point in Cleansing adds 4 Guard to every copy, and Heal keeps climbing with further investment. Neither card ever drew and gained Guard for free again — that combination now costs the same one point of investment Bash and Dodge already ask for. Runs already in progress keep the old Prayer and Cleansing exactly as they were.

Content

  • Barbarian starts with Stun in the opening deck.: The Barbarian's starting deck now carries a Stun in place of one of its three basic Attacks. Stun deals 10, applies 1 Stun and builds 2 Rage, so it earns its slot as an opener — and it means every Barbarian run has a way to shut down a heavily armored enemy's turn from the start, instead of hoping the right reward shows up. The deck is still 13 cards.
  • Bash starts as a clean Rage-building strike; one point in Bash adds Stun to every copy.: Bash is simpler to start and worth investing in. It now deals 14 and builds 2 Rage for 2 energy — the Guard and the situational bonus damage are gone, so the opening deck reads as one clear action. Put a single point into Bash and every copy you own gains Stun 1, at the same cost: a second way to shut down a heavily armoured enemy's turn, on a card you were already playing. Further points add damage, and at rank 5 Bash+ keeps the Stun on top of its Rage payoff. Runs already in progress keep the old Bash exactly as it was.
  • Deathmark is now a unique relic: found from act bosses after Rift I, never offered at the charter or sold.: The Assassin's Grand Charm: Deathmark is now a unique relic. It no longer appears in the run-start charm pick and can't be bought from a vendor — instead, clear Rift Tier 1 with the Assassin to unlock it, then find it dropping from act bosses during your runs, same as any other boss trophy.

UI

  • Combat hand cards no longer mid-word-break their rules text, hide it under the next card, or split a keyword from its number.: On desktop, the rules text on your hand cards no longer breaks words in the middle, and it now stops short of the next card in the fan instead of disappearing under it. Keywords stay attached to their numbers too, so a line never starts with a stray "8." Cards with very long rules can still run past the bottom of the band; lift the card to read the full text while that is worked on.
  • Respec-point preview now names the capability, Card+, or SHELL coverage a purchase would take away.: The camp sage's respec-point offer now tells you exactly what a purchase would do before you buy it: which capability a gated card would lose (like Bash's Stun), whether a Card+ copy would revert to its base form, and whether your deck would be left without an answer to a threat like SHELL. The first skill-point tutorial also spells out how ranks work: base cards play now, rank 1 adds a capability, ranks 2-4 make it stronger, and rank 5 upgrades every copy to Card+.
  • Skill-tree previews now show what a rank unlocks (and, for cards, when it grants a copy or Card+) in the live run and the wiki archive.: Class-tree nodes now tell you what the next point actually buys. A rank that unlocks a card rider (like Bash's Stun 1) shows the capability and its scaling on one line and which copies gain it on the next, ahead of the plain rank number. A rank that grants a bonus copy or upgrades every copy to Card+ says so on its own line, in the live run and on the wiki's class archive.
  • Every authored zone now has its own GPT Image 1.5 High combat backdrop, with distinct landmarks and atmosphere across all five acts.: Every journey now has a stronger sense of place: each authored zone uses a dedicated combat arena with its own landmark, terrain, weather, and lighting instead of borrowing a generic backdrop from another location.

Fixes

  • An upgraded Bash+ always applies its Stun, and runs on the old rules read the old rules on the card.: Taking Bash+ as a card upgrade no longer leaves you with a Stun you cannot use. An upgraded card is the finished version of itself, so Bash+ applies its Stun whether or not you ever spent a point in the Bash node — previously it stayed locked, and the reward preview greyed it out as if you still had to buy it. Separately, a run that started before the Bash rework now prints the old rules on the card it is actually playing: the bonus damage against a staggered target was still being dealt but had stopped appearing in the card's text. The rank-1 preview line on a card you have not invested in yet is readable now: it sits on its own line under the card's rules instead of squeezing in beside them, in a colour that shows up against the card's parchment.
  • The mystery-charm vendor no longer offers scenario charms, which are acquired only through their route checkpoints and could be sold into a full pouch because they are exempt from the pouch slot budget.: The town's mystery-charm vendor no longer lists scenario charms. Those charms are earned only at their route checkpoints, and because they do not count against the pouch's slot budget the vendor could sell one to you even when your pouch was already full. The vendor's pool is now the same rarity-and-class filtered set as before, minus those exempt charms; nothing else about its prices or stock changes.
  • Sim pilot no longer treats a SHELL brute's turn-3 expiry as a crack it earned; only a landed Poison, Freeze, or Stun scores the crack bonus.: Balance-sim only, no change to play. The pilot's scorer paid the same crack bonus when a shelled brute's shell simply timed out on turn 3 as when the pilot cracked it with an answer card, so with deeper lookahead it learned to wait instead of spending Poison, Freeze, or Stun. Expiry now earns nothing. The local shell sweep tool also keeps one fight seed per deck and encounter across all arms, so its gate and pilot comparisons run on the same draws.

Tech

  • Add a verify script so the pre-push gate's checks can be run before committing: Running the repo's verify script now performs the same code-quality checks the pre-push gate performs, so a change can be checked before it is committed rather than at push time. Previously there was no way to run the gate's check set locally, so a change that skipped one merged cleanly and then blocked the next person to push, who had to diagnose someone else's failure before doing their own work.
  • Card definitions can declare effects that unlock at a skill rank; the resolver that reads them lands ahead of any content using it.: No player-facing change. Card effects can now declare the skill rank that unlocks them, and one shared resolver works out which rules a copy actually has right now — so combat, the card face, and the sim will all read the same answer once cards start using it. No card is gated yet, and a run that started before this keeps every rule it had. The readers are now hooked up to it too: the card face, the skill tree, the reward picker and the sim pilot all ask the same question about a card, so once a rank unlock exists they'll all give the same answer. A card holding something back behind a rank shows one quiet extra line saying what that rank would add, and the tree tells you what a point buys before it tells you the numbers it moves. One small correction came out of it: a card whose only Poison sits in a delayed "foretold" payoff now counts as a shell answer, because it really does apply the Poison when it lands. Every card face now answers that question the same way — the decklist, the pile viewer, the Scout/Surveil picker and the reward preview join the hand and the lifted reading card. Behind the scenes, the sim's own scoring now applies the rank-5 Card+ swap the engine was already executing, so the next rebaseline is not comparable with earlier ones on that axis. That swap now reaches the whole decision, not half of it: the pilot was pricing a rank-5 card by its Card+ in some parts of a choice and by the base card in others. Prerequisites, counter and aura scoring, cycle tax, the beam's follow-up check and the autoplay suggestions all read the one definition the engine will actually execute.
  • Fleet experiment backlog: operator-approved batches the daemons publish when the fleet drains, without gaining the power to choose the work (ROG-1853): No player-facing change. Balance experiments can now be queued ahead of time as fully-materialized, operator-approved batches, so the simulation fleet can start the next measurement the moment it goes idle instead of waiting for someone to notice. The daemons that publish a queued batch still cannot pick the pin, the runner, or the shard plan — they only replay a batch an operator already approved. Operators manage the queue with fleetctl-pg.js backlog add|list|next|remove|refuse|autoseed| sync-tickets (dry-run by default, --submit to write), and fleetctl status now reports how much work is queued and when the fleet last fired any of it. backlog autoseed queues a re-baseline whenever the simulator's own inputs move at origin/master — reader, docs and tooling commits do not count — replacing its own previous unfired one rather than stacking duplicates. Each fleet daemon runs a 15-minute tick that fires the next approved batch if the queue lets it. The admin HTTP submit endpoint now takes the same fleet-wide enqueue lock every other path does, so a re-baseline's "is the fleet idle?" check can no longer be raced by a submit from the dashboard. The /fleet dashboard gained a Backlog panel over the same queue: how much approved work is ready, what a daemon would fire next, when the fleet last fired anything, and how much of today's daily cap is already spent. It warns when the queue is empty (the fleet will idle once the running work drains) and when the simulator's inputs have moved since the last auto-seeded re-baseline.
  • Record applied skill-point investments and gated-card play counts in sim run history so the rank-unlock 2x2 report can measure first-investment timing and rank-5 timing under the existing planner, not just the marginal-unlock pilot.: No player-facing change. Balance sim runs now record which skill node actually took each class point (and when), plus per-gated-card play counts split before/after the card's rank-1 rider unlocks — under the existing planner as well as the marginal-unlock pilot — so the rank-unlock 2x2 report can measure the baseline-policy cells it previously had no telemetry for.
  • The sim pilot's skill-point allocation can now value what a rank actually unlocks, behind an off-by-default experiment arm.: No player-facing change. The balance sim's pilot used to spend skill points on where the point went, never on what it bought: a flat bonus for its preferred tree, a flat penalty for anything else. With card effects now able to unlock at a rank, that made the pilot blind to the choice the design is built around - splashing a cheap AoE or Poison to bridge the act you are currently losing to. Behind a new pilot-unlock experiment arm (off by default, so nothing changes until a fleet run promotes it), the pilot now resolves every affected deck copy at its current rank and at one rank higher and prices the difference: what the newly active effects are worth, whether they answer something the next act is about to ask that the deck currently cannot, and whether they add a capability the deck is missing entirely - discounted the later in the run it is bought. The preferred-tree bias is rescaled rather than piled on top, so a genuinely useful splash can win the point. Every decision it makes is logged with its reasons, so the upcoming content-versus-policy experiment can tell "allocation changed" apart from "allocation changed for the right reason."
  • Add a rules-version sim arm (legacy/current CARD_RANK) so ROG-1831's content x policy 2x2 runs at one pin.: No player-facing change. Balance experiments can now run the same seeds under the pre-unlock card rules (rules-version:legacy) and the current rules side by side at one code pin, so the rank-unlock work can be measured as content versus pilot policy instead of guessed at.
  • SHELL telemetry records where the answer was aimed, when it was first played, and whether it landed on the brute; kill turn no longer off by one.: No player-facing change. SHELL fight telemetry now records the turn an answer card was first played and whether it could reach the shelled brute at all, so balance analysis can tell a mis-aimed answer from a resisted one from one played too late. The recorded kill turn also no longer counts one turn high when the fight continued past the brute's death.
  • SHELL crack telemetry records which actor applied the cracking status (card, charm, mercenary, minion).: No player-facing change. SHELL fight telemetry now records which actor (a card, a charm, a mercenary, or a minion) applied the status that cracked a shelled enemy's damage gate, so balance analysis of the SHELL ask can credit a non-card answer as a real answer instead of reading it as unanswered.
  • SHELL telemetry: punishment measured after turn 2; the two-turn answer window and censoring now behave as specified: Sim telemetry for shelled packs now measures what the design says it does. Punishment is judged at the end of player turn 2, so a shell cracked during turn 2 counts as answered instead of punishing; the answer window covers turns 1 and 2, so an answer that only becomes affordable on turn 2 registers; and a fight that ends inside turn 1 is reported as unmeasured rather than silently counted. Shell rows written from here on carry telemetryVersion: 3, and the reader refuses those cells by name on older rows instead of pooling two different questions. No gameplay change.
  • The §F 2x2 reader no longer refuses a pilot-unlock cell for runs that died before reaching any skill-point decision.: Balance tooling only, no gameplay change. The content-x-policy 2x2 reader treated a missing marginal-unlock decision log as proof the policy arm never ran, so a handful of act-1 deaths — runs that ended before the first town skill-point decision, which is what creates that log — threw away an otherwise complete 100-seed cell. It now refuses only where a run proves it reached the chooser (it applied an investment the marginal scorer itself picked) and where no run in the whole cell carries the log at all; the remaining runs are reported as no-decision rows instead.
  • The §F 2x2 fleet reader reads the per-run investment telemetry, so first-point, rank-5 and per-card play metrics are measured on all four cells: Internal balance tooling only — no in-game change. The content-versus-policy 2x2 report now reads the per-run record of every skill point a run actually spent, which is written under every allocation policy rather than only under the experimental one. Allocation questions that the report previously had to leave unanswered on half its grid — where the first point went and when, when a card reached rank 5, and how often each rank-gated card was played before and after its unlock — are now answered for all four cells. Runs recorded before that telemetry existed still fall back to the older, narrower log, and the report labels those cells so a mixed comparison is never presented as a single clean measurement.
  • Add the ROG-1831 §F content x policy 2x2 reader for the rank-unlock content/policy experiment.: No player-facing change. A new fleet report reads the rank-unlock experiment's four cells (old versus new card rules, existing versus unlock-aware pilot) at one code pin with paired seeds, and refuses by name when the cells straddle pins, arms did not reach execution, or seeds are unpaired, so the read cannot quietly compare the wrong things.
  • The §F content x policy 2x2 reader can read a submission whose arms all share a composed-in gate (ROG-1831): No gameplay change. The balance tooling that reads the card-rank unlock 2x2 can now read a run whose four arms all carry an extra shared setting — the SHELL-ask gate has to be switched on in every arm for its own panel to measure anything, which previously made the whole run unreadable. The shared setting is named on the report so a read can never be mistaken for the ungated one, and a setting that is only in some of the arms is refused by name rather than quietly compared.
  • The §F content x policy 2x2 reader reads a single four-arm fleet experiment (ROG-1831): No gameplay change. The balance tooling that reads the card-rank unlock 2x2 experiment now understands the shape those runs are actually submitted in — one fleet experiment per class carrying all four arms — and splits its rows into the four cells by arm token, instead of requiring four separate experiments. An arm that has not ingested yet, or a row carrying an arm the 2x2 does not define, is refused by name rather than quietly producing a short cell.

Angel Snack 0.1.0-alpha.22 Patch Notes

Release date: 2026-09-10

Stage: alpha

Package version: 0.1.0-alpha.22

These notes are gathered from the release fragments in docs/patch-notes/unreleased/.

Gameplay

  • SHELL_BRUTE now gates all damage (instead of granting Guard) until Poison, Freeze/Stun, or turn-3 expiry cracks it. Flag-gated behind shellAskEnabled, DEFAULT OFF — not yet live.: Shelled Brutes (the SHELL_BRUTE act-2 pack modifier) no longer enter combat with a wall of Guard to chew through — instead they take zero damage from everything (cards, weapons, mercenary, minions, thorns) until their shell cracks, which only a landed Poison stack, a landed Freeze or Stun, or simply surviving to the start of the third turn will do. This is flag-gated behind shellAskEnabled, which stays DEFAULT OFF — it is not live in any run yet.

Balance

  • Flag-gated (default OFF): belt heal shares the per-turn utility-potion slot when beltPotionSharesUtilitySlotEnabled is enabled; sim arm belt-potion-slot.: An experimental, opt-in mechanic (default OFF, arm belt-potion-slot) makes the healing belt potion and prepared utility potions share the single per-turn potion action — only one of the two can be used each turn once the flag is on, with a matching UI disabled state and status message. No change to default play while the flag is off.
  • New SHELL_BRUTE encounter modifier: one Brute enters with Guard already up (flag-gated, not yet attached to any pack): No player-facing change yet. Adds the SHELL_BRUTE encounter-modifier handler (ROG-1785): the first alive Brute in a pack can enter combat with Guard already granted, sized to a configurable share of its max life. The modifier is not attached to any encounter yet — that lands separately (ROG-1786) behind the act-2 SHELL ask.

UI

  • Keep Arena setup and result content clear of the iPhone camera cutout in landscape.: Arena choices, result text, and action rows now use the shared left and right safe edges while retaining full-bleed scenery. Screenshot regression coverage checks both camera orientations at the two canonical phone sizes. The result ledger adapts its column count to the available width so longer metric labels do not overlap neighboring columns.
  • Preserve position and focus when choosing Arena loadout tiers on phones.: Choices within the same Arena step update the existing workbench instead of replacing its scrolling container. Moving between setup steps still starts the new decision at the top.
  • Keep Arena pre-fight target labels compact and encounter details readable.: Arena's target label no longer inherits oversized missing-art lettering. Encounter names, intent, stats, and tags use the shared readable text sizes and contrast. Hero calibration uses readable labels and larger level controls. The phone review scrolls through the summary and calibration without hiding the preset buttons. Completed phone setups use compact summary rows and omit the duplicate readiness checklist, bringing hero calibration closer to the selected encounter. The target portrait and stats take less vertical space on phones, and summary labels reserve enough width to stay separate from their values.
  • Show real unique effects and fixed bonuses in the Codex instead of flavor text alone.: Found items retain readable mechanics on phones, and effect search includes their rules and bonuses.
  • Refresh End Turn after drawing without rebuilding the hand and HUD.: Refresh End Turn after drawing without rebuilding the hand and HUD, and keep its accessible label consistent when drawing can be settled.
  • Keep one primary heading in fresh and saved Expeditions across phone and desktop Hall navigation.: Keep a single primary heading in fresh and saved Expeditions across phone and desktop Hall navigation without adding screen chrome.
  • Reworked the phone-landscape Account Hall into a notch-safe expedition stage with compact menu navigation and reviewable screenshot coverage.: The desktop menu retains a readable single-column destination list without horizontal clipping, while phones use the wider three-column sheet. The title-screen menu keeps utility labels readable in a stacked list instead of inheriting the wider Hall sheet's columns. Switching Hall destinations starts the new section at the top, keeping its class selector and opening decisions visible instead of inheriting the previous section's scroll position. Reselecting the current destination preserves your position. Runeword Codex now keeps its category controls inside the phone screen while its card shelf scrolls independently, matching the other Trophy categories. Charms now folds search, filters, and discovery guidance behind one compact control on phones, keeping the live count visible and giving revealed art more room. Charms, Unique Codex, and Achievements share this disclosure; desktop filters start open and retain a visible result count. Codex keeps all three filters and its discovery explanation available when expanded. Found Codex items now pair compact artwork with their name, scope, and readable description on phones, fixing oversized art frames and hidden item descriptions. Hall screenshot review now has shared populated-account fixtures for Charms, Codex, and Achievements, with guards against missing discovery data. Their run-history builder is a shared sibling module, keeping screenshot fixtures within the source-size limit without changing generated history. Review captures no longer wait for offscreen or clipped lazy images; broken visible artwork still blocks capture. Screenshot accessibility checks now recognize native form labels without treating option or field-value text as a label. The active Hall section now exposes one top-level heading to assistive technology, reusing the existing compact phone title or desktop scene title without adding header space. Revealed Charms on phones now pair artwork with wider, larger text so the first charm's name, effect, and source fit together in the opening view; undiscovered silhouettes remain compact. Phone Achievements now use wide swipeable art-and-text cards, keeping the first goal, reward, and progress together in view with larger text instead of narrow, clipped columns. Desktop Charms and Codex keep revealed cards at consistent gallery widths with bounded artwork, including when only one item is found. Codex names, scope labels, and phone status badges are larger, as is the empty Charm category guidance. The Account Hall now keeps the expedition choice prominent on landscape phones, clears the camera-side safe area, and moves its crowded section tabs into a wide three-column command sheet with larger destinations, clearer spacing, and an always-reachable title exit. Character Progress now uses a swipeable class rail and one readable full-width overview instead of squeezing a duplicate roster beside the account summary. Trophy categories now stay in one touch-sized row above a swipeable shelf of larger collection cards, so art and progress details are readable in the first view. Unique Codex removes its duplicate mobile title and brings collection silhouettes into the first view while preserving discovery progress and all filters. Achievements now keeps Search, Category, and Status behind one compact filter dropdown by default, leaves the live result count visible, and presents readable reward cards in a swipeable shelf with the first complete art frame visible immediately.
  • Shelled enemies now show a visible steel-ring cue on their sprite and a status-panel row explaining what cracks the shell.: A SHELL_BRUTE's shell was previously invisible outside of it silently no-selling every hit. The enemy now shows a steel ring around its sprite while the shell is up, and its inspect panel lists a "Shelled" status: "Takes no direct damage. Poison, Freeze or Stun cracks it; it breaks on its own on turn 3." Both clear the instant the shell cracks. shellAskEnabled stays default OFF, so this is invisible unless that flag is on.
  • Keep the saved Expedition resume action in the first phone screen with a compact hero summary.: The portrait now sits beside the hero details, while secondary Momentum stats follow the resume actions.
  • Some cards on the reward board now show a small telegraph badge and header chip hinting at what Act 2's packs will test next (behind an experimental flag, off by default).: When the next act's packs are about to demand something specific from your build (right now: tough Guard shells that only fall to poison, freeze, stun, or a heavy hit), the reward screen now says so up front — a small chip on the header names the coming test, and any offered card that answers it carries its own badge, so you can draft toward it instead of discovering the problem mid-fight. This lives behind an experimental flag and is off by default; nothing changes for players until it ships.
  • Open the Spellbook for browsing without automatically starting text entry.: Spellbook opening focuses Close instead of search, and phone search text uses the readable body size. Search remains available when selected; user zoom stays enabled. The count title wraps on narrow phones so it does not overlap search. Spellbook content respects the camera-safe margin on either edge of the phone. Off-screen deck and library illustrations defer loading while combat art retains immediate loading. Phone search and Close stay vertically anchored when filtering returns no spells.

Fixes

  • Opening approach choices fit together on iPhone with aligned actions and less wasted framing.: Scout Ahead, Charge Forward, and Follow the Trail share the available phone width without a hidden third choice. Route rewards remain readable beside their combat bonuses, and approach artwork loads immediately. Approach choices also respect the iPhone camera and home-indicator safe areas.
  • Keep camp controls and their menu clear of the camera on either side of a landscape phone.: Camp Command stays clear of the camera in either landscape orientation. Its compact run header and status cards leave more room for useful actions, while menu buttons retain comfortable touch targets.
  • Strengthen mobile combat verification with continuous-turn journeys and calibrated frame-pacing guards.: Mobile combat checks now exercise consecutive card plays and the following enemy turn without resetting the fight. Frame-pacing checks flag stutters separately from unusable browser calibration; they do not replace physical-iPhone testing.
  • Card inspection stays responsive while compact enemy formations retain their layout.: Browsing card details is more responsive, including large Spellbook collections. Enemy formations retain their layouts as enemies are summoned or defeated.
  • Isolate combat timing checks from concurrent UI tests: The full UI gate runs its combat pacing benchmark after other browser tests finish, without changing timing thresholds. Both phases must pass, and complete test counts are retained in verification stamps.
  • Make the phone Chronicle scrollable and show the run score before the narrative.: The mobile Chronicle uses a compact portrait and verdict, keeps the score near the top, and provides a contained scrolling report for the remaining statistics and final action. Archive & Analytics opens on the first tap and stacks its panels at readable phone widths.
  • Keep large mobile enemy rosters on one row instead of stacking offscreen after summons.: Six or more enemy entries, including retained corpses, use a horizontal formation with lane-local overflow. Mobile target navigation no longer scrolls the whole battlefield when revealing a target. Existing smaller formations are unchanged.
  • Keep feedback fields and submit controls visible together on landscape phones.: The feedback form gives the message field the available screen height and keeps Contact and Submit visible, with larger touch controls and camera-safe margins. Background menu controls no longer cover the feedback dialog's close button on phones. Submitting and retry messages have room without overlapping the form fields.
  • Keep card rules visible during the mobile card-play spotlight.: Mobile card selection and playback share a readable face with room for rules text. Long selected cards scroll within their frame, while the playback spotlight expands within the screen so its rules do not disappear or require scrolling. Cards played without opening their preview, including drag-to-play, also retain full-size artwork instead of inheriting the hand thumbnail's narrow art window. The reading surface also fills the card consistently in iOS WebKit, including cards with short rules that previously shrank toward their text width. Hand-position keyboard badges no longer overlap the rules during playback.
  • Give post-combat route choices more room and readable selection controls on iPhone.: Route decisions share the safe screen width, with compact bottom controls and no decorative frame covering their content. Descriptions are shown on the cards without a duplicate hover tooltip. The feedback button stays clear of the bottom controls, including when restoring an overlapping dragged position.
  • Give mobile enemy formations more room and keep target details above the battlefield.: Larger enemy groups use the available battlefield width. Selected enemy health and intent stay in a docked readout instead of opening a tooltip over the enemy. The readout follows the same paced combat state as the visible figures. Its compact height and ally-side clearance keep short-phone figures, mercenary intent, and phase feedback from overlapping the selected target details. Combat review screenshots verify painted hand illustrations instead of accepting decoded images that have not yet appeared in the capture. Small-phone energy displays retain their battlefield anchor instead of moving over the draw pile. During phone combat, Report Bug / Suggestion remains in the menu without a second floating button covering the resource controls. Desktop hand-card rules stay inside their frames, with long descriptions available in the card's scrolling text region.
  • Keep combat turn announcements clear of mobile controls: Turn announcements now leave room below the mobile top bar, avoiding overlap with the Pouch button while preserving enemy and intent visibility.
  • Read mobile hand-card rules even when you do not have enough energy to play them.: Tap an unaffordable card once to inspect it. A second tap still rejects the play without spending energy or closing its rules.
  • Fixed iPhone Google sign-in rejecting valid server responses before opening the browser.: Native sign-in and saved-account restoration now use the same Foundation-to-Capacitor JSON conversion, preserving nested user data and session responses.
  • Reduced-motion mode avoids unnecessary transitions when browsing cards and menus.: With reduced motion enabled, menus and card details update without starting tiny transitions on surrounding text. Essential combat feedback remains visible.
  • Make Spellbook cards readable on phones: Spellbook entries now place art beside full-size rules and variant controls, with content-sized cards that keep long descriptions inside their tile.

Tech

  • Cards carry a derived answers-asks marker used by the upcoming pack-ask telegraph: Internal: every card now derives an answersAsks marker at catalog load (poison, freeze, stun, or a strong single-target hit qualify for the SHELL ask). Nothing is shown to players yet; the reward-board telegraph that reads it lands in a later change (ROG-1774).
  • Combat pilot now widens lookahead when a SHELL-shelled enemy still guards and no in-hand card can affordably answer, gated behind the pilotAskAware probe key (byte-identical off).: ROG-1791: isDifficultEncounterState (sim-policy-decision-candidates.ts) gained an ask-aware clause, hasUnansweredShellAsk, so the combat AI's beam-search lookahead now also deepens when an encounter's "shell" ask is unanswered — an alive enemy is still shelled with Guard remaining and no card currently in hand both answers "shell" (card.answersAsks) and is affordable at its effective cost. The check runs only when the pilotAskAware probe key (ROG-1787's plumbing-only sim arm) is set; with the arm off, behavior is byte-identical to before this change. No player-facing effect until a fleet experiment promotes the pilot-ask:on arm.
  • Sim pilot now values a reward card that answers next act's telegraphed ask (SHELL) when the current deck can't yet answer it, gated on the pilot-ask-aware probe key.: No player-facing change. The sim reward scorer now has an experimental term (default-off, behind the pilot-ask arm's pilotAskAware probe key) that recognizes when the next act's packs will pose an ask (currently just act 2's SHELL) the player's deck can't yet answer, and values a reward choice's answer card accordingly — the sim analogue of the reward-draft telegraph players will eventually see (ROG-1789). This lets the ROG-1774/ROG-1790 SHELL experiment separate "did the pilot notice the ask" from "did the encounter change work," rather than conflating the two in a single before/after comparison.
  • Sim telemetry: persist per-encounter raw enemy intake and guard-absorbed damage so trivial fights can be attributed to attack-vs-guard (ROG-1771).: No player-facing change. Fleet per-encounter rows now carry rawIntake (pre-guard enemy damage) and guardAbsorbed alongside the existing post-guard life-loss fields, so a fight that costs no life can be told apart as "the pack never hit" versus "guard ate every hit".
  • Forward lookahead-immune enemy-action/life-lost ledger counters through the sim seams and retire the beam-polluted heroDamageDealt whitelist key: No player-facing impact. Sim/balance tooling change: the fleet's per-encounter rows now carry enemyActions/enemyLifeLost sourced from the lookahead-immune combat health ledger (ROG-1772), and the beam-lookahead-polluted heroDamageDealt key is no longer emitted.
  • Fix avg_enemy_actions always persisting 0 on seed-winnability rows by emitting a run-level avgEnemyActions mean: No player-facing change. ROG-1773: buildRunHistoryRow (seed-winnability writer) now emits a run-level avgEnemyActions (mean of the ROG-1772 ledger-backed per-encounter enemyActions, omitted when unmeasured) so balance-db-history.js's avg_enemy_actions column stops persisting 0 on every seed-winnability row. The run-balance-sim path's run-level combatLogSummary.enemyActions fold (aggregateRunCombatLogSummary) now prefers the same ledger-backed per-encounter counter over the capped 18-entry combat-log sum when every encounter in the run measured it.
  • Add a committed act-entry deck probe tool for SHELL calibration analysis: Internal tooling only, no gameplay change: promoted a scratch probe into scripts/tools/probe-act-entry-decks.js, a committed, documented, seeded tool that captures a class's real deck contents, level, energy, life, and power score at act-N ENTRY (the checkpoint when act N begins) by driving the same progression-sim harness the balance suite uses. This gives the SHELL entry-Guard calibration work (ROG-1795/1796) real act-2-entry decks to measure throughput against instead of a hand-picked example deck.
  • Extend combat-feel paint evidence to the enemy reaction beats (enemy-step/mercenary-step/end-turn): No player-facing change. ROG-1800 (first bounded step): the sequence-fx enemy reaction loop now calls the existing recordPaintEvidence observer per struck target, immediately before the hit-class mutation, so dom-before-paint/animation-after-paint evidence is produced for the enemy-step/mercenary-step/end-turn families — correlated actionId+stepId+targetId against reaction points in checks-impact.js (previously deferred as producer gaps). In the same change, recordSemanticDeltaStep (action-dispatcher-combat-sequence-beat-telemetry.ts, called from action-dispatcher-combat-sequence-fx.ts's impact-beat callback) emits one action-level semantic-delta record per step — {heroLife, heroGuard, enemiesAlive}, correlated actionId+stepId (never targetId) — closing the semantic-delta producer gap those three families previously had; the existing per-target target-delta records are unaffected. Both observers stay armed-only and read-only; timing, mechanics, and reduced-motion semantics are unchanged. Browser verification: a 4-attacker + 1-mercenary fixture (5 live targets) observed PASS with 5 steps and 20 evidence records. The full analyzer matrix (all cells/families) is not yet run — this closes the enemy paint and semantic-delta evidence gaps only, not full-turn conclusive evidence. step-interval (the absolute per-step interval) remains notChecked/informational per contract §8, unchanged by this step.
  • SHELL's static answer marker is Poison/Freeze/Stun only now; the throughput lane never actually cracked the ROG-1803 damage gate and is removed, re-deriving requiresShellAsk promotions (paladin drops to zero).: No direct player-facing change (shellAskEnabled remains default OFF). card.answersAsks's SHELL derivation (game-content-card-asks.ts) now recognizes Poison/Freeze/Stun effects only — the throughput lane (single-target damage ≥ a threshold) is removed, since the ROG-1803 damage gate cannot be raced by raw damage at all. game-content-profiles.ts's act-1 requiresShellAsk promotions were re-derived from the corrected marker: amazon_exploding_arrow and paladin's whole block (sacrifice/zeal) no longer qualify and were dropped — paladin now has zero static SHELL answers (ROG-1780 tracks giving it a real one). Remeasuring p(≥1 answer offer) under the new marker also surfaced that sorceress and warlock, previously propped up by the throughput lane, are now pool-starved with no promotion lever yet — recorded in docs/wiki/mechanics/rewards-and-drops.md, not acted on here.
  • Persist shellCrackedTurn/shellCrackedBy (SHELL_CRACK passthrough) per-encounter and add a crackedBy distribution + expiredRate headline to the SHELL ask reporter.: No player-facing change. Sim-fleet SHELL per-encounter telemetry (docs/architecture/TELEMETRY-SCHEMA.md §7) now persists shell.shellCrackedTurn/shell.shellCrackedBy — a null pair mirroring CombatEnemyState.shell.crackedTurn/.crackedBy — so perEncounter[] rows record what (if anything) cracked a shelled enemy's damage gate: poison, melt_poison, freeze, stun, expired, or null for never-cracked. scripts/lib/shell-ask-reporting.js adds a crackedBy distribution and an expiredRate headline metric (per arm × class, same {value,n,coverage}/named-refusal contract as the rest of the SHELL ask report) so a balance session can see the unanswered-outcome rate next to punishmentRate instead of inferring it.
  • Add a flag-gated (shellAskEnabled, default OFF) act-1 reward-tier-promotion lever that raises poison/freeze/stun/high-throughput (SHELL-answer) card offer rates for paladin, druid, barbarian, amazon, and assassin, whose act-1 mainline drafts were measured to rarely surface their only qualifying answer cards; flag-off behavior is unchanged.: Several classes' act-1 reward drafts rarely offered any poison, freeze, or stun card because their only such cards were crowded out by the rest of the early card pool. This ships a flag-gated (default OFF) fix that gives paladin, druid, barbarian, amazon, and assassin extra weight on those cards in act-1 drafts, so a run is far more likely to see at least one before act 2. No effect while the underlying flag is off.
  • Wire two independent sim arm dimensions (shell-ask, pilot-ask) so ROG-1787's 2x2 exercises four real arms; pilot-ask is plumbing-only, inert until ROG-1790/1791 land a reader.: No direct player-facing change. Two independent sim arm dimensions land for ROG-1787 (T4): shell-ask (a normal boot-flag lift of the existing shellAskEnabled flag, ROG-1786) and pilot-ask (a sim-only pilot dimension that sets a pilotAskAware probe key around a run, inert plumbing until ROG-1790/1791 add a reader). Being independent, shell-ask x pilot-ask gives future balance sessions a real 2x2 to run once the reader lands.
  • SHELL ask attaches to act-2 mainline packs (flag-gated, off by default): Behind a default-OFF flag (shellAskEnabled), act-2 mainline pack encounters that include a Brute now get the SHELL ask attached at catalog build: the Brute enters combat with Guard already up, asking the player to chew through it, bypass it, or skip its re-guard turn with control. Side-branch encounters and the act boss are never eligible. No visible change while the flag is off — this ships the mechanism for the ROG-1774 slice-9 fleet A/B.
  • Per-enemy ask ledger counts guard-bypassing life damage, control applied, and guard chewed: Internal telemetry only: every enemy now carries flat counters for life damage that bypassed its Guard, Freeze/Stun events that actually landed after resistance, and Guard points chewed by the party, plus the entry Guard stamped on a shelled Brute. Combat outcomes are unchanged; the sim reads these to tell whether a build answered the SHELL pack ask (ROG-1774).
  • Add a pack-scoped SHELL ask-mechanic reader (conditional fast clear, potion spend, pack-scoped life floor, boss win-rate, kill-turn by power tercile) with named refusal for thin/sparse cells.: Adds scripts/run-shell-ask-report.js / scripts/lib/shell-ask-reporting.js, a read-only fleet report that measures whether the SHELL ask-answer mechanic (ROG-1786/1792/1793) is actually tightening pack encounters: conditional fast-clear rate given an executable answer card vs. not, potion spend, a pack-scoped (non-boss) life floor, boss win-rate, and kill-turn broken out by class and build-power tercile. No player-facing change — this is balance-session tooling only. Every metric carries its sample size and coverage, and any cell below the configured floor (or an arm with zero SHELL fights) is refused by name instead of silently rendering as zero or "no change," so a future A/B on this mechanic can't misread a thin or inert arm as a flat result.
  • Combat pilot no longer wastes hits on an immune SHELL-BRUTE target and is rewarded for cracking its shell open (probe-gated, default OFF).: ROG-1804 (G2): the sim combat pilot's target priority, guard-value scoring, and reward terms now recognize a SHELL-BRUTE enemy's active shell (enemy.shell.active) — it no longer nominates a shelled enemy as the "finish it" target while another target is available, no longer treats a shelled sole survivor as "lethal in hand" when scoring guard value, and now earns a dedicated reward for cracking a shell open rather than only for the kill that follows. All three changes are gated behind the same pilotAskAware probe key introduced in ROG-1787/1790/1791 and are default-OFF; no player-visible or production pilot behavior changes until the probe is promoted.
  • Fix a targeting gap where an answer card (e.g. Poison/Freeze/Stun) could never reach a shelled enemy dropped from the shared priority-target list on a crowded board, silencing the shell-crack reward.: Sim/AI-internal fix (probe-gated behind pilotAskAware, no player-facing change while the probe is off). On a board with 3+ enemies, a shelled enemy could be excluded entirely from the shared list of priority targets that every enemy-targeting card enumerates against, because its effective life sorts as +Infinity to keep the pilot from wasting hits on it. That made it impossible for a Poison/Freeze/Stun card to ever target the shelled enemy at all, so the pilot could never crack it open and collect the crack reward — measured as a drop in the answer-played rate under ROG-1806. The candidate-target list now additively restores the shelled enemy as a reachable target for any card that answers the encounter's live ask.
  • Persist per-encounter SHELL ask-answer telemetry (askTag, answerAvailable/Executable/Played, punishmentTriggered, kill-turn) with a strict missingness contract: Internal telemetry only: every SHELL-tagged pack encounter now persists whether the deck carried an answer, whether it was drawable and affordable within the first two turns, how many times it was actually played, whether the shelled Brute survived (and on which turn it died if not), and whether it punished an unanswered build by surviving turn 2 with Guard still up. A field is omitted (not defaulted to false/zero) whenever the fight ended before its measurement window closed, so the sim can tell "never answered" from "never got the chance to answer" (ROG-1774/ROG-1793).
  • Committed gate sweep tool for the SHELL ask (faithful fights, four arms, breaker-kind distribution): Internal tooling: scripts/tools/sweep-shell-gate.js runs the SHELL gate on real act-2 decks through the production combat path across gate-off/on and pilot-off/on arms and reports crack kinds, kill turns, fight length and the conditional gap. No gameplay change.
  • Sim telemetry records the shelled enemy's kill turn as the turn it died, never one past the fight's end: Internal telemetry fix: the per-encounter SHELL block's kill turn read one turn too high whenever the killing blow ended the fight, because the fight-ending turn never reaches the end-turn increment. It now reads the runner's own turn counter, so a last-turn kill reports the same value as the fight length. No gameplay change.

Angel Snack 0.1.0-alpha.21 Patch Notes

Release date: 2026-09-09

Stage: alpha

Package version: 0.1.0-alpha.21

These notes are gathered from the release fragments in docs/patch-notes/unreleased/.

UI

  • Track your bug reports and see when they are closed.: Bug reports no longer ask for contact details. Open My reports to see your submitted reports and whether they are open or closed, including any resolution note from the team.

Angel Snack 0.1.0-alpha.20 Patch Notes

Release date: 2026-09-09

Stage: alpha

Package version: 0.1.0-alpha.20

These notes are gathered from the release fragments in docs/patch-notes/unreleased/.

Balance

  • Retune the per-act encounter floor to a life-weighted acts 2-3 profile so mid-game packs survive long enough to act.: No player-facing change yet — the encounter floor stays default-OFF pending its A/B. Mid-game fights are currently over before the monsters do anything: act-2 battles end in 1.37 turns and remove 0.2% of the hero's life, with 0.08% of that arriving on turn one. Scaling those monsters' damage does nothing, because a pack that dies first never uses its attack. This gives acts 2 and 3 enough survivability to take an action, leaving their damage untouched, and targets the pacing of act 4 — the act that already plays well — rather than making fights longer. A first A/B at a stronger setting confirmed the approach: mid-game fights stopped being free (trivial share 94% to 82%, fight length 1.65 to 2.65 turns) with no increase in near-death moments. It also cost more winnability than intended and hit one class much harder than the rest, so the strength has been stepped down and is being re-measured.
  • Test widening mid-game patrol packs by one enemy instead of scaling monster stats.: No player-facing change — this ships default-OFF for measurement only. Mid-game patrols currently field three enemies while act-4 patrols field four, and across the whole game the number of enemies in a pack tracks how much damage a fight actually deals far better than any monster stat does. An extra enemy means one more action each turn rather than a longer fight, which is the shape the two previous attempts at the mid-game floor missed: raising damage did nothing because those packs die before acting, and raising health made them survive but left most fights trivial anyway. This adds the fourth slot from act 2 so the idea can be measured.

UI

  • Clarified Battle Arena setup progress with persistent desktop build context, compact actions, and explicit mobile completion markers.: Battle Arena setup now keeps each choice legible as the contract takes shape: desktop shows class roles and a persistent build summary, while phone landscape folds the five touch-safe stages into the active workbench header, removes the redundant title band, and reduces the bottom commands to one 48px row so the actual setup decisions own the screen.

Fixes

  • e2e lane now preflights pinned Playwright browser revisions before launching any test, failing fast with the exact npx playwright install remedy instead of a wide browser-death crash across every file.: Dev-tooling only, no player-facing change: npm run test:e2e now checks that every Playwright engine the lane launches (chromium, webkit) has its pinned browser revision installed before any test file runs, and fails immediately with the exact npx playwright install <engine...> command when one is missing, instead of every file dying with a generic browser-crash signature.
  • Make the e2e gate load-adaptive: bound node --test concurrency to host load, record a per-attempt verdict so a red run supersedes a stale green freshness stamp, and print execution-condition provenance on failure.: No player-facing change. This is a release-tooling fix: the pre-push e2e UI gate (npm run test:e2e:gate) now bounds node --test's concurrency to current host load instead of letting it run uncapped (measured: up to 11 simultaneous browser-driving files on a 12-CPU box, which produced non-reproducing failures under load). A failing gate run now also records a per-attempt verdict, so a red run correctly supersedes an older green freshness stamp instead of being invisible to check-e2e-freshness.js.
  • Guard-break screen shake/flash now fires only on an actual guard break, not any guard chip; reduced motion now suppresses screen flash the same way it already suppresses shake.: Chipping an enemy's guard no longer shakes and flashes the screen as if it had broken — only a hit that actually breaks a guard (drops it to 0) triggers the heavier shake and break flash now. Separately, turning on Reduced Motion now also turns off full-screen flash (it already turned off screen shake), since a flash can be just as disruptive as camera shake for players sensitive to sudden visual motion; the standalone Screen Flash toggle still works on its own for anyone who wants flash off without reduced motion.
  • Restore map levels when continuing older saved runs: Older saved runs now recover their map levels and encounter links when continued after zone renames. Existing route progress, rewards and in-progress combat are preserved.

Tech

  • Combat-feel telemetry: player-card/potion impact cues now carry the staged action's id, and the enemy/mercenary step arc plus struck-target player impacts now emit per-target semantic-delta evidence (closes two combat-feel-analyzer producer gaps, ROG-1738).: Internal combat-feel telemetry only — no player-visible change. Player-card/potion impact audio cues and the enemy/mercenary attack sequence now record which action and target they belong to, so automated combat-feel verification can check per-target hit evidence it previously had no way to observe.
  • Impact-fx now emits dom-before-paint and animation-after-paint evidence for player-card impacts (armed-only, not yet consumed by the combat-feel analyzer).: Internal combat-feel telemetry only — no player-visible change. The player-card impact path now emits two new evidence kinds when a telemetry trace is armed: dom-before-paint (a mutation timestamp plus a raw-rAF observation that it's still present) and animation-after-paint (an animationstart listener attached before the triggering class add). Both are deliberately not yet wired into the combat-feel analyzer (scripts/combat-feel/checks-impact.js) — that is a follow-up step (ROG-1757 step 2b).
  • combat-feel: player-phase-spacing no longer reported as notChecked for phase-driven scenarios (it does not apply): Internal combat-feel analyzer change only; no player-visible behavior changed.
  • combat-feel analyzer checks the reduced-motion moving-clone claim positively instead of always deferring it: Internal combat-feel telemetry only; nothing player-visible changes. The played-card fly-out clone now records evidence either way — attached to the FX layer, or deliberately suppressed under reduced motion — so the analyzer's reduced-motion cells can prove the suppression positively (moving-clone-suppressed, new FAIL:suppression-unproven class) instead of deferring the claim forever. single-hit / reducedMotion / chromium reaches a real PASS for the first time.

Angel Snack 0.1.0-alpha.19 Patch Notes

Release date: 2026-09-07

Stage: alpha

Package version: 0.1.0-alpha.19

These notes are gathered from the release fragments in docs/patch-notes/unreleased/.

Gameplay

  • Salvage and directed crafting are now live in every run: break down gear at the Horadric Cube for Arcane Dust, then spend it to reroll a specific affix line on equipped or carried gear.: Players can now salvage unwanted gear into Arcane Dust at the Horadric Cube, and spend that dust on directed crafting — rerolling one affix line at a time on a piece of equipment — right from the Cube's overlay. Both actions were previously available only behind experimental flags; they're now on for everyone.

Balance

  • Experimental Act 5 encounter floor: A default-off balance flag can raise ordinary Act 5 encounters to 1.25x life and 1.35x damage for fleet evaluation. There is no default player-facing change; Acts 1–4 and boss encounters retain their existing scaling.
  • Razor Pit Demon (act 4) now has Thorns, as its family entry always intended.: The Razor Pit Demon (act 4) now retaliates with Thorns when hit, as its family entry always declared — a roster-row precedence bug had silently dropped the trait in game. Melee-heavy builds fighting this enemy will now take a small reflected physical hit on their attacks, same as other Thorns-bearing monsters.
  • Sim pilot gear valuation can weight conditional stats by deck applicability (experimental, default off): No direct player-facing change — this ships a new derivedApplicabilityEnabled sim-only valuation lever, default off. When an A/B enables it, the balance sim's gear-value scoring weights conditional stat bonuses (intelligence, strength, dexterity, and the elemental bonuses) by how much of the current deck can actually use them, instead of pricing them at full value regardless of the deck's shape — a stat a deck never applies is now worth roughly nothing to the pilot's evaluation, with a floor that keeps very early decks from being penalized before they've had a chance to develop. This affects only how the AI opponent used for balance testing values gear during simulated runs; it does not change gameplay for players.
  • Greater Mummy regenerates, matching its mummy-family identity: The Greater Mummy (Act 2) now regenerates each turn, matching the rest of its mummy family (Embalmed, Preserved Dead, Unraveler, Guardian) — its roster row had shipped without the trait its own family override declares, so it was the one mummy in the roster that could be chipped down instead of needing to be burst before it heals back up. No other stats changed. (Internal: also removed the dead FAMILY_DEFAULTS derivation from the monster encounter registry — an unused per-family defaults table with zero consumers in src/; no behavior change.)
  • Trapper/summoner/demon-binding build specs now price heroTrapPower/heroMinionPower instead of a false int-scaling comment; attribute/element boundary-adjusted gear weights (dex/cold/lightning/fire/magic) re-measured against the current catalog; the +3 offense heuristic for attribute-scaled cards now applies to str/dex cards too (gated on a real matching damage effect), not just int.: Gear-comparison prices shift for equipment rolling dexterity, cold, lightning, fire, or magic bonus lines — a fresh measurement against the current card catalog moved dexterity-bonus gear up about +3.5% in gold value, fire-bonus gear down about 25%, and magic-bonus gear down about 19% (cold and lightning move by less than 1%). This shows up wherever gear is priced or compared: town buy/sell prices, the inventory upgrade-chevron's power verdict, and the pilot's own equip-upgrade decisions all read the same global scoreEquipmentBonuses weight table (item-town-pricing.ts / inventory-view-upgrade-chevron.ts / sim-policy-town-chooser.ts). Separately, the Assassin Trapper, Necromancer/Druid Summoner, Amazon Valkyrie Vigil, and Warlock Demon Binding sim pilots now shop for gear the way their combat actually pays off — trap and minion power instead of a false intelligence/dexterity-scaling assumption. This only changes sim-pilot build-aware gear preferences (scoreItemForBuild), not the player-facing chevron or town prices, which use the global scorer above regardless of build. The sim's own card/deck power scoring also changed: the "this card scales with an attribute" pricing bonus, previously applied to every intelligence-attribute card regardless of whether it dealt damage, now applies to strength/dexterity attribute cards too and is gated on the card actually having a matching damage effect — a purely-utility card that happens to declare an attribute no longer scores as if it hit harder.

UI

  • Mobile combat clearance: Target navigation uses the shared mobile placement, and selected-card previews can shift upward to stay between the header and hand without overlapping either.
  • Recast Battle Arena results as an illustrated trophy ledger instead of a generic panel dashboard.: Arena victories and defeats now foreground their battlefield art, present combat metrics as a single engraved ledger, and organize the verdict, loadout, and tactical guidance within one cohesive report surface.
  • Simplify the expedition hall and keep mobile account navigation clear of global controls.: A compact hero-selection row replaces the empty stat dashboard and duplicate shortcuts. The archive now has a concise first-expedition empty state, and account tabs scroll without shrinking their labels. Attribute names retain readable sizing on landscape phones. The refreshed screens now use smaller, focused stylesheets while retaining their existing visual layout and cascade order.
  • Act-transition labels are now readable, accessible, and touch-sized across desktop and landscape phones.: The act-complete screen now keeps its smallest status and destination labels at the legibility floor, retains its page heading for assistive technology on compact phones, removes repeated training instructions, and gives both onward actions a full 44px touch target.
  • Restyle the Blacksmith workboard with dark forged-steel action cards, a sigil category rail, and modal-safe keyboard and touch behavior.: The forge now keeps its atmosphere and controls readable across desktop and phone-landscape layouts.
  • Combat now keeps its location heading visible, its resource costs readable, and its primary controls clear of the hand.: Combat now preserves the Act and zone heading in the phone top bar, keeps alternate-resource card costs legible, separates the desktop energy orb from the hand, and gives End Turn a compact forged-metal treatment without shrinking its phone touch target. The bug-report launcher also recedes during combat instead of glowing beside the primary action.
  • Reframe Combat Puzzles as a full-stage trial index with an always-visible briefing on desktop and phone landscape.: Combat Puzzles now presents its trial index and selected puzzle briefing together, making challenges easier to browse on desktop and landscape phones.
  • Redesign puzzle results as a full-stage visual outcome and tactical debrief with persistent follow-up actions.: Solved and failed trials share an illustrated result layout. The tactical debrief can scroll to keep longer revealed solutions accessible, while Retry and other follow-up actions remain outside the scrolling content. Phone action rows fit the number of available choices.
  • Improved Expedition Setup heading semantics and mobile readability and touch targets.: Expedition Setup now keeps its rift label readable on phone screens and gives the Rift picker a full-size touch target. The screen also exposes the chosen hero as its page heading, improving navigation for assistive technology without changing the visual hierarchy.
  • Redesign Active Relics as illustrated artifact cards, replace empty ledger tabs with a sigil rail, and rebuild Attributes as a full-width offering altar with unique illustrated stat themes.: Active Relics now presents charms as illustrated artifacts with clearer rarity and size-group identities. The inventory navigation and Attributes view also use stronger visual landmarks so players can scan character progression without reading through stacked empty panels.
  • Improved the inventory loadout hierarchy so equipped gear reaches the first phone-landscape frame, with a compact bloodline strip and clearer ledger semantics.: Equipped gear now appears earlier and more clearly in phone-landscape inventory views. A compact bloodline summary and cleaner ledger hierarchy preserve more room for the loadout while keeping character context visible.
  • Give Pack Contents the full inventory width, prioritize carried gear in the mobile layout, and improve slot-number legibility.: Pack Contents now uses the full inventory workspace instead of reserving space for a redundant profile portrait. Carried gear is prioritized on smaller screens, and slot numbers remain readable across the supported viewport range.
  • Bring mercenary contracts onto the shared full-width vendor panel with cards that fit their tactical details.: Mercenary contracts now use the same full-width service panel as the other town vendors instead of an unframed exception. The current contract reads as a compact, left-anchored dossier rather than an empty full-width banner; cards size from their content, keep active status at full contrast, and preserve readable combat stats and aura details across supported phone layouts.
  • Increase town-service section labels to the shared legibility floor across desktop and mobile layouts.: Recovery, supplies, mercenary, stash, and related service headings now use the standard label scale instead of a sub-floor one-off size.
  • Redesign the Ranked Arena lobby around live standings and a clearer challenge contract across desktop and phone landscape.: The Ranked Arena lobby puts standings and challenge details in a clearer layout across desktop and landscape phones.
  • Turn the full Ranked Arena board into a themed Blood Ledger with readable filters and an always-visible personal standing.: The Ranked Arena leaderboard adopts the Blood Ledger theme, with readable filters and a persistent view of your own standing.
  • Encounter reward cards now keep their complete art, titles, and rules visible on landscape phones.: The first encounter reward draft now scales complete card previews into their choice frames on landscape phones, keeps its decision prompt readable, and preserves the page heading for assistive technology without restoring the desktop header band.
  • Expand every town-service store to the full game-page height while keeping merchant portraits balanced with the decision space.: Vendor, healer, stash, mercenary, travel, and blacksmith screens now share one full-canvas shell while their decision lists remain independently scrollable. Standard service portraits keep a consistent framed proportion instead of stretching to consume spare page height.
  • Redesigned Training Hall as a connected, art-first skill network with contextual upgrades.: Training now grows all three disciplines from one class root into branching vein maps set against a dedicated occult atlas backdrop. Skills connect through shared tier rails instead of redundant line bundles, while progress-ring seals name the real 3-point and 5-point discipline commitments without inventing skill-to-skill prerequisites. Larger skill circles make art and invested ranks easier to read, and hovering, focusing, or selecting a skill reveals its next upgrade or lock requirement in context. The Training Hall is now a full-screen surface, and the atlas reads as one continuous material field instead of a stack of nested panels. Compact screens show all three named discipline trees in one scrollable atlas instead of hiding two behind another menu.
  • Recompose Murn's shop around compact stocked offers, a focused mobile identity rail, and accessible modal navigation.: The vendor now gives the stock grid more room, keeps trade controls comfortably tappable, and avoids clipped merchant copy in phone landscape.
  • Wake Camp now keeps its location heading visible on phone screens.: Wake Camp now keeps its location heading visible across desktop and phone layouts, making the current place clear without adding extra copy or covering the camp scene.
  • The World Map now clearly identifies itself and keeps its supporting labels readable.: The World Map now names the current surface on desktop and phone layouts, while its boss context and Parchment View control remain readable without covering route choices.

Fixes

  • Kept Arena setup stages and actions readable, reachable, and compact across desktop and phones.: The Battle Arena now keeps its phone setup action visible and touch-sized, protects the Review stage from the persistent menu, and prevents the desktop docket from stretching navigation actions into oversized empty slabs.
  • Kept Battle Arena results readable and actionable across desktop and phone landscape.: The Arena victory ledger now keeps its rematch actions visible and touch-sized on short phones, presents the outcome and combat metrics as a compact landscape dashboard, and restores readable contrast to its supporting guidance.
  • Reframed Ascension Clear rewards around the next playable decision on desktop and phones.: Ascension Clear now presents its earned rewards as a centered desktop spread and a compact horizontal phone rail, keeping both the return and next-tier actions visible and touch-sized without crowding the character art.
  • Prevent sticky double-tap zoom on iPhone while preserving pinch zoom.: Rapid double taps no longer leave the iPhone game stuck at a magnified scale, while pinch zoom remains available when you need it.
  • Made native iPhone screenshot reviews cover modern and short-height devices and reject launch or Home Screen frames.: Native iPhone review captures now cover both a modern notched display and a short-height display. The gallery waits for the real Angel Snack front door and rejects blank, portrait, launch-animation, Home Screen, missing, or incomplete captures before reviewers see them.
  • Raised compact front-door actions to the mobile landscape text floor.: Compact guest and Battle Arena actions on the front door now remain readable at the phone-landscape design floor. Character Select keeps one semantic page landmark, restores its compact heading for assistive technology, and moves locked-class guidance from crowded roster rows into read-only hero previews.
  • Enemy target navigation now stays visible and tappable on short landscape phones.: Combat encounters with three or more enemies now keep their previous/next target controls inside the battlefield on compact landscape phones. The full-size direction buttons also remain directly tappable instead of being covered by decorative battlefield art.
  • Native Google sign-in now blocks duplicate taps and shows clear recovery feedback when the system auth flow cannot open or complete.: On iPhone, every Google sign-in button now uses the same guarded native flow. The button shows when the system sign-in page is opening, ignores accidental repeat taps, and gives a clear retry message if the page cannot open or authentication does not complete.
  • Run-path list ordering (rewards, charms, runeforge, persistence) now uses locale-independent codepoint comparison so ranked re-simulation is byte-stable across host locales: Lists that sort by name or id outside combat (reward offers, charm tiers, runeforge slots, save metadata) now order by codepoint instead of the device locale. Two devices in different locales see the same order, and ranked-run re-simulation reproduces the same result on any host.
  • Thorns and Lightning Enchanted now punish the enemy that actually struck them, even when a Confused enemy's attack landed on a packmate.: When a Confused enemy's attack was redirected onto another enemy with the Thorns or Lightning Enchanted trait, the reflected damage used to land on you instead of the attacker that caused it. Both traits now correctly hit the enemy that struck them. Act 1's Spike Fiends carry Thorns now too, so watch your redirects around them.
  • The Horadric Cube's transmutation recipes are reachable in town again: Once you've earned the Horadric Cube, its transmutation recipes now show up as a proper stop on the town map — previously they never appeared there even after the unlock, so the Cube was invisible in the safe zone despite being available under the hood.
  • Elite Frost Blunderbore uses its act-5 Pulverize kit instead of the generic Blunderbore frenzy kit: An elite (or otherwise scaled) Frost Blunderbore in act 5 previously resolved the wrong monster-family entry — a keyword collision meant it silently used a generic act-2 Blunderbore's frenzy kit instead of its own act-5 Pulverize attack pattern. Monster-family lookups are now act-aware, so elite Frost Blunderbores use their intended kit.
  • Native (iOS/desktop) Google sign-in shows accurate error text and a Cancel option so a pending attempt can't strand the sign-in button: On the desktop and iOS apps, backing out of the system browser during Google sign-in no longer leaves the "Opening Google sign-in…" button stuck for up to five minutes — a Cancel option appears while sign-in is pending. The error message shown after a failed attempt is now accurate to what actually happened (most failures mean the sign-in didn't finish, not that it couldn't open), and it clears itself after a few seconds instead of lingering until the next attempt.
  • Made run-ending controls and Chronicle metadata readable at every supported viewport.: The run-ending cinematics now render secondary actions at the shared supporting-text floor. The defeat composition expands into a full desktop spread with a larger verdict, legacy story, and rift seam instead of presenting a compressed mobile-sized decision strip. The Chronicle applies the same readability floor across score labels, stat metadata, run logs, and archive analytics, while its phone layout reserves the top-right corner for persistent menu controls.
  • Unified town shop card sizing and responsive spacing, clarified mercenary hire states, improved Veyra portrait framing, illustrated Corven Vale's allocation choices, and made vault item labels readable.: Town shops now share one full-screen shell and the same content-sized card grid across vendors, the forge, remedies, and mercenary contracts. Card descriptions grow to show their complete text instead of being clipped by fixed heights or line limits, and empty-service labels meet the shared readability floor. Veyra is framed at the same visual scale as the other shopkeepers, while mercenary cards more clearly distinguish active contracts from hire and revive actions. Corven Vale's attribute choices now carry distinct generated illustrations, and skill-node choices reuse their corresponding card art instead of showing empty tiles. Profile Vault item names, categories, and capacity counts also meet the shared readability floor.
  • Fix dead proficiency keys on Swiftwing Longbow, Thunderspire Javelin, and Glacial Focus so their implicits actually deliver in combat; drop Stormeye Focus's unreachable fire row: The Swiftwing Longbow now grants +2 lightning damage per bow attack, and the Thunderspire Javelin now grants +3 lightning damage and applies 1 Shock per javelin attack — both were authored with a proficiency key that never matched a real card and delivered nothing in combat. The Stormeye Focus's fire-damage row, which had the same problem and no correct key to fix it to, has been removed; its cold-damage row is unaffected. The Glacial Focus's second cold-damage row was keyed to a proficiency only ever applied by druid cards — dead for this sorceress-locked unique — and is now folded into the same live "cold" channel as its sibling row, so all 6 cold damage lands instead of 4.

Tech

  • Guard: the five charm-only mitigation bonus keys can never be authored on items, uniques, runes, runewords or affixes without a named test failure (no change to play).: Internal only: five mitigation bonus keys are read from charms alone; a guard now fails by name if an item, unique, rune, runeword or affix ever authors one. Nothing in play changes.
  • Pre-push hook checks a lane-stamp instead of re-running build+tests every push (no change to play).: Internal only: git push opens its SSH connection before the pre-push hook runs, so re-running build + the full default test lane there (7-40min) held the connection idle long enough to die under ephemeral-port pressure, failing the push regardless of gate result (repeatedly misdiagnosed as an SSH auth failure). The hook now checks a stamp npm test writes on a fully-passing run (a content hash of the tree, not just git rev-parse HEAD) instead of re-verifying — sub-second either way. Run npm test before pushing, same as before; nothing changes for players.
  • Retire legacy proficiency->attribute scaling tables (zero production readers) behind a frozen test-only fixture vocabulary; no gameplay behavior change.: Internal cleanup with no gameplay change: the legacy proficiency-to-attribute scaling tables (unused since card scaling moved to per-card attribute/element declarations) were removed from the engine and preserved only as a frozen test fixture vocabulary.
  • Retire the inert class-conditional affix flag superseded by class-weighted affix rates: No player-facing change. Retires the never-populated classConditionalAffixesEnabled flag registry entry: no affix ever declared a class restriction, so the flag was byte-identical on and off, and the mechanism it prototyped was superseded by the class-weighted affix rates shipped in ROG-1608. The lifecycle baseline entry is marked retired to stop it from expiring; no runtime code, types, or tests changed.
  • Engine groundwork for directed crafting: a canonical single-affix-line replacement API and full derived-state projection (no player-facing behavior yet).: Internal engine groundwork only: directed crafting (ROG-1691) gains its canonical single-line reroll machinery behind the scenes. Nothing changes in play until the crafting verb ships.
  • Fix the sim pilot's planner candidate-cap displacement bug: salvage/craft crowded core actions out of evaluation, costing -11.3pp winnability with zero engagement (sim-lane only, no player-facing change).: Internal sim-lane fix only, no player-facing change: the balance pilot's town planner now admits salvage/craft candidates through a separate reserved lane instead of the same capped list core actions (equip/vendor/potion/sustain) compete for, so a heavily-geared run's salvage/craft volume can no longer crowd core actions out of evaluation — the exact bug that cost -11.3pp winnability in fleet A/B testing with zero salvages/crafts ever taken.
  • Guard sweep: every authored exact-match value channel gets a canary-verified resolvability guard: Internal only: seven new canary-verified guards close silent-drift gaps across gear and content data. Template-authored item/unique/runeword/rune bonuses keys now must resolve to a combat reader or a valuation weight table (or a documented non-combat allowlist entry) — a typo'd bonus key on a unique used to price itself in the sim/UI power score while delivering nothing in combat. Persisted affixLineIds on saved equipment now round-trip through town-pricing's id lookups with an observable skip counter, so a future affix-registry rename can no longer silently strip pricing from already-owned items. The skill-tree card map now has a forward guard (every map key resolves to a real card or a declared passive node) alongside its existing reverse guard. Four more guards (counter-id census, monster intent-dispatch exhaustiveness, elite-affix table join, roster intentsKey vocabulary) close the same class of gap in combat/content data. docs/architecture/SYSTEM-SEAMS.md gained rows for all of these. Nothing in play changes.
  • Per-arm margin-telemetry A/B report over the fleet canonical: Internal only: adds scripts/run-margin-report.js, a read-only per-arm margin-telemetry A/B report over the fleet's Postgres canonical, seed-paired by the fleet's CRN pairing key rather than pooled means. Where win-rate is saturated near 100% and can no longer show whether a balance change helped, this report answers that from boss HP-floor/turns/potions margins instead — see "Margin methodology (A/B)" in docs/fleet/FLEET-GUIDE.md. No gameplay change.
  • Combat-feel verification contract and scenario manifests for the combat-feel reviewer agent: Internal tooling groundwork with no gameplay change: a new verification contract states which named timing constants and impact-evidence layers a validating agent may check, and ships the scenario manifests it will run against. Nothing players see changes in this release.
  • Combat presentation telemetry now covers potion and end-turn actions and can export a per-trace record with settings readback for the combat-feel reviewer: Internal instrumentation only, no gameplay or animation change: combat presentation timing marks now cover potion and end-turn actions as well as card plays, and a test harness can arm a per-trace buffer that refuses to silently drop events. Nothing players see changes in this release.
  • Add per-beat/audio telemetry correlation (actionId/stepId/targetId) to the enemy action-sequence FX scheduler and cast/hit cues, gated behind an armed verification trace so it never runs or perturbs choreography in normal play.: No player-facing change. This is slice B of the combat-feel verification instrumentation (ROG-1732/ROG-1730): the FX beat scheduler and the enemy action-sequence presentation layer now record a scheduled/fired/cancelled-stale/fast-forwarded lifecycle event per beat (announce/telegraph/travel/impact/reaction), and the sequence's cast/hit/status audio cues carry the same action/step/target ids, so a future automated reviewer can correlate choreography timing against the audio it produced. All of it is armed-only — recording is a no-op, and telemetry failures can never affect scheduling or playback, so normal combat is byte-identical to before.
  • ROG-1732 slice C: observe-only telemetry for the terminal victory/defeat sting and defeat-moment phase clock, plus a named OUTCOME_STING_MS constant replacing the bare 300ms literal.: No player-facing change. This is the third slice of the ROG-1732 combat-feel telemetry instrumentation: the victory/defeat banner and sting, and the defeat-moment phase clock (impact/fall/verdict/rift/legacy/ready), now emit correlated evidence events when a trace is armed, so verification tooling can observe terminal-combat choreography end to end. The victory/defeat sting's previously-unnamed 300ms delay is now the named OUTCOME_STING_MS constant (same value — no timing change).
  • Add pure ROG-1733 combat-feel verdict analyzer core (schema/identity/completeness/ordering): No player-facing change. Adds the pure verdict-analyzer core for the ROG-1730 combat-feel verification pipeline (scripts/combat-feel/analyze-trace.js + supporting checks-*.js/matrix.js modules): given a presentation-telemetry trace, a scenario manifest, a scenarioId and a cellKey, it certifies manifest schema, trace identity, settings-readback agreement, completeness, and structural ordering/beat-outcome classes per docs/design/combat-feel-verification-contract.md §8, with spacing/lateness/ impact-coherence deferred to a follow-up (part 2). Every expected time is resolved by name off the compiled combat-fx-timing authority — no millisecond literal lives in the analyzer, guarded by a dedicated test.
  • Combat-feel analyzer: implement spacing, scheduler-lateness, impact-coherence, and reduced-motion checks (ROG-1733 part 2).: Internal only — no player-facing change. Lands the ROG-1733 part 2 deferred checks for the combat-feel verification analyzer (scripts/combat-feel/): choreography spacing on raw scheduler offsets plus a separate per-beat multiplier reconstruction (checks-spacing.js), scheduler lateness with a host-load-scaled tolerance (checks-lateness.js), impact-evidence coherence including the optional cue-feed window and producer-gap awareness (checks-impact.js), the reduced-motion set (checks-reduced-motion.js), and a readback-vs-runtime-table multiplier check (checks-multiplier.js). Adds getSpeedMultiplierFor to __ROUGE_COMBAT_FX_SETTINGS (src/ui/combat-fx-settings.ts) so the analyzer can resolve the runtime's own speed-multiplier table by name instead of a literal. A cell with nothing left deferred can now reach a real PASS instead of always carrying INCONCLUSIVE:checks-deferred. Also fixes a part-1 edge case where a reaction-layer stale beat was ranked below every skip target instead of at impact's rank, and a part-2 edge case where turn-banner grouping used actor identity instead of the runtime's own side-based grouping. Second-pass fixes: end-turn is no longer treated as a semantic-delta producer (the enemy-phase path it hands off to has none until ROG-1738), and evidence matching now uses only the correlation fields a producer actually declares (never widened/narrowed by what an impact point happens to carry). provenance is documented as harness-added (contract §7) — its absence skips lateness (notChecked: ["lateness:no-provenance"], WARN:no-provenance, capped at PASS_WITH_WARNINGS) rather than reading as a trace defect; present but non-finite provenance still does. An injected timing object (bypassing loadTiming()) is now validated identically to a loaded one (isValidTimingAuthority). stepId parsing is now strict: index must match ^(0|[1-9]\d*)$, actorKind must be one of the closed set (enemy/mercenary/minion), and actorId must be non-empty.
  • Combat-feel scenario harness captures a real browser trace and runs it through the verification analyzer: Internal verification tooling only, with no gameplay or presentation change: a new end-to-end harness plays a real card in a real browser, records the timing and evidence the combat presentation emits, and checks it against the combat-feel contract. Nothing players see changes in this release.
  • Removed the unused guestAccountsEnabled boot-config field and hardened the feature-flag lifecycle check against unrecognized decision values.: No player-facing change. The RougeBootConfig.guestAccountsEnabled field was never read anywhere — guest-account availability is and remains driven by the live /api/auth/config response, and the admin toggle reads a separate server-side config, so sign-in and guest play behave exactly as before. The dead field and its feature-flag registry entry were removed together so neither outlives the other. The flag-lifecycle check now also rejects unrecognized decision values, which previously let a typo silently bypass a flag's review deadline.
  • Admin-auth startup tests wait for the server's output instead of sampling at a fixed instant: Internal test-reliability fix with no gameplay or server change: the admin startup-guard tests now wait for the server to actually report, instead of checking at a fixed moment and finding nothing on a busy machine. Nothing players see changes in this release.
  • Add a single-arm margin profile for reading absolute encounter threat and run-resource shape from fleet rebaselines.: The fleet margin report can now profile a single arm without inventing an A/B comparison. It summarizes life-floor risk, turns, and potion use by act, encounter kind, and named encounter, plus the run-level margin telemetry needed to inspect rebaseline difficulty curves.
  • Sim/arena tooling: boss encounters authored via consequence packages now receive the same Normal boss scaling as the campaign in synthetic-run builders (not player-visible).: Internal only: arena and crafted-fight builders now classify consequence-package bosses as bosses, so their life and damage match the campaign. The arena lobby never offers those encounters, so nothing in play changes.

Angel Snack 0.1.0-alpha.18 Patch Notes

Release date: 2026-09-03

Stage: alpha

Package version: 0.1.0-alpha.18

These notes are gathered from the release fragments in docs/patch-notes/unreleased/.

Highlights

  • Added a bundled iPhone app shell with native sign-in, secure cloud transport, and reviewer screenshot capture.: Angel Snack can now run from a bundled iPhone app in landscape, with secure native account sign-in and cloud profile access. A simulator screenshot command also creates a small review gallery and rejects blank or incorrectly oriented captures before they reach reviewers.

Gameplay

  • Add a flag-gated Anvil Reforge blacksmith action (game-side core, default OFF): pay gold to reroll an equipped magic/rare item's affix lines in place.: The blacksmith gains a new Anvil Reforge action: pay gold to reroll the affix lines on an equipped magic or rare item in place, without losing its sockets, runes, or any runeword it forms. Cost scales with the item's value and rises each time that item is reforged. This build lands the game-side mechanics plus internal balance-simulation tooling to evaluate it — the action is still flag-gated and stays OFF by default until it's balance-tested, so nothing changes for players yet.
  • Anvil Reforge is now available by default in town.: The Blacksmith's Anvil Reforge service is now available by default, from Act 2 onward. Pay gold to reroll the affix lines on an equipped magic or rare item in place — the base item, sockets, and any inserted runes are kept, and rerolling never produces a unique. The price rises each time the same item is reforged.
  • Assassins can now find claws, and traps finally scale off a weapon: Claws are a new weapon family for the assassin: Cestus, Blade Talons, Greater Talons and Scissors Suwayyah, one appearing roughly per act. They boost martial arts and shadow skills, and — for the first time — trap skills, which until now no weapon in the game could strengthen at all. An assassin running traps was carrying a sword that did nothing for the half of her kit she actually played. Claws also drop and appear in shops at the rates you'd expect for a class's own weapon, which was another thing the traps build never had.
  • Affix eligibility is now gated by a gear piece's own attribute (str/int/dex, hybrids, and neutral) instead of the rolling run's class.: Affix lines that scale a specific attribute (starting with the "Arcane" intelligence prefix) now roll based on the gear piece's own attribute identity (strength/intelligence/dexterity, hybrid weapons like scythes and maces, or neutral slots) rather than which class is running. This has no impact yet: it replaces an unused per-class restriction with an equivalent, currently-inert mechanism on a single tagged affix line, and neutral/untagged gear stays fully open as before.
  • Weapon affixes now respect the base's attribute: +damage rolls on strength/dexterity weapons, +dexterity and crit on dexterity weapons; caster weapons (wands, staves, orbs, grimoires) no longer roll melee affixes. Accessories and armor unchanged.: Weapon affixes used to roll off a single shared pool, so a wand could roll +dexterity or crit chance identical to a sword's, even though a caster weapon has no melee/dex identity to back either roll. Weapon-flavoured affix lines now respect the base's attribute instead: +damage rolls on strength or dexterity weapons, and +dexterity and crit chance roll only on dexterity weapons. Caster weapons (wands, staves, orbs, grimoires) no longer roll any of the three on the weapon slot itself — they can still find flat damage on gloves and rings, and dexterity and crit on gloves, which stay open to every build. Armor and every other accessory slot are unaffected.
  • Magic, rare, and set gear now rolls a tier-banded strength, intelligence, or dexterity bonus matching its base's declared attribute identity.: Magic, rare, and set gear now grants a strength, intelligence, or dexterity bonus rolled from the base item's own attribute identity — Grimoires and Orbs still grant intelligence, plate armor and heavy weapons lean strength, and light/agile bases lean dexterity. The bonus scales with the item's tier and rolls independently of the item's other affix lines, so it never crowds out a prefix or suffix.
  • Cards now carry authored element tags instead of a guessed one, fixing miscoloured and mis-gated cards: A card's element used to be guessed at load time from the statuses it applied and the words in its name. That guess was wrong on a lot of cards — Cold Arrow read as lightning because it paralyses, and Fire Arrow did not read as fire at all. Cards now carry their elements as authored data, and a card can have more than one. Two mechanics that keyed off the old guess, Plasma and Shatter, now read the real lightning tag. Some cards will start triggering them that previously did not, and a few that triggered them by accident will stop.
  • Removed unreachable weapon-family flavor titles for basic attacks (barbarian Hurl, necromancer Carve, sorceress Slice never fired; those cards now show their fallback title).: Barbarian, necromancer, and sorceress basic-attack flavor rules referenced weapon families no item in the game can actually have (Throwing, Daggers), so their special titles ("Hurl", "Carve", "Slice") could never appear. Those classes now consistently show their fallback basic-attack title (Bash / Curse / Spark) instead of a title that only ever existed in unreachable code. No mechanical/damage change.
  • Wands and staves now carry a caster stat line and wands boost caster elemental skills as well as their occult ones, so a sorceress wielding a wand is no longer left without weapon affinity. Staves remain the stronger elemental weapon.: Wands and staves are now properly caster weapons. Previously some wands carried a martial attack stat more fitting a sword than a spellbook; they now carry a caster stat line instead, at the same overall strength. Wands also boosted only bone, poison, curse and summoning skills, so a sorceress holding one got no weapon bonus at all on her fire, cold and lightning cards — despite wands being offered to her as a preferred weapon. Wands now also boost the elemental skill lines, while keeping their occult bonuses at full strength. Staves still give a larger elemental bonus, so a staff remains the stronger choice for a dedicated elementalist and the wand serves as a sidearm. Necromancers lose nothing: every bonus a wand gave before, it still gives.
  • Town acquisition (vendor stock + gear gamble) now biases toward your class's usable attribute.: Smarter town shopping: vendor stock and the gear gamble now draw a bounded share of their offers from bases whose attribute your class actually uses, so fewer offers are dead on arrival — while off-attribute gear stays in the pool and rings and amulets remain fully neutral. This shipped behind a default-off flag pending a balance experiment and is now on by default after a fleet-validated, winnability-neutral confirm (see the ROG-1652 promotion note).
  • Card preview numbers in combat now come from the real combat resolution, so what you see is what the card does: The numbers on a card's preview — damage, guard, statuses, draw — used to be worked out separately from what actually happens when you play it, and the two could disagree. They now come from the same place, so several previews change to tell the truth: cards that scale off your attributes, auras, Mastery or shadow charges were being shown too low, and cards hitting an enemy that resists a status were being shown too high. Chaos Surge previewed nothing at all and now previews properly. One change will look like a bug and isn't: Draw counts now respect your deck and hand limits. A card that says "Draw 2" will preview "Draw 1" when your deck only has one card left to give. The card has always behaved this way — the preview simply used to ignore it. Previews on Cycle, Adventure, kicker and pile-replay chips are covered by this too; they previously used a rougher approximation than the main preview did. Two more small corrections fall out of the same fix: charms that key off "you have unspent Energy" now preview accurately instead of nearly always showing as active, and soul-cost cards that refund unspent Energy now preview a real refund instead of always showing zero.
  • Deck surgery now unlocks only after clearing Black Pit (Ashfall Hamlet no longer counts).: Act 1 deck surgery at Corven Vale now unlocks only after clearing Black Pit. Clearing Ashfall Hamlet alone no longer opens the surgery slot.
  • Weapons can now roll elemental and minion affixes: Weapons can now roll Cold Skill Damage, Lightning Skill Damage, Poison Damage, and Minion Damage as affix lines on magic and rare drops, giving elemental casters and summoners more ways to build around their specialty through gear, not just skills.
  • Weapons can roll Cold and Lightning skill damage, giving caster builds distinct gear identities (unreleased, off by default).: Weapons can now roll Cold Skill Damage and Lightning Skill Damage, joining the Burn bonus that fire builds already used. Each adds flat damage to cards of that skill proficiency, so a cold sorceress and a lightning sorceress finally want different weapons instead of competing for the same one. A weapon can roll both at once, which is exactly what a dual-element build wants. This is groundwork and is off by default — nothing rolls these stats in a normal run yet.
  • New town gamble: pay a premium for an unrevealed piece of equipment with strong odds of magic or rare quality and a small chance of a unique. Disabled by default pending balance validation.: Town now offers a gear gamble for each equipment slot: pay a fixed gold premium and receive an unrevealed act-appropriate item of that slot, with much stronger odds of magic or rare quality than a normal drop and a small chance at a unique. Behind a flag and disabled by default pending balance validation.
  • Unique weapons can now grant ranks in a specific skill: Some unique weapons now read "+1 rank to <skill>" and mean it literally: the skill behaves as though you had spent another point in it, including the per-rank scaling on its damage, guard, healing and summons. If the extra rank takes you to five, the skill upgrades to its plus version while the item is equipped, and reverts if you take it off — so a unique can finish a build you were one point short of, without spending anything. Your actual invested points never change; gear ranks sit on top of them, and they do not unlock skills, satisfy tree requirements, or refund anything when you respec. Glacial Focus is the first weapon to carry one, granting a rank of Ice Bolt.
  • Gear tooltips now show only the skill-damage lines your class can actually use: Weapons carry skill-damage and skill-support bonuses for every discipline in the game, but your character can only ever benefit from their own. Tooltips used to list all of them — a tier-1 mace showed eighteen lines, and a sword showed both "Combat Skills Damage" (the barbarian's tree) and "Combat Damage" (the paladin's) side by side, one of which was always dead weight. Gear tooltips now hide the lines your class has no skills for, so what you read on an item is what you actually get. Item power is unchanged.
  • Defeat recaps now explain what ended your run: The defeat screen now includes a "What Killed You" section: the enemy that landed the fatal blow and the fight it happened in, your top damage sources for the run, and one honest read on whether a single source did most of the damage or you were worn down from all sides.
  • Gear can roll Minion Damage, so summoner builds finally have equipment that strengthens their minions (off by default).: Gear can now roll a Minion Damage bonus that strengthens every summoned minion's attack — the payoff summoner playstyles never had, since until now no piece of equipment touched your minions at all. It applies to demon-binding warlocks, druid summoners and necromancer summoners alike, and it can roll on any slot rather than only weapons. Traps and support summons are unaffected, and it is separate from your mercenary's damage. This is off by default while it is tuned.
  • Orbs and scythes join the loot table for warlocks, sorceresses and necromancers: Two more weapon families. Orbs — Glass Sphere, Cloudy Orb, Voidglass Orb and Eye of the Storm — strengthen chaos skills, and both warlocks and sorceresses can find them; the middle two also carry a little cold or lightning of their own, so which orb you find matters, not just which tier. Scythes — Rusted Sickle, Grave Scythe, War Scythe and Reaper's Toll — are the necromancer's melee answer, boosting bone, summoning and curse skills together, which finally gives necro a weapon worth considering besides a wand.
  • Fix 19 multi-hit cards' over-declared perHit gear-scaling boundary so their base hits get full gear value: 19 cards across 8 classes (Amazon, Assassin, Barbarian, Druid, Necromancer, Paladin, Sorceress, Warlock) declared a conditional bonus-damage line (e.g. "if in Wolf form, deal more" or "if Ledger is 12+, deal more") as if it were a guaranteed extra hit for gear-scaling purposes. That inflated the "H" divisor, so gear bonuses were divided by 2-4x even on the common play where only the base hit landed. Base hits on these cards now take full gear value; conditional bonus hits still scale, and now correctly reward meeting their condition instead of diluting the base case. Affected cards: Feral Burst, Maul, Lycanthropic Fury, Fury, Hunger, Savage Pounce (Druid), Firestorm (Druid), Charged Strike, Voltaic Pierce (Amazon), Meltdown Charge (Assassin), Raging Strike (Barbarian), Plague Burst, Acidic Decay (Necromancer), Retribution (Paladin), Shatter Storm, Arc Overload (Sorceress), Ruinous Pact, Meltgrasp (Warlock).
  • Gear can roll Poison Damage, giving poison builds their own equipment identity (off by default).: Gear can now roll a Poison Damage bonus. Poison builds finally have a weapon stat that boosts their poison the same way fire builds already boost their burn. It rolls on weapons only and stacks with your existing bonuses rather than replacing them. This is off by default while it is tuned.
  • Removed the phantom 'Scepters' weapon family from rune and runeword allowlists (Black, Oath of Radiance, and two crafting-related rune allowlists) — no item ever declared that family, so it was dead weight in the eligible-weapon list; the affected recipes now correctly resolve to Maces (and Maces/Swords for Oath of Radiance).: No visible change to any item you can find or equip. The "Scepters" family named in a few rune/runeword crafting rules never matched any real weapon, so those slots were quietly narrower than intended; the crafting rules now list only weapon families that actually exist (Black is now Maces-only, Oath of Radiance is Maces/Swords), which is what they always resolved to in practice.
  • Reward offers now favor the card your deck actually needs.: One of the two card offers after a regular battle is now picked with the deck's real gaps in mind — favoring an answer you're missing, a payoff for setup you've already banked, or a support card you're short on, instead of any role-matching card at random. This shipped switched off pending an experiment and is now on by default after a fleet-validated confirm (see the ROG-1652 promotion note).
  • Ascension (Rift) ladder now grants rewards at tiers 4, 7, and 10 — not just tier 1: each class gets a small cosmetic keepsake at Rift IV, and clearing Rift VII/X with any class unlocks account-wide pile-art cosmetics.: Previously only Rift Tier 1 paid off — the rest of the 10-tier Ascension ladder was push-for-nothing beyond difficulty. Each class now earns a small cosmetic keepsake for reaching Rift Tier 4 (Legacy Card Art, if not already unlocked), and clearing Rift Tier 7 or Tier 10 with *any* class unlocks account-wide pile-art cosmetics — rotating deck and graveyard backs at Tier 7, the full achievement-themed pile art set at Tier 10. None of these touch combat power; they're purely account-meta rewards.
  • The Summit Wardens' guaranteed grand relic, the Sigil of the Ancients, is live: the fight now shows a distinct Grand Relic door chip on the world map, and the belt upgrade ladder now has an act-4 rung (War Belt moved 5 -> 4) so there's no longer a dead act with no belt upgrade available.: The Summit Wardens (Summit Altar) now guarantee the Sigil of the Ancients on defeat — a class-agnostic grand relic that shields you at combat start and mends and strikes back every fourth turn. The world map now labels that fight "Grand Relic" instead of the generic boss-lair chip, so you know the payoff before you commit. Separately, the War Belt now unlocks at act 4 instead of act 5, closing the gap where act 4 had no belt upgrade available at all.
  • Tiered (D2-style) prefix/suffix affix system for magic/rare/set gear: Magic, rare, and set gear can now roll from a tiered pool of named prefix/suffix affixes (crit chance, intelligence, dexterity, status-resist penetration, extra potion slots, and more), with magnitude scaling by item tier the same way D2's affix system does. The system ships default-off behind a feature flag and doesn't change existing drop odds or item power when disabled. Tooltips also now render several stats that were previously invisible on existing gear and uniques, including status-resist penetration and critical chance.
  • Runes now drop from bosses, item drops can roll sockets, and runewords can be assembled by inserting matching runes into an item's sockets — a directed gambit distinct from unique drops, which stay the game's undirected jackpot.: Runewords are live for every class. The Countess now drops a rune on every clear, item drops can roll open sockets, and vendors carry a rotating rune selection that scales up with your level and how many times you've refreshed the shop. Insert matching runes into a socketed item's slots to complete a runeword and unlock its bonus — a deliberate, plan-toward-it path to power that sits alongside unique drops, which stay the game's undirected jackpot.
  • Random exploration events and Fated jackpots are now part of every run.: Route checkpoints and cleared zones can now surface a random exploration event on any run — previously this required opting in. Some of these events come up Fated: gilded, with their rewards tripled. Both are on by default after a fleet-validated A/B confirmed a favorable winnability swing.
  • Random events return: some route checkpoints now offer a strange encounter, and clearing a zone can occasionally reveal a new place on the map.: Random events are back between fights: a route checkpoint will occasionally offer a strange encounter alongside the usual choices — a shrine, a wandering trader, a risky wager, and more. And now and then, clearing out a zone reveals a whole new place that wasn't on the map a moment ago, waiting to be explored.
  • Rarely, an event comes up Fated: gilded, with its rewards magnified.: Every so often, one of the returning random events comes up Fated — the card turns gilded, and its rewards are magnified well beyond the ordinary payoff. Watch for the gold shimmer; it's worth stopping for.
  • Rogue Scout's mid-tier route perk now branches into a real either/or choice, and three mercenary descriptions were rewritten to stop implying a combat mechanic they don't have.: Rogue Scout's route-perk progression previously converged into a single grinding chain -- every deeper perk just required everything before it. Its tier-2 perk is now a genuine either/or fork: taking the "Hidden Wayfinders" path leans into hero damage scaling, while "Ridge Countermarch" leans into guard and behavior scaling instead. Taking one forecloses the other. Separately, Sunwell Lancer, Oasis Warmage, Kurast Sage, and Frosthaven Berserker's descriptions were rewritten to say what they actually do -- carry a powerful party aura -- instead of describing a special attack behavior that was never implemented.
  • Damage tooltip now shows the doubled hit for shadow-spending cards instead of half the real damage.: The damage tooltip for shadow-spending cards (e.g. Shadow Burst, Phantom Storm) now shows the true doubled hit when Shadow is banked, instead of silently reporting half the real damage. The breakdown also lists a "shadow ×2" multiplier so the number is explained, not just larger.
  • The auto-pilot and simulator can now play cards in their Adventure and Cycle modes, matching what a player could always do.: Combat autoplay (and the balance simulator behind it) now considers a card's Adventure side and Cycle option when choosing its next action, instead of only the card's normal play. Cards like Tempest Hunt or Pilgrim Vow can be auto-played on their cheaper alternate side when that is the better move.
  • Uniques on an attributed base now grant the same fixed attribute bonus a rare on that base would roll, closing a silent stat loss when upgrading into a unique.: Unique weapons and armor built on a str/int/dex base now carry that base's attribute bonus, matching what a rare or magic item on the same base already grants. Previously a unique never rolled this bonus, so upgrading from a rare into a unique on the same base could quietly cost you strength, intellect, or dexterity even though everything else about the item improved.
  • Warlocks can now find grimoires — their first weapon that boosts their own skills: Grimoires are a new weapon family for the warlock: Tattered Folio, Bound Grimoire, Daemonicon and Codex of the Abyss, one appearing roughly per act. They strengthen eldritch skills, which matters more than it sounds — until now no weapon in the game boosted anything a warlock casts. Whatever you were holding, it did nothing for your deck. Grimoires also drop and stock in shops at the rates a class's own weapon should, so a warlock finally has a weapon slot worth shopping for.
  • Weapons now show exactly which skills they boost: Every weapon used to quietly boost a set of skill lines that was never written down anywhere — a staff strengthened your fire, cold and lightning skills, and nothing in the game told you so. Those bonuses are now printed on the weapon itself, so a short bow reads "Bow Skill Damage +2, Bow Skill Support +4, Passive Skill Support +3" and you can compare two drops by reading them instead of guessing. Nothing was taken away; the same scaling you already had is simply visible now, and weapons that grant many skill lines collapse the extras behind a "more in detail" link rather than flooding the panel. One side effect worth knowing: rarity now multiplies these bonuses rather than adding a flat amount, so a unique weapon's skill scaling pulls further ahead of a white one than it used to.

Balance

  • Reforging an elevated-tier item now preserves its item level; tooltips show the effective tier.: Equipment now remembers the highest tier it ever resolved at. Reforging an elevated-tier item (from a gambled jackpot, a boss drop, etc.) at the Anvil or advancing an invested belt in place no longer resets it back down to its base tier — the roll's original power level is preserved, and item tooltips/telemetry show that effective tier rather than the item's own base tier.
  • Vendors now price an item by the affixes it actually rolled, not just its type and rarity.: Town prices used to ignore what an item actually rolled: two copies of the same base with the same rarity cost and sell for exactly the same gold whether one rolled a marginal bonus and the other rolled an excellent one. Vendors now price the rolled affix lines themselves, so a strong roll is worth more to buy and more to sell than a weak one of the same type. This shipped switched off pending an economy A/B and is now on by default after a fleet-validated, winnability-neutral confirm (see the ROG-1652 promotion note).
  • Gear affix magnitude bands are now wider by default -- qualifying affix bands roll 33-100% more spread, same means.: Gear now rolls its affix magnitudes from a wider range by default. Qualifying tiered prefix/suffix bands roll 33-100% more spread (after integer rounding) than before, while the average roll stays the same, so two items of the same rarity and tier can now land noticeably different affix magnitudes. This was fleet-validated as winnability-neutral before promotion (300 paired seeds at ascension 6, net-zero flips); the old narrower resolution remains available as an opt-out for archaeology/comparison purposes.
  • Gear now generates with the deeper D2-style tiered affix system by default — magic and rare items roll from a wider pool of prefixes/suffixes with tier-gated magnitudes.: Item generation now uses the deeper, D2-style tiered affix system by default. Magic and rare gear rolls its bonus lines from a wider pool of prefixes and suffixes, with magnitudes gated by the item's tier, instead of the flatter legacy bonus roll. This was fleet-validated as winnability-neutral before promotion; the old flat resolution remains available as an opt-out for archaeology/comparison purposes.
  • The max-energy gear affix now grants exactly +1 at every tier, and no single item can grant more than +1 max Energy from any combination of sources.: The "of Focus" affix now grants exactly +1 max Energy at every tier, instead of scaling to +2 on higher-tier amulets and helms. Energy is the most powerful resource in the game and is deliberately kept scarce -- you are guaranteed a way to reach 4 through ordinary play, and every source beyond that is meant to be rare and hard-won -- so a routinely rollable +2 from a single affix line sat well outside that intent. Alongside the roll change, the "+1 max Energy per item" rule is now enforced across every channel an item can grant Energy through (rolled affixes as well as runes and runewords), so no single piece of gear can exceed +1 by combining sources.
  • Belt-capacity shop prices can now be tuned via a config multiplier (sim price-tuning lever; default prices unchanged).: Belt-capacity upgrade prices at the quartermaster now support a configurable multiplier used by balance tuning. With the default configuration nothing changes — tier prices remain 150/400/900 gold.
  • Belt slots 6-7 are now purchase-only through the Quartermaster.: The Quartermaster's belt-capacity upgrades now do what they were meant to: your first five belt slots still fill up naturally from run rewards and exploration finds, but slots six and seven are earned only by paying the Quartermaster for them. Previously, free capacity from events and rewards could quietly climb all the way to the top of the belt on its own, leaving the Quartermaster's upgrade with nothing left to sell you. Now those extra slots are worth going out of your way — and worth your gold — to unlock.
  • The quartermaster now sells +1 belt-capacity upgrades (acts 2/3 at 150/400 gold, act-4 tier 900g in the corner case), raising the belt cap from 5 up to 7. Free capacity from events still caps at 5.: The quartermaster now sells belt-capacity upgrades: two tiers early in a run (150 and 400 gold), plus a pricier third tier once you've reached the endgame. Each purchase adds one charge to your potion belt, raising the cap from five up to seven. Capacity you pick up for free from events and rewards still tops out at five — the two extra slots are yours only if you pay the quartermaster for them.
  • Deferred belt cluster: in-place base upgrade for an invested belt, act-gated reward tiers, and an honest belt reward preview.: Belt-capacity item model follow-through: a belt you've invested in (magic/rare, sockets, runes) now has its base upgraded in place by a capacity reward instead of permanently converting to gold; capacity rewards respect act-appropriate belt tiers; and the belt reward preview shows what will actually happen — a capacity gain, a belt item, or gold — instead of always claiming "+1". These shipped behind default-OFF flags pending balance measurement and are now on by default after a fleet-validated, winnability-neutral confirm (see the ROG-1652 promotion note).
  • Belt-capacity rewards can now advance your equipped belt in place when possible (flag-gated experiment, off by default).: Belt-capacity rewards can now upgrade your equipped belt to the next tier in place — no gold cost, no lost affixes or sockets — instead of always handing you a separate belt item to carry and equip yourself. Unique belts, and belts with nowhere higher to go, are unaffected. This is a flag-gated experiment (off by default) while we measure its effect on belt-capacity pacing in acts 2-4.
  • Belt capacity now comes from your equipped belt, and capacity rewards advance it in place.: Potion-belt capacity is now driven by the belt you have equipped (plus any potionSlots bonuses from gear and charms) instead of a flat, purchase-grown counter. Belt-capacity rewards from quests, exploration events, and bosses now try to advance your equipped belt one rung in place first — keeping its rarity, sockets, and inserted runes — before falling back to granting a new belt or a small gold consolation.
  • Cold and Lightning gear affixes now roll on amulets and rings, not weapons only, so elemental casters can actually build into their damage type.: Rimebound (Cold) and Stormbound (Lightning) prefixes previously rolled on weapons only, and rarely even there. They now roll on weapons, amulets, and rings at a higher weight, roughly matching how Intelligence is supplied. Elemental casters should see gear that supports the damage type they are actually building, rather than a stream of generically good stats.
  • Wands can optionally carry Intelligence instead of a mercenary-attack stat: Wand weapons (Yew Wand, Bone Wand, Lich Wand, and the base Wand) previously carried the same martial mercenary-attack bonus as swords and axes, even though nothing about them is martial. Behind a new, currently default-off flag, that mercenary-attack stat is replaced with Intelligence at the same point value — the caster-generic stat that boosts fire, cold, lightning, elemental, curse, and poison/bone card damage alike. Staff weapons already carry Burn (a caster-flavored stat) and are unaffected. With the flag off — which is the state of the game today — nothing about Wands changes.
  • Charm vendor is now available by default from act 3 onward — a premium random-charm gold sink, gated to one purchase per encounter-progress advance.: The charm vendor is now open by default from act 3 onward instead of requiring an opt-in flag. Visit town to spend gold on a random charm — one purchase per encounter-progress advance — giving every run a new gold sink and a fresh charm-hunting decision each act.
  • Added a Charm Vendor town service (act 3+): pays a scaling gold price for a random unowned charm, gated to one purchase per battle.: Starting in Act 3, a new Charm Vendor town service can appear: pay a gold price (scaling with act and ascension) for a random unowned charm — small or large, weighted 60/40 toward small — that you don't get to see before you buy it. You can buy at most one mystery charm per battle completed (the offer refreshes only after your next fight), and the vendor won't sell you anything your pouch has no room for. This shipped behind the charmVendorEnabled flag; see the companion "charm vendor is now on by default" patch note for its live status.
  • Several spells and skills that display a cold, fire, lightning, poison, or magic identity — including the sorceress's Frost Lance, Fireball, and Thunderstrike, the paladin's Phoenix Strike-adjacent burn hits, and others — were quietly landing as plain physical damage. Their damage type now matches what the card shows and what your gear scales.: Several sorceress, paladin, assassin, druid, necromancer, and amazon cards that show a cold, fire, lightning, poison, or magic identity in their tooltip — and scale off that element's gear stat — were secretly dealing plain physical damage underneath. Frost Lance, Frost Fire, Glacial Lance, Absolute Zero, and Frost Storm now actually deal cold damage; Fireball, Elemental Mastery, Spell Cascade, Fists of Fire, Eruption, and Meteor Sigil now deal fire; Spark Bolt, Arc Surge, Thunderstrike, Telekinesis, Spell Surge, Storm Surge, Elemental Convergence, Arcane Torrent, Polymath, and Tempest Javelin now deal lightning; Poison Dagger now deals poison; a handful of "hit plus Burn" cards (Thorns, Vengeance, Zealous Brand, Holy War, Crusade, Phoenix Strike) now deal an explicit physical hit as intended; and Creed of Ashes now correctly deals fire damage in its second chapter and magic damage in its third (previously both landed as physical). This is a delivery fix, not a numbers change — the values on the card are unchanged.
  • Gear gambling and its variance-driven jackpot are now on by default, and top-end battle drops are slightly scarcer.: Gear gambling is now available by default, letting you spend gold at town for a chance at better gear via a four-bucket variance distribution (junk/decent/good/jackpot) with a 12% jackpot chance. Top-end battle drops are also slightly scarcer, so bosses and gambling become the more reliable channels for a run's very best gear — gold now buys real chances at great equipment.
  • Sim pilot learns a sell-junk-then-gamble two-step (gamble-sell-plan arm, default off) so gambling can be measured as a real gold sink when the pack is full.: Balance-sim infrastructure only — no in-game behavior changes. The seed-winnability pilot can now (behind the default-off gamble-sell-plan arm) sell a strictly-worse-than-equipped carried item to free a pack slot and immediately spend the gold on a gear gamble, so fleet experiments can measure whether gambling works as a gold sink once the pack is full. Junk selection is affix- and capacity-aware and never sells anything that could be equipped as an upgrade.
  • Raised the minimum roll on tier-1-3 (and most tier-4-6) element and attribute gear affixes -- Rimebound/Stormbound/Emberbound/Voidbound, Arcane/Keen-Eyed, and the tier-banded attribute implicit -- so they no longer floor to a dead 0 on perTarget/AoE effects; low-tier caster gear now delivers real damage instead of doing nothing.: Low-tier element and attribute gear (Rimebound, Stormbound, Emberbound, Voidbound cold/ lightning/fire/magic affixes, Arcane/Keen-Eyed intelligence/dexterity affixes, and the base attribute implicit on int/dex/str items) used to roll a +1 that did absolutely nothing against multi-target and AoE damage cards -- the bonus was too small for the math to actually add any damage. Those affixes now roll at least +2 at every tier, so a low-tier item with one of these stats reliably contributes real damage instead of sitting on the item doing nothing. Nine charms carried the same dead +1 (Large Charm of Volley, Afflictor's Edge, Grand Charm: Soulleech, Small Charm of Insight, Arcane Battery, Fletching, Stormknot, and Surgepin, plus one stat on Insight's dual Int/Dex roll) and are now +2 as well, with their tooltip text updated to match. Two of them (Volley, Insight) would have become measurably rarer drops purely from the stat bump; their rarity is pinned at its old value so this is a pure quality-of-life fix, not a drop-rate change. The starting-tier Yew Wand had the same dead +1 Spell Damage baked into its base stats and is now +2 as well; its price and drop tier are unaffected.
  • Gear valuation now weights heroInt/Dex/Str/Cold/Lightning bonuses by the measured boundary mix of the effects they scale (perTarget/perHit deliver less than perCast), so the equip-decision pilot no longer overprices AoE/multi-hit builds.: Gear that boosts Intelligence, Dexterity, Strength, Cold, or Lightning is now valued a little lower on average when comparing items — it was previously priced as if every point always landed at full strength, which overstated its worth on area-of-effect and multi-hit builds.
  • Groundwork for gear that is judged against your build instead of one global power number — shipped switched off.: Gear is currently ranked by a single global power number, so two items with different affix rolls always resolve to one ordering no matter which build you are playing — an intelligence roll and a strength roll of the same size read as equally good to everyone. This change adds the machinery to score gear against the build you are actually playing, so a stat your build cannot use counts for less, while stats that help any build (and rare max-energy rolls in particular) keep their full value. Nothing changes in-game yet: the new scoring ships behind a switch that is off by default, pending measurement. Also corrects the upgrade chevron and the power verdict so they can never disagree with each other about whether an item is an upgrade.
  • Add heroFireBonus/heroMagicBonus dedicated element-axis gear stats (default ON) and delete the unused heroElementalBonus composite: Gear can now roll Fire Skill Damage and Magic Skill Damage, joining the existing Cold and Lightning affixes. Cards that deal fire or magic damage already declared their element but had no gear stat behind it, so those lines simply did not benefit from elemental gear — fire and magic builds now scale the same way cold and lightning ones do. When a card counts as more than one element, it takes the single best matching bonus rather than adding them together.
  • Build-relevance gear scoring now separates on-build from off-build stats more sharply (unreleased system, still off by default).: Gear that suits your build is now valued distinctly more than gear that merely rolls big numbers. Where the scoring curve previously treated an off-build stat as worth most of its raw value, it now falls away sharply as the stat drifts from what your build actually wants — so two rolls of the same item are more often a genuine choice rather than a ranking. A strong roll of an expensive off-build stat is still worth equipping; a cheap one your build ignores is not. This affects the build-aware gear scorer only, which remains off by default and is not yet reachable in a normal run.
  • Certain builds now value cold, lightning, poison, and minion-boosting gear more accurately when comparing item choices.: A handful of builds — cold and lightning sorceresses, the necromancer's summon and poison decks, the druid's summoner, the warlock's demon-binding and chaos decks, the assassin's martial artist, and the javazon — now rate gear more sharply against their actual playstyle, so an item's on-theme bonuses (elemental damage, minion strength, or poison) stand out more clearly against off-theme rolls when comparing choices.
  • Gear-scaling coefficients (perTarget/perHit) are now applied to attribute/element/proficiency gear bonuses on damage cards, fixing the AoE and multi-strike gear sponge.: Attribute, element, and weapon-proficiency gear bonuses no longer add at full strength on every AoE hit or every strike of a multi-strike card — they now scale by the card's application boundary, same as the design contract always intended. A perTarget AoE card (damage_all/chaos_surge) now grants roughly half its gear bonus per enemy hit instead of the full bonus to each; a multi-strike perHit card now splits its gear bonus evenly across its hits instead of re-adding the full bonus on every strike. Single-target perCast cards are unaffected. Net effect: AoE and multi-strike decks lose an unintended gear-scaling advantage over single-target decks; the character sheet, item comparisons, and card previews all show the same, now-corrected number.
  • Kicker/overpay/countdown/adventure/saga AoE and multi-hit damage now scale through the same gear-boundary coefficients as base card effects, closing a gap where nested effect containers received full-magnitude gear scaling.: Kicker payoffs, overpay bonuses, countdown detonations, adventure sub-modes, and saga chapters that deal AoE or multi-hit damage now scale with gear the same way the card's base effects do (0.5x per target hit, 1/H per multi-strike hit). Previously these nested effects landed at full, uncoefficiented gear magnitude while an otherwise-identical effect in the card's main effect list was already coefficiented — a nerf to affected AoE/multi-hit lines, not a buff to anything.
  • Foretold Umbral Strike now scales with Dexterity; internal scaling declarations completed for nine cards.: Foretold Umbral Strike was missing its scaling declaration, so gear did nothing for it despite being a shadow skill like its neighbours. It now scales with Dexterity. Nine cards whose damage lands through a delayed or alternate-cost effect — foretold strikes, primed traps, saga chapters and kicker payoffs — carry explicit damage-type declarations for the first time. These describe what those cards already did rather than changing it, so no damage values move; they close a gap where the declaration was simply absent. Charged Strike's bonus hit is unchanged. Its gear apportionment was corrected internally to stay within the declared hit range, which produces identical numbers at every gear value.
  • Traps now scale with a new Insidious trap-damage affix; summons keep scaling with minion power. The element-affix rollout flag is retired now that it is permanently on.: Placed traps now benefit from gear: the new Insidious prefix adds flat damage to every trap you have on the field, the same way Necrotic adds damage to every summoned minion. Traps and summons scale on their own separate lines — trap gear does not buff summons and minion gear does not buff traps. The damage a trap card deals when you cast it is unchanged; only the placed device scales.
  • Autoplay and the pilot now weigh a fallen mercenary's value against the revive cost instead of always rushing back to town.: Autoplay and the pilot no longer treat a fallen mercenary as an automatic emergency. Instead they weigh the mercenary's actual value to the build — power, aura/behavior fit, and revive cost — against everything else worth doing in town. A weak, off-build mercenary may be left dead rather than rushed back to; a strong, on-build one is still revived promptly. Hero life and belt charges still force an immediate return to town as before.
  • Bosses at Normal now have 60% more life and deal 60% more damage; ordinary fights are unchanged.: Act bosses now hit harder and carry more life at Normal difficulty — 60% more life and 60% more damage than the roster otherwise suggests. Ordinary fights, minibosses, and elite packs are unaffected; this only touches the act's true boss encounter. Rift Tiers still layer their own continuous scaling on top of this new Normal-tier floor, so bosses at higher tiers are relatively tougher than before by the same 60% margin. Validated by a 720-run boss-only A/B: win rate stayed at or above 90% for every class, and the added pressure shows up specifically at boss fights rather than spreading into the rest of a run.
  • Paladin's offensive and defensive aura cards now scale their damage with Intelligence, giving paladin a strength/intelligence gear split between its combat line and its aura lines.: Paladin's aura cards — Might, Thorns, Holy Fire, Consecrated Ground, Holy Radiance, Defiance, Holy Shield and 23 others — now scale with Intelligence. Previously no gear attribute affected them at all: over half of paladin's damage cards ignored your equipment entirely, so Intellect rolls were dead weight and paladin gear meant far less than any other class's. Paladin now splits like the other dual-axis classes: Strength drives the combat line, Intelligence drives the auras. Building into either is a real choice, and Intellect gear finally does something on a paladin. This is a substantial power increase for aura-heavy builds.
  • Rare and set gear now roll 3 affix lines instead of 2 (never more than 2 of the same kind, so 2 prefixes + 1 suffix or 1 prefix + 2 suffixes).: Rare and set items are more powerful: they now roll 3 affix lines instead of 2 (never more than 2 of the same prefix/suffix kind), so a typical rare/set drop carries an extra stat beyond the previous cap.
  • Fixed magic/rare/set/unique implicit affix rarity scaling collapsing to identical values on small base magnitudes: Magic, rare, set, and unique gear now reliably grant progressively larger implicit stat bonuses over each other. Previously, low-magnitude implicits (common on early-game and cheap items) could round to the exact same bonus across all four rarity tiers, making a unique item indistinguishable from a magic one on that stat.
  • The third belt-capacity upgrade (act 4, 900 gold) has been removed — the quartermaster now sells two belt upgrades, in acts 2 and 3.: The quartermaster's third belt-capacity upgrade (previously unlocked in act 4 for 900 gold) has been retired. Two upgrades remain, available in acts 2 and 3.
  • Card rewards now taper as your deck grows: full three-card drafts below the soft cap, two deliberate picks above it, and no new cards at the hard cap.: Regular encounter rewards now pay attention to how big your deck already is. Below the soft cap nothing changes -- you still get the full three-card draft. Between the soft and hard caps the draft narrows to two choices, deliberately picked to be a real decision (a primary pick and a support/tech/pivot pick) rather than a best option plus filler. At the hard cap the draft stops offering new cards entirely and hands you the other reward types instead. The intent is that a deck stops silently bloating past the point where drawing your good cards is reliable, and that the late-run choice becomes "is this better than what I have" rather than "how many more can I take".
  • The autoplay pilot now values every reward on one measured gold-equivalent scale, so a big stat reward no longer scores the same as a small one.: The autoplay pilot (and the assist highlight / decision-EV overlay) used to price non-card rewards on a hand-written table that stopped counting past three points of anything — a +10 max life reward and a +3 one scored identically, and about seventy percent of the charm catalog landed on the same number. It now prices every reward, cost, charm and item on a single gold-equivalent scale derived from the prices the game's own events and vendors charge, with no magnitude cap. Rewards that were previously indistinguishable now rank by how much they actually give you, mercenary attack is valued against max life at the rate the game's own shop prices imply, and a reward that costs you gold or life is weighed against what it buys instead of being scored as pure upside.
  • Assassin Shadow Master gains two shadow-spend damage payoffs (Shadow Strike Deep, Void Lash) in its arena deck and a higher early-act energy floor, fixing its early-act boss losses.: The Shadow Master arena build lost nearly every early-act boss fight (acts 2 and 3 went winless) in long ~22-turn attrition losses: its setup-heavy deck spent whole turns cycling stealth and defense with no energy left to attack, so sustained single bosses simply out-lasted the shadow ramp. Its early-act energy floor rises (3 to 4 in act 1, 4 to 5 in act 3) and its flex slots add Shadow Strike Deep and Void Lash so the ramp has payoffs to cash into, lifting acts 1-3 arena performance from 77/86/80 percent to roughly 93/95/89 percent with no late-act regression.
  • Paladin Combat Zeal arena build gains mitigation flex cards (Divine Shield, Defiance, Holy Shield) and a melee-peer act-5 stat floor, fixing its act-5 collapse vs multi-elite fights.: The Combat Zeal arena build was the roster's weakest late-game deck: an all-offense card list with a caster-tier stat floor lost nearly half its act-5 fights, going winless against the Summit Wardens and the elite breach/ambush branches. Its flex slots now bring Divine Shield, Defiance, and Holy Shield (replacing Sacrifice), and its act-5 stat floor rises to match melee peers, lifting act-5 arena performance from 55% to about 92% without touching the build's zeal-chain core.
  • Radomir's plague festers faster, the Pale Conjurer is sturdier, and Battlemaid Sarina now splits armor — the act 2-3 minibosses actually bite.: Three of the act 2-3 minibosses were easy to no-sell — their signature damage was fully absorbed by Guard, or they died too fast for it to matter. Radomir's Plague Touch now poisons harder and never cools down, the Pale Conjurer has more HP so his burn and summoned adds get a real chance to land, and Battlemaid Sarina's new Armor Splitter shatters most of your Guard before the hit connects. Stack Guard against these three like you used to and you'll feel it.
  • Typed-damage/resist affix lines on weapons and armor now always roll from the unified registry; the narrow UNIQUE-rarity fallback path this composite roll entry point serves no longer grants a legacy weapon/armor profile or its hidden 10% immunity chance.: Weapon typed-damage/effect lines (fire, cold, lightning, poison, Burn/Freeze/Shock/Slow/ Crushing) and armor resistance lines now always roll through the unified affix registry — this was previously gated behind an internal flag validated by an 8-class balance test that came back winnability-neutral. One reachable edge changes: this roll entry point's UNIQUE- rarity path (reached by, e.g., rolling a UNIQUE drop with no eligible unique item for that base) previously still granted the full legacy weapon or armor profile — three guaranteed typed-damage/effect or resistance lines, plus a 10% chance of a bonus elemental immunity on armor. That whole fallback profile is retired along with the legacy roller: this path now grants no weapon/armor lines and no immunity chance at all. This is a narrow, largely invisible edge (real UNIQUE drops normally carry their own authored profile and never reach this fallback), not a broad rarity-tier change.
  • Hesphar's Molten Crescendo and Azuel's Corruption Cascade both ship on by default: Hesphar the Forgemaster and Azuel the Fallen both gain new threat beats. Once Hesphar's Hellforge Anvil is destroyed and his full attack pool is unleashed, he now periodically telegraphs paired Molten Crescendo strikes — the previously flat unleashed phase carries a rhythm you can play around. Azuel's corruption clock now also builds toward periodic paired Corruption Cascade spikes, telegraphed the same way. Both ship ON by default after fleet A/Bs confirmed they are winnability-neutral roster-wide.
  • Belt-capacity rewards under the items model now equip-swap a plain white belt (or pay a tier-scaled consolation) instead of a flat 25g when the pack is full (flag-gated, default off).: With the item-derived belt-capacity model enabled, belt-capacity rewards no longer fizzle into a flat 25 gold when your pack is full: if you're wearing a plain white belt, the reward now upgrades it in place to the next-tier belt and pays you half the old belt's value in gold. Belts with any investment (magic or better, sockets, runes, runewords) are never swapped away — those cases instead pay a consolation scaled to the withheld belt's tier. This model is still experimental and off by default.
  • Autoplay town chooser now prices merc revives and belt refills through the sim's shared valuation primitives: Autoplay's town decisions now weigh a mercenary revive against its actual combat value instead of a flat price — a badly wounded merc will more often skip an expensive revive in favor of buying stronger gear or healing the hero first. An empty potion belt is now treated as a real emergency: autoplay will refill it before almost anything else, since running out of potions mid-fight was previously under-valued.
  • Assassin shadow damage now scales with Dexterity; warlock chaos and eldritch damage now scale with Intelligence.: Assassin's Shadow Disciplines damage cards now scale with Dexterity, and Warlock's Chaos and Eldritch lines now scale with Intelligence — gear investment in those attributes finally pays off on those cards, the same way it already did for the other proficiency lines in each class.
  • Declare fire scalingElements on meteor_sigil/falling_meteor and a summoning proficiency on necromancer_grave_orders, closing three gear-scaling declaration gaps.: Meteor Sigil and Falling Meteor now correctly declare their fire element for gear scaling (previously undeclared despite dealing fire damage), and Grave Orders now carries a proficiency so it is eligible for the same gear-scaling bonuses as other necromancer damage cards.
  • Class-aware town stock and gambling, affix-aware pricing, belt upgrade-in-place and act-gating, shrine Attune choice, need-aware reward drafts, Warding elite aura, and a deeper elite trait pool are all switched on by default.: A batch of previously opt-in features are now on by default, having cleared fleet-validated A/B testing: town vendor stock and gear gambling now lean toward gear that suits your class's attributes (never exclusively — off-attribute picks stay reachable); vendors price an item by the affixes it actually rolled, not just its type and rarity; an invested equipped belt now upgrades in place instead of falling back to a gold consolation, and belt rewards no longer offer a belt gated to a later act than you're currently in; shrines can offer a fourth "Attune" choice that grants a charm suited to a committed build; the reward draft's support/tech slot now favors the card your deck actually needs over an arbitrary pick; the Warding Aura elite affix and the Vengeful elite affix (plus its Thermal Shock / Hexdrinker synergy pairs) are now part of the normal elite trait pool from act 3 onward at high ascension. Each of these can still be switched off via its existing escape hatch if you notice a problem.
  • Sage deck-surgery removals are now priced at a premium from act 3 onward (with a new act-5 slot) and the town planner values them correctly by default.: The sage now charges a premium to remove cards from your deck starting in act 3 (roughly 3x the old rate), with a brand-new removal slot unlocked in act 5. In exchange, the town planner's build guidance now correctly recognizes and values these removals, so it stops undervaluing deck cleanup the way it used to.
  • Sage deck-surgery gets a pilot valuation fix (sage-pilot, sim-only) and an opt-in premium repricing + act-5 expansion (sageSurgeryRepricingEnabled) — both default OFF pending measurement.: No player-facing change ships in this pass — both levers land default OFF. Behind the scenes, the balance sim's town-planner now has a working (arm-gated) valuation for the existing "excise a card" deck surgery service at Corven Vale, so future balance sessions can actually measure how it's used instead of assuming it's dead. A separate, also-off flag prototypes a pricier deck-surgery tier for acts 3+ plus a new act-5 option, for a future balance pass to evaluate before any of it reaches players.
  • The auto-play pilot now treats paying gold as a cost, so it weighs the price of a purchase instead of taking every deal for free.: Wherever an event offers to sell you something -- the gambling dens, the peddler, the travelling smith, the wishing well, the shrine tithes -- the auto-play pilot was scoring the gold you hand over as a small bonus rather than a price, and ignoring how large the price was. Paying thirty gold looked exactly like paying ten. That made every purchase read as free, and it erased the choice built into the paired offers: a big bet and a small bet, or buying in bulk versus buying one, differ only in what they cost and what they return, and the pilot could not see either half of that trade. Gold costs are now weighed as costs, and in proportion to the amount, so the pilot picks the offer that is actually worth its price.
  • The auto-play pilot no longer treats self-inflicted damage as a reward, so it stops choosing shrine offerings that cost you health for their own sake.: The auto-play pilot scored the health cost on a shrine offering as though it were a benefit, which meant it reliably picked the option that hurt you -- and the damage was the reason that option won. At the Shrine of War it took "Embrace the Fury" over "Reject the Shrine" every time, not because the mercenary attack was worth six health, but because losing the health scored positively on its own. Costs are now weighed as costs, so the pilot evaluates a shrine as the trade it was designed to be. This also affects balance measurements: every simulated run that passed a shrine was carrying a health trajectory shaped by the mistake.
  • The auto-play pilot now values charms and gear on the same scale as everything else it compares them against.: When the auto-play pilot weighed a reward grid, charms and gear were priced by the game's real power scorers while every other option used a separate hand-written scale. The two were added together as though they meant the same thing, and they did not -- a whole build-matched charm came out worth less than a single point of max life, so the pilot would pass up a charm for a trivial stat bump almost every time. Charm and gear values are now converted into the same units as the rest of the grid before anything is compared, and the same ceiling that applies to stat rewards applies to them too. Charms and gear are now weighed on their merits against the alternatives, which also means balance measurements involving them reflect what a reasonable player would actually pick.
  • Druid Season of Storms now genuinely deals lightning instead of physical, matching its always-electric flavor. (Sorceress Spell Cascade's element-typing split was tried and reverted — see below.): Druid's Season of Storms had a text/data mismatch under ROG-1680's "declared elements deal elemental damage" ruling: its three saga chapters displayed as lightning (feeding the Plasma archetype) while actually dealing physical damage. All three chapters now genuinely deal lightning damage, matching their always-electric flavor. There is no enemy-side elemental resistance in the game yet, so this has no combat outcome change today. Sorceress's Spell Cascade has the same kind of text/data mismatch (its flavor text names three elements but the card carries one flat, untyped damage value) and was NOT changed. Splitting its one combined hit into three separately-typed hits was attempted and reverted after review: three separate hits are three separate landings to nearly everything except the gear-bonus math — non-gear damage bonuses (temp bonuses, synergy, pending-skill effects, auras, skill-rank bonuses) and per-instance effects (thorns retaliation, weapon riders, lifesteal, elemental procs, minimum- damage floors) would all have tripled, a real and significant power increase disguised as a cosmetic typing fix. Spell Cascade is unchanged and stays flagged as a known text/data mismatch pending a different fix that doesn't require adding extra hits to the card. Separately, perHit (the mechanism for cards that strike multiple times) now composes with the kind of coefficient area-of-effect cards use, instead of always assuming a single-target coefficient — a general correctness fix with no shipped card changes today (no card currently uses this combination).
  • Javelin damage now scales with Dexterity (matching bow) instead of Strength; barbarian warcry damage cards now scale with Intelligence, giving warcry-tempo barbarians a deliberate int-gear build option.: Amazon's javelin cards now scale their damage with Dexterity instead of Strength, matching the bow line — Amazon is now coherently a Dexterity class across both her weapon proficiencies. Separately, barbarian's damage-dealing warcry cards (War Cry, Thunderous Cry, and other warcry-tempo damage cards) now scale with Intelligence. This is intentional: it opens up an Intelligence-gear "warcry" build as a build-diversity option inside the Strength class, alongside the existing Strength-scaling combat/mastery cards. It is not a bug — barbarian's other proficiencies (combat, combat_skills, masteries, martial_arts) are unchanged and still scale with Strength.
  • Trade Network account tree converts to point allocation: rank thresholds 1/4/7 award tokens spent on buy/sell/refresh/socket rate lanes or gamble-stake discounts.: The Trade Network account tree now offers real choices instead of automatic discounts. Crossing its milestones advances your Trade Rank as before (and every unlock you already earned — vendor depth, consignment, the gold ledger — is untouched), but the generic buy/sell/refresh/socket price discounts are no longer granted automatically: ranks 1, 4, and 7 each award an allocation token, spent on a permanent either/or pick — cheaper buying vs richer selling, cheaper stock refreshes vs cheaper socket commissions, and discounted gamble stakes vs a broad generalist discount. Picks are confirmed and permanent, mirroring the Mastery Hall. Veterans keep their earned ranks and can allocate their banked tokens on their next visit.

Content

  • Act-1 trash monsters (pack clans, shadow/vile raiders, beasts, constructs) now carry distinct attack patterns instead of a shared generic kit.: Act 1's trash packs stop reading as one generic raider in different skins: pack-hunter clans howl and hex their allies, shadow and vile raiders pierce guard or poison on the lance, thorned beasts punish melee, harrying flocks strike twice for less, and gargoyle traps and returned corpses each fight with their own telegraph. Difficulty is unchanged -- this is a variety pass, not a nerf or buff.
  • Act 2 desert-region trash monsters gained distinctive kits (pouncing cats, swarms, undead, skeletal horrors, slingers, structures) instead of reused generic attacks.: Act 2's desert-region trash monsters now fight with distinctive tactics instead of reused generic attacks: pouncing desert cats, a chip-everything swarm cloud, corpse- eating carrion feeders, a life-draining bat demon, smoldering burning dead, a withering-curse mummy, crackling-lightning skeletal horrors, ranged slingers, and stationary fire/lightning structures each have their own kit.
  • Act 3 (Kurast jungle) trash monsters gained distinctive abilities — priests heal, cantors buff, sextons detonate corpses, temple guards shield, jungle beasts poison/drain/pounce — cutting the generic-trash rate from 54% to 14%.: Act 3's Kurast jungle and Cult of the Idol trash monsters shed their generic attack-only scripts for kit-driven abilities matching their D2 identity: Idol Priests chant healing over their allies, Cantors sing a war hymn that buffs the pack, Sextons desecrate graves for corpse explosions, Temple Guards shield the line, and Idolites hunker down as stone golems. Zealots, Idol Zealots, and the Faithful now dart in with a fast double strike; Hierophants and Council Members intone a weak lightning judgment across the whole party. In the swamp and jungle, Frog Demons spit venom, Swamp Dwellers and Bog Creatures slough a poisonous mist over the group, the leeching Blood Divers/ Lampreys/Suckers/Mosquitoes drain life, Tree Lurkers and Cloud Stalkers ambush-charge past guard, Doom Apes frenzy, Tentacle Beasts flail at everyone, Winged Nightmares shriek away energy, and Slime Princes smother foes in chilling ooze. Kurast's Hell Swarm now correctly shares the established swarm-cloud kit instead of falling through to a generic script, and the Willowisp (Gloam) row now reuses its own family's proper kit.
  • Act 4 (Hell / Chaos Sanctuary) trash monsters get distinctive kits — Doom Knight vanguard slam, Abyss Knight hellfire brand, Finger Mage mana siphon, Vile Mother brood-summoning, swift Vile Child, Vile Witch hex, Strangler force-discard, Groper chill grasp, Megademon anti-summon cleave, thorned Razor Pit Demon, and blinking Dark Familiar.: Hell's trash monsters fight back with their own tricks now: Vile Mothers summon Vile Children mid-fight, Stranglers rip cards from your hand, Megademons cleave down your summons, and Dark Familiars blink away from danger — Act 4 no longer plays like a wall of reskinned attackers.
  • Act-5 monster trash gets 19 new distinct kits (Catapult, Siege Beast, Overlord, Dominus, Blood Boss/Bringer, Hell Spawn, Putrid Defiler's Defiled Warrior summon, and more), cutting act-5 generic-reskin rate from ~46% to 11%.: The armies besieging Harrogath now fight like Baal's own: Suicide Minions detonate on death, Catapults entrench and barrage, Siege Beasts ram your line, Overlords lash allies into a frenzy, Dominus hexes weaken your hero, blood demons drain life, Demon Imps blink across the field, Putrid Defilers call up real Defiled Warriors, and the frost fauna of the highlands chills, pounces, and pulverizes. Twenty-nine Frost/Vaught/Crown Stone variants also inherit their base families' mechanics from earlier acts. Names and art are unchanged — the monsters you already know just stopped being copies of each other.
  • The five act bosses finally have bestiary lore — the seals on the road get their stories.: The bestiary no longer goes silent at the top: all five act bosses — the Briar Matron, the Sepulcher Devourer, the Idol Patriarch, the Ashen Lord, and the Siege Tyrant — now carry lore entries in the established voice, along with the Tyrant's war-host levies. Check the bestiary after a boss kill and the seal you just broke has its story.
  • Spell Cascade is now fire, cold and lightning damage in one hit (5/5/5); it gains the cold tag.: Sorceress's Spell Cascade now deals its 15 damage to all enemies as a genuine three-element split (5 fire, 5 cold, 5 lightning) in a single hit (the rendered rule text still reads 15 damage; the split is not shown), and its scaling now reads fire, cold, and lightning gear instead of fire alone — it also picks up the cold tag alongside its existing fire and lightning tags.

UI

  • Magic and rare items are now named from their rolled affixes (e.g. Honed Short Sword of Vitality).: Magic and rare gear now carries a name built from its actual rolled affixes — the strongest prefix and suffix fragments wrap the base item name, D2-style (a rare with many lines shows its two strongest). Uniques keep their fixed names, and white and set items keep their base names. Purely cosmetic: no stats, drops, or prices changed.
  • Screen Scale simplifies to Standard / Fit Height - the Fill Window option could crop interface text on unusual window shapes and has been retired (existing Fill users get Fit Height).: The Screen Scale setting now offers two options, Standard and Fit Height, instead of three. Fill Window has been removed because it could crop interface text and controls on unusual window shapes; anyone who had Fill Window selected will automatically switch to Fit Height.
  • Added a Screen Scale display setting (Standard / Fit Height / Fill Window) that lets the desktop canvas scale up past 1x, capped at 1.25x, on large monitors.: Added a "Screen Scale" option to Display settings (Standard / Fit Height / Fill Window). On large monitors, Standard still caps the game canvas at its native size, but Fit Height and Fill Window now let it scale up to 1.25x so the game reads bigger — Fit Height never crops, Fill Window crops symmetrically to fill the window edge-to-edge. The change applies immediately, no restart needed.
  • Class-select now shows each bloodline's complexity tier and a one-line playstyle read, including for classes you haven't unlocked yet.: Picking a class used to mean judging a portrait and a short pitch line. The class-select screen now carries a Complexity chip (Straightforward / Moderate / Intricate) and a mechanics-grounded playstyle line for every bloodline, so you can tell a rage-spending frontline brawler from a three-engine spellcaster before you commit. Locked classes get the same read in the roster rail, so the classes you're chasing tell you what you're chasing them for.
  • Explain why the game switched to compact layout, and how to get it back.: When your browser window is too small or zoomed in past 100%, Angel Snack now shows a compact layout instead of the fixed game frame. A dismissible banner explains why and reminds you how to reset browser zoom (Cmd+0 on Mac, Ctrl+0 elsewhere) if that's the cause — dismiss it once and it stays gone.
  • Defeat now unfolds from the final battlefield through a readable rift and bloodline handoff.: Defeat now holds on the fallen battlefield before the verdict arrives, a rift tears through the scene, and the surviving bloodline legacy appears. Players can skip the sequence at any time, while reduced-motion settings reveal the settled result immediately.
  • Desktop polish: the title screen offers a working Sign In button when guest play is closed, the spellbook no longer strands single-card cost rows on an empty page, the combat hand centers between the energy orb and End Turn, discard/exhaust piles are legible, and camp-menu labels/icons are clearer.: A desktop polish pass on five surfaces. When guest play is closed, the title screen's primary button is now a working Sign In (previously a dead disabled button with no sign-in control on the page), and the locked Battle Arena button explains why. The spellbook packs small cost groups side by side instead of giving each one a mostly empty full-width row. In combat, the hand of cards centers in the true gap between the energy orb and the End Turn cluster, and the discard/exhaust piles got the same legible styling as the draw pile. The camp menu no longer shows a second conflicting "Act N:" label and its Wiki/Art entries have distinct icons.
  • Fullscreen toggle in the camp menu (hidden where the browser doesn't allow it; Esc exits stay in sync).: Added a Fullscreen item to the camp menu's tools section. It flips the whole game into browser fullscreen and back, the canvas re-fits automatically on enter/exit, and the menu label stays correct even when you leave fullscreen with Esc. The item only appears in browsers that support fullscreen (it's hidden on iOS Safari).
  • Choosing a class now takes you straight into the hunt when you have no rift depths to pick from.: Picking your hero used to drop you on a setup screen that asked which rift depth you wanted — even when there was only one to choose. That screen now appears only once you have actually unlocked deeper rifts and the question means something; until then, committing to a hero takes you straight out onto the road. Note that this makes hero selection the point of no return on a fresh run: there is no longer a setup screen to back out from.
  • Locked skill-tree nodes now preview their numeric rank-1 grant, and world-map waypoints mark encounters that carry a modifier.: The class-tree archive/wiki view now shows the same numeric "what rank 1 buys" preview for locked nodes that the live in-run tree already showed — so you can compare capstones before committing points, not just read flavor text. World-map waypoints also gained a small marker that appears whenever a node's encounter carries a modifier (fortified line, ambush opening, etc.) — it tells you a modifier is in play without spoiling which one, so a hidden mechanical weight becomes a visible one before you commit to the fight.
  • The World Map exit in town now carries visual weight matching its role as the action that advances the run.: In camp, the World Map gate now stands taller against the shopkeepers around it. It was easy to read the six lit shop portraits as the whole screen and miss the one control that actually sends you back out on the road — so the exit has been given presence to match its job. Nothing moved, and the shops are unchanged; the door is simply easier to find.
  • Added the Unique Codex: an account-scoped found/unfound collection view for every hand-authored unique item, reachable from the Hall.: The Hall has a new Codex tab tracking every unique item in the game. Uniques you have found in any run show their name and art; the rest appear as silhouettes, with found counts overall and per class — so a rare drop is now progress toward a collection, not just a one-off surprise.

Fixes

  • Spells that say they deal cold, fire, lightning or poison damage now actually deal that kind of damage.: A spell whose text read "Deal 12 cold damage" was quietly dealing plain physical damage instead — the wording was right, but nothing behind it was. That was true of every elemental attack in the game, including Ice Bolt, Blizzard and the whole sorceress elemental line. Cards now deal the kind of damage they say they deal. Nothing about their numbers has changed, and nothing in the game currently treats one kind of damage differently from another, so you will not see a difference in play today. It matters because everything built on top of elemental identity — gear that favours one element, enemies that shrug off another — needs the cards to be telling the truth first.
  • Carried (unequipped) items no longer lose their rolled affixes, rarity, and unique identity when the game is saved and loaded: Items sitting in your inventory (not equipped) were silently stripped of their rolled affixes, rarity, and unique identity every time the game was saved and loaded — only equipped gear kept its rolls. Carried items now survive save/load intact, so stashing a good drop for later no longer ruins it.
  • Fit every class selector card inside the iPhone landscape frame.: The hero selector now presents every class as a consistent, full-size touch target on iPhone landscape screens, without hiding later choices below a nested scroll lane.
  • Remove the dead weapon-proficiency reader that no item ever fed: Player-invisible cleanup. getWeaponAttackBonus/getWeaponSupportBonus read weaponProfile.attackDamageByProficiency/supportValueByProficiency, a field pair no item has authored since ROG-1613 moved base-weapon proficiency value into explicit bonuses.hero<Discipline>Bonus implicits — those getters always returned 0 in every build. This change deletes the dead reader half end-to-end (getters, type fields, tooltip/preview/scoring mirrors) while leaving the live typedDamage/effects unique mechanic untouched, and adds a content-scan tripwire so the deletion stays safe if a future item ever tries to author one of those rows again.
  • Restore the fleet's dev-dependency install closure so sim hosts can build again.: Internal tooling only — no gameplay change. The balance-simulation fleet installs without dev dependencies and compiles the test project on every sync, so a test importing a dev-only package broke every host's build. The offending test now compiles through a separate local-only project, the dev dependency returns to where it belongs, and a fast check blocks any future test that would reintroduce the problem.
  • The damage breakdown and preview tooltip now show what your gear actually contributes, instead of the pre-coefficient value.: The combat log and preview tooltip were showing the raw value of your gear stats rather than the amount that actually reached the damage. On an area-of-effect card, +3 Intellect displayed as "intellect 3" while only 1 was applied; on a multi-hit card each hit claimed the full bonus while the total was split across the hits. The listed numbers did not add up to the damage dealt. The breakdown now shows a single "gear" line carrying the real, post-scaling contribution, and it matches between the preview and the combat log. Damage itself is unchanged — only what you were being told about it.
  • Replace the placeholder iPhone icon with the Angel Snack sword mark.: The installed iPhone app now uses the game's gold sword mark instead of the default Capacitor placeholder, making Angel Snack recognizable on the Home Screen and in system surfaces.
  • Native iOS screenshot reviews now normalize the simulator framebuffer into readable landscape captures.: Simulator review bundles now preserve the same landscape reading direction as physical iPhone captures instead of leaving the rendered game sideways.
  • Locked-class playstyle guidance now stays readable across mobile landscape layouts.: Locked-class complexity and playstyle guidance now remains legible at the mobile text floor instead of shrinking below readable size in landscape layouts.
  • Mobile combat now respects iPhone cutouts, keeps Prepared effects readable, shows card art, supports touch dragging, and opens a larger selected-card preview.: On phones, combat controls now clear the iPhone camera cutout and long Prepared-effect text stays horizontal. Card illustrations remain visible in the hand, dragging works alongside tap-to-inspect, and the selected-card preview uses substantially more of the battlefield while staying below the combat header and above the hand.
  • Kept dragged card art visible and made enemy status attacks play as readable, non-overlapping mobile combat beats.: Dragged and played cards now keep their full artwork and contrast. Ordinary card plays reconcile in place instead of rebuilding the combat screen, use compositor-only clone motion, and return control sooner after the replacement-card draw. Enemy status attacks use a compact actor-anchored action cue, show their elemental charge and target impact in order, and leave a readable settle gap before the next combatant begins. Cinematic pacing now keeps those beats deliberate without letting a five-actor mobile turn hold controls for more than 15 seconds.
  • Expanded first-run tutorial and Wake Camp controls to reliable mobile touch targets.: First-run prompts now keep comfortable touch targets on phones, and the Wake Camp arrival action no longer shrinks below the mobile interaction floor. Tutorial panels also reposition from their rendered size so the larger controls remain fully visible on short landscape screens.
  • Fixed perHit gear-scaling apportionment to resolve the correct hit index for any effect container (kickerEffects, cycleEffects, overpay, countdown, autoplay, adventure, saga chapters), instead of always searching card.effects; also fixed a latent identity-loss bug that made every cloned perHit effect (including base card.effects during real play) default to hit index 1.: Multi-strike cards now split their gear bonus evenly across every hit, no matter which part of the card the hit comes from (base cast, kicker, cycle, overpay, countdown, auto-play, adventure, or a saga chapter) — a couple of multi-hit cards were previously over-applying gear on some hands because every hit was silently credited as the card's first hit.
  • Damage preview now includes Strength scaling: Strength-scaled cards (Bash, Whirlwind, and the rest of the physical/melee lineup — 124 cards in total) now show the correct predicted damage in their hover tooltip and hand display. The blue damage number previously omitted your Strength bonus entirely, so it under-reported the actual hit for any hero with nonzero Strength gear or buffs; the real damage dealt was always correct, only the preview was wrong.
  • Cleared all production npm audit advisories (tar critical, js-yaml/cosmiconfig/graphile-worker high, deepmerge-ts/@prisma/config high) via non-breaking version bumps.: No player-facing change. Bumped tar (critical: crash/DoS advisories), js-yaml (high: exponential-time DoS parsing untrusted YAML), and deepmerge-ts (high: stack exhaustion) to their patched versions and added a pre-push guard (npm run check:prod-audit) that fails by name on any critical advisory in the production dependency tree going forward.
  • Add a content-validation guard ensuring every resolved card proficiency has an explicit attribute-scaling decision (mapped or deliberately non-scaling).: Internal only: no player-facing change. Adds a content-validation test guard so a typo'd or unresolved card proficiency value silently disabling attribute scaling (as happened with the dead "holy" row in ROG-1586) can no longer land unnoticed.
  • Fixed content-drift guards by porting arena deck balance tweaks into sim policy specs and refreshing the monster registry snapshot; no player-visible change.: Internal-only fix: no player-facing change. Two content generators (the arena deck-spec builder and the monster-registry extractor) had drifted from their source data after prior balance edits were hand-applied to the generated files instead of the source. We ported those edits into the source and regenerated — the arena decks and monster stats players see are unchanged.
  • Rogue Scout's Hidden Wayfinders vs. Ridge Countermarch route-perk fork is now reachable: The Crossroads Signal opportunity at the act-1 vigil shrine lets you choose.: Contract Rogue Scout, light the vigil shrine's beacon blessing, and a new act-1 opportunity — The Crossroads Signal — now opens up: mark the hidden paths for an offense-leaning route perk, or drill the ridge withdrawal for a guard-leaning one. Previously neither perk could ever unlock; now the choice is live.
  • Responsive CSS now rejects raw viewport-unit regressions in each stylesheet instead of hiding them inside a pooled total.: Responsive layouts now keep each stylesheet accountable for raw viewport-unit use, preventing a cleanup elsewhere from masking new double-scaled text or controls on mobile screens.
  • Widen and center the first-run wakeup narrative on phone landscape screens.: The opening campfire narrative now spans and centers within phone landscape screens, keeping every line visible while leaving the sealed-scroll action clear and tappable.
  • Made the home artwork fill the screen without the outer gate showing around it.: The welcome screen's artwork now stretches to fill the whole viewport, so the outer gate frame no longer shows around its edges on any screen size.

Tech

  • Split admin-settings-view.ts into config/tables/orchestrator modules to stay under the 500-line cap (ROG-1507); no behavior change.: No player-facing change. The admin settings view (src/ui/admin-settings-view.ts) was split into a server-config module, a users/logs tables module, and a thin render orchestrator to stay under the repo's 500-effective-line cap, following the existing admin-settings-view-runs.ts split pattern. Behavior, markup, and dispatcher wiring are unchanged.
  • Groundwork for migrating legacy weapon/armor affix pools onto the unified affix registry (flag default-off, zero behavior change at the time).: No player-facing change at the time. Internal groundwork only: added a rollUnifiedAffixesEnabled flag (default off), a discriminated output-kind schema on the affix registry, and a composite rollEquipmentAffixes roll entry point that the legacy weapon/armor affix pools would migrate onto in later changes. One real fix rode along: getAffixEntryById no longer read an eager module-load snapshot that missed the elements-sibling registry entries, so element affix display names resolved instead of silently falling back. Superseded: the flag and the legacy weapon/armor rollers this groundwork prepared to migrate off of were retired outright in the ROG-1688 slice-3 cutover (see balance-rog-1688-affix-cutover.md) — the registry path this groundwork built is now the unconditional, only path.
  • Fixed the tiered-affix roller (behind affixDepthEnabled) so a requested N-line roll always delivers N lines instead of silently under-delivering when a prefix/suffix quota filled early.: The tiered-affix roller (still flag-gated behind affixDepthEnabled, default off) could silently deliver fewer affix lines than requested: once the prefix or suffix quota filled early, remaining picks were discarded instead of falling to the other pool. Rolls now always deliver the requested line count, so gambled and dropped gear carries its full budget when the affix system is enabled.
  • authored the base attribute identity (str/int/dex or paired) for every weapon family and chest armor class, plus a runtime-catalog guard: Player-invisible groundwork (ROG-1621). Every base weapon and chest-armor template now carries a declared attribute identity (e.g. Swords are str_dex, cloth armor is int); every other slot is explicitly neutral. Nothing reads this field yet — no combat math, loot roll, or affix gate changed — it is data authoring plus a test guard in preparation for a follow-up ticket that will use it. Players will see no change from this patch.
  • Vendor belt stock floor, item-based capacity rewards, and capacity-shop retirement behind the belt-capacity-from-items flag (disabled by default).: No live player-facing change: beltCapacityFromItemsEnabled remains OFF by default. When enabled internally, town vendors always stock an act-appropriate belt so item-based capacity growth can't be RNG-starved, capacity-granting rewards and exploration events hand over the next-tier belt (or a small gold consolation once fully upgraded) instead of an abstract bonus, the quartermaster's belt-capacity purchase disappears in favor of gear, and owned charms' potion-slot bonuses now count toward effective belt capacity.
  • Groundwork for deriving potion-belt capacity from equipped belt items (disabled by default; no player-facing change).: Adds the data model for deriving potion-belt capacity from equipped belt items and affix bonuses, behind a new boot-config flag (beltCapacityFromItemsEnabled) that defaults OFF. This phase is pure data model + derivation — belt items now carry an authored beltCapacity, gear can carry a potionSlots affix, and a new (unused while the flag is off) run.progression.legacyCapacityBonus counter exists for a future migration of reward-granted capacity. No vendor, reward, sim, or gamble logic changed, and no player-facing behavior changes in this release.
  • State-aware valuation of potion-slot capacity in gear and charm comparisons (disabled by default).: Gear and charm comparisons (the gear screen's power verdict, autoplay, and the vendor/inventory shopping logic) now know how much an extra potion slot is worth given how many the run already has — an empty belt values a new slot highly, a nearly-full one only slightly, and a slot that would overflow the 7-charge cap is worth nothing. Off by default; no visible change until enabled.
  • Sim: boss-scalar arm scales only boss encounters for same-pin difficulty A/Bs (default behaviour unchanged).: No player-facing change. Adds a boss-scalar:<life>[,<damage>] sim arm (--arms) that applies its life/damage multiplier ONLY to an act's true boss encounter — minibosses and every other encounter stay byte-identical — so a fleet A/B can probe the boss-floor difficulty lever in isolation from the earlier monster-scalar arm's flat (every-encounter) scaling, which a 720-run A/B showed broke act 1 while barely moving boss-floor medians.
  • Gear affixes can now be restricted to specific classes; no affix uses this yet, so drops are unchanged.: Groundwork only. The affix system can now mark a gear affix as class-restricted, so a stat that only serves one class can be offered to that class without diluting everyone else's drops. Nothing is restricted yet and the feature is off by default, so gear rolls exactly as it did before this change.
  • Internal: combat now reads each card's own scaling declarations. No player-visible change.: Combat now works out which gear boosts a card by reading what the card says about itself, rather than inferring it from which skill tree the card happens to live in. That inference was the reason a card could sit in an elemental tree while behaving as something else entirely. Every card was checked, one by one, to confirm the new route produces exactly the same numbers as the old one — so nothing about damage, gear or builds changes in play. The point is that the game now has a reliable answer to "what scales this card", which is what the rest of the gear rework is built on.
  • UI reads combat state through a public facade instead of engine internals: No player-visible change. Nine combat-view UI modules previously reached directly into seven __ROUGE_COMBAT_ENGINE_* private engine sub-namespaces (helpers, turns, preview, corpse, minion actions, token system, defense flavor) to read card-cost, targeting, and preview data. They now read the same functions through a new public facade, ROUGE_COMBAT_ENGINE_READS, closing part of the ROG-989 cross-domain boundary ratchet (baseline dropped 205 → 177). Part of the ROG-1512 code-quality epic, phase 2.
  • Internal: damage effects now declare how they deliver damage. No player-visible change.: The last piece of groundwork for the gear rework (ROG-1600). Every damaging effect now records how it actually delivers its damage — once per play, once per enemy hit, or once per strike on a multi-hit ability. This matters for what comes next: without it, a card that strikes three times would soak up three times as much benefit from the same gear as a card that strikes once, purely because of how it is built rather than by design. Recording the shape lets gear reward those cards evenly. Nothing reads these declarations yet, so no card behaves differently in play.
  • Add a pure, unconsumed deck-level static marginal-application share measurement for the five damage-effect gear stats (ROG-1598), plus a committed validation script comparing it against measured +N-stat damage deltas through the real combat engine.: No player-facing impact. This adds a pure, dev-only measurement function (not wired into any scorer, cache, or gameplay path) plus a committed validation script, both used to evaluate a future gear-valuation proxy before it is ever consumed.
  • Converge the deploy-kit toolchain pin to v0.25.0: No player-facing change. Moves the deploy tooling pin from v0.24.4 to v0.25.0 so rouge matches the rest of the fleet, which had drifted across four installed versions. The reason to converge rather than leave it alone is the clipd incident: drift left long enough eventually predates verify-pins itself, and a detector older than the drift it exists to catch reports nothing at all.
  • Docs reconciled against source by the new docs-steward agent: wiki act pages regenerated from the live zone seeds, boss/trait/reward pages moved onto the 0-10 rift-tier ladder, and stale paths, counts, and flag states corrected across engineering, design, and balance docs.: No gameplay change. The player wiki now describes the game that ships: the five act pages list the real zones, towns, and side branches from the zone seeds (they previously described Diablo II areas), boss and monster-trait pages use the 0-10 rift-tier ladder instead of the retired Normal/Nightmare/Hell/Uber tiers, and card, item, reward, and status pages carry corrected values (hand size, rune-drop weights, charm counts, potion healing). Engineering, design, and balance docs were reconciled the same way. Follow-up (ROG-1705): the class, strategy, and build wiki pages no longer carry May-2026 sim win-rate tables (live numbers come from the fleet canonical, see the fleet guide); the product is named Angel Snack consistently across the docs; the draw-flight and combat-audio design docs describe the shipped mechanism with current source anchors; and plan-style content (phasing ladders, a superseded fleet RFC, dated drill and validation notes) moved out of the repo docs to Cairn.
  • Add opt-in dropTopEndScarcityEnabled flag + drop-scarcity sim arm (default OFF) down-weighting top affix magnitude steps and trimming the rare-rarity weight on ordinary battle drops.: No player-facing change — the flag defaults OFF. Adds a sim-only lever (dropTopEndScarcityEnabled / drop-scarcity:on arm) that, when enabled, makes ordinary battle drops less likely to roll top-end affix magnitudes (top step 0.5x weight, second step 0.75x weight on qualifying bands) and trims the battle rare-rarity weight from 8% to 6%, so bosses stay the dense top-end gear channel and the gambler (ROG-1548) becomes the other one — pending A/B validation before any default flip.
  • pre-push now warns when UI-touching diffs lack a recent green e2e run: No player-facing change. The e2e runner now records a stamp after every full green lane, and pre-push checks it whenever a diff touches src/ui/, styles/, index.html, or boot/: if there is no green e2e run behind the change (missing, stale, or from an unrelated commit), the push prints a loud advisory naming the reason and pointing at npm run test:e2e:gate. Advisory-only for now — the ROG-1367 rot class, where the e2e lane silently went unexercised for weeks, can no longer happen without every push saying so.
  • Engine card preview can now model every play shape, not just a normal play from hand: Internal groundwork with no player-visible effect in this build. The engine's card preview previously could only replay a normal play from hand, which is why the combat view kept a second, independently-written preview calculation for Cycle, Adventure, kicker/overpay and discard/exhaust pile replays. The engine preview now accepts the caller's real play options and can find a card in any pile, so those shapes can be previewed from one place. Nothing calls the new capability yet — the duplicate calculation is removed in a later change, once every shape it covers has a home.
  • Sim: new equip-ablation:on arm (equipAblationEnabled, opt-in, sim-only) builds combat with equipment withheld while the pilot stays gear-aware — the channel-blind ground truth for gear's contribution (ROG-1696); both combat builders now share buildGearCombatInputs.: No player-facing change. Adds the equip-ablation:on sim arm (boot flag equipAblationEnabled, opt-in, default OFF, sim-only): the two combat-state builders construct combat with equipment withheld while the pilot keeps valuing and equipping gear, so the arm measures gear's causal contribution without enumerating its channels (ROG-1696, feeding ROG-1665's residual = ablationDelta − Σ attributed). The ablation decision is captured on the combat state (equipmentAblated) so the post-combat unstamp stays symmetric with the stamp. Both builders now share buildGearCombatInputs (src/run/run-equip-ablation.ts) instead of duplicating the item-bonus/armor/weapon lookup. Belt capacity is deliberately not ablated. Contract: docs/design/GEAR_SCALING_AND_AFFIXES.md §10.
  • Gear-gamble outcome distribution reworked into a variance-driven junk/decent/good/jackpot roll, plus a pilot EV/surplus-spend policy for balance sims (all opt-in, default OFF).: No player-facing change while gearGambleVarianceEnabled stays default OFF. When enabled (fleet A/B only, ROG-1553 Step 4), gear gambles resolve via four outcome buckets — junk (45%), decent, good (12%, richer rolls at a bumped tier), and a jackpot (fleet-tunable, default 3%) that lands either a decay-free unique shot or a maxed "gambler's-rare" item with four top-band affix lines. A companion sim-only pilot policy lets balance runs value and spend surplus gold on these gambles for experimentation.
  • Extracted an exact, RNG-free gambler outcome-distribution primitive and refactored the resolver to share its branch/threshold tables (no player-visible behavior change).: No player-facing change. Internal refactor only: the town gambler's card/refund/dust odds and their empty-pool fallbacks (including gold's rare-card-to-uncommon-card cascade) now come from one shared table consumed by both the live resolver and a new RNG-free odds primitive intended for a future sim tool — behavior is bit-identical.
  • Internal: comment and test-guard cleanup from the ROG-1610/1613 code review. No behaviour change.: No player-facing impact. The two touched source files changed only in comments: a load-order note that a file move had made false, and the removal of line-number pins and duplicated contract prose. The substantive part of this change is test-side -- a guard pinning that a card's declared proficiency agrees with the resolution combat actually uses, and moving an anti-duplication guard out of the sim lane into the default lane so it runs.
  • Internal: card scaling declarations and the gear-scaling contract module. No player-visible change.: Groundwork for the gear scaling rework (ROG-1600). Cards can now declare which attribute and damage element scale them, replacing the old arrangement where a card's skill tree doubled as its damage tag. Sorceress cards carry the first declarations, and an exhaustive test proves every one reproduces exactly what the game already does. Nothing reads these declarations yet, so no card, item or number behaves differently in play. This entry exists because the change touches content and type files, not because anything changed for the player.
  • Internal: one canonical table now defines every gear stat key. No behaviour change.: No player-facing impact yet. Groundwork for making gear effects visible: every skill line now has its own explicit stat key (Bow Skill Damage, Curses Skill Damage, and so on) defined in one table, and the four systems that consume stat keys -- the item-to-hero mapping, combat scaling, item valuation and the tooltip text -- all read from it. Nothing grants these keys yet, so no item, score or number changes. The visible payoff comes when items start declaring them directly, replacing the current weapon bonuses that the game applies but never shows the player.
  • Groundwork: gear can now carry a Strength damage stat, mirroring Intelligence and Dexterity.: Groundwork only. Six melee card types (combat, combat skills, masteries, martial arts, javelin, shape-shifting) scale with Strength, but no piece of gear could grant Strength the way gear grants Intelligence or Dexterity. That stat now exists and is wired through damage, scoring, and the character sheet. No item, affix, or charm grants it yet, so nothing changes in a run today — this is the foundation for Strength-flavoured rings and amulets.
  • Extracted the CSP-safe image error/load fallback listeners from main.ts into their own runtime module (main-media-fallback.ts); no behavior change.: Internal refactor only — no player-facing change. Moved the CSP-safe image error/load fallback listeners out of main.ts into their own module so main.ts stays under the file's line cap.
  • Sim: monster-scalar arm dimension for same-pin Normal-difficulty A/Bs (default behaviour unchanged).: Internal only: adds a sim experiment lever that scales enemy life and damage at Normal for same-pin difficulty A/Bs. No change to play.
  • Internal: cards can now declare more than one scaling element. No player-visible change.: More gear-scaling groundwork (ROG-1600). A card can now declare that more than one kind of gear scales it — several paladin abilities that strike and set the target alight are now both physical and fire, so either kind of gear will eventually reward them. Where two kinds both apply, the better one counts rather than both stacking. That keeps a dual-natured card roughly as strong as a single-natured one on the same gear, so the extra tag buys flexibility about how you build rather than raw power. Nothing reads these declarations yet, so no card behaves differently in play.
  • Widen the engine card-effects preview to cover mark/mercBuff/recover/summon buckets.: No player-visible change. This widens the engine's card-effects preview (previewCardEffects) to also report mercenary mark/attack-buff gains, cards recovered from Exhaust, and summon labels — the same buckets the UI's separate preview-text math already computes by hand. The UI still generates its own preview text for now; this step only makes the engine replay capable of covering it, so that hand-rolled math can be deleted as a follow-up without changing any output.
  • Removed the dead 'holy' proficiency row (no card ever resolved to it) and corrected four stale build-spec comments claiming int/dex scaling that doesn't apply; added a reachability guard so an unreachable proficiency key fails loudly.: Internal only, no player-facing change. Removed a dead "holy" proficiency-to-attribute mapping that no card has ever used (paladin holy cards resolve to the "offensive_auras"/ "defensive_auras" proficiency instead) and corrected four build-spec comments that incorrectly claimed int/dex scaling for paladin aura and assassin claw/fade cards. Weights are unchanged; added a test that fails by name if a future proficiency key is ever added without a card that actually uses it.
  • Gear-relevance tests now read the engine's real supported-stat list instead of keeping their own copy of it.: Internal only; nothing about the game changes. Two test fixtures kept a hand-written copy of the stats the build-relevance scorer supports, so adding a new stat left them silently out of date and failed the suite for a reason unrelated to what those tests actually check. They now read the real list from the engine, and assert it is populated first so they cannot pass by iterating an empty one.
  • Delete the dead weaponDamageBonus/getMeleeDamage gear channel (no src/ consumer) and its ablation-instrument plumbing (ROG-1701).: No player-facing change. Removed a dead gear channel found during the ROG-1696 equipment- ablation review: weaponDamageBonus (a second, equipment-only buildCombatBonuses read) was stamped on every combat state but its only consumer, getMeleeDamage, had no caller in src/. Deleted getMeleeDamage, the weaponDamageBonus param/state field, the extra buildCombatBonuses call in buildGearCombatInputs and the three other combat-state builders that duplicated it, and the corresponding .d.ts declarations.
  • Internal: the balance simulator derives weapon data from the game's own tables instead of a stale copy. No player-visible change.: The balance simulator kept its own list of which skills each weapon type supports, and that list had fallen behind the game's on every single weapon type — a mace supports nine skill lines and the simulator knew about two. It now reads the game's tables directly, so the two cannot disagree again. Several smaller copies of the same kind were removed alongside it, and a test that had quietly stopped checking anything was repaired. Nothing in the game changes — this only affects the offline tooling used to reason about balance.
  • Removed the unused, default-off BuildSpec-modulated gear relevance model (ROG-1565); the UI already scores through the global path, so this is a no-op for players.: Internal cleanup with no gameplay change. An experimental gear-rating model that would have adjusted the upgrade arrow and gear comparison to your build was built but never switched on. It had two flaws that made it unfit to enable — it kept a fraction of a stat's value even for builds that literally cannot use that stat, and it matched your deck to the closest authored build even when nothing actually matched, so an unusual deck was rated against someone else's plan. It has been removed rather than fixed; a replacement that reads your real deck is being designed. Gear ratings are unchanged.
  • Internal: admin-settings UI reads now go through a public ROUGE_ADMIN_SETTINGS facade instead of the app-engine module's private __-internal surface (no behavior change).: No player-facing impact. Internal refactor (ROG-1512): admin-settings UI code now reads the app-engine admin module through a public ROUGE_ADMIN_SETTINGS facade instead of reaching into its private __ROUGE_APP_ENGINE_ADMIN_SETTINGS internal surface.
  • Sim pilot gains an opt-in anchor-token valuation probe (anchor-token-pilot arm): inert mechanic tokens like the Hellforge Anvil are no longer scored as free kills.: No direct player-facing change. The balance sim's autopilot can now (behind a default-off probe) value boss mechanic tokens like Hephasto's Hellforge Anvil by their consequence instead of treating them as free kills, so future difficulty measurements of token-anchored boss fights better reflect how real players approach them.
  • No player-facing change: added a structural base-line lookup to the affix registry so the findability guard can tell rank-N upgrade lines apart from the base line they upgrade.: Internal only, no gameplay change: the item-affix registry now exposes a structural lookup from a rank-2/3/4 upgrade affix (e.g. "Runic") back to the base line it upgrades, so tooling can distinguish an upgrade's intentionally rarer drop rate from a base line that is genuinely too rare to find.
  • Armor resist affixes migrated to the unified affix registry (flag-gated, default OFF at the time).: Internal groundwork only, no player-facing change at the time: armor resist affixes (physical/fire/cold/lightning/poison) could now roll through the same unified affix registry that already rolled other magic/rare/set suffixes, behind a new default-OFF flag (rollUnifiedAffixesEnabled). With the flag off — the shipped default at the time — drop/gamble/anvil-reforge behavior stayed byte-identical to before this change. Superseded: the flag was retired and this registry path made unconditional in the ROG-1688 slice-3 cutover (see balance-rog-1688-affix-cutover.md), which is now the only armor-resist roll path.
  • Weapon typed-damage/effect affixes migrated to the unified affix registry (flag-gated, default OFF at the time).: Internal groundwork only, no player-facing change at the time: weapon typed-damage/effect affixes (per-family fire/cold/lightning/poison damage and burn/freeze/shock/slow/crushing effects) could now roll through the same unified affix registry that already rolled armor resists and other magic/rare/set suffixes, behind the existing default-OFF flag (rollUnifiedAffixesEnabled). With the flag off — the shipped default at the time — drop/gamble/anvil-reforge behavior stayed byte-identical to before this change. Rolled weapon affix lines started pricing into an item's gold value (previously invisible to pricing), but deliberately carried no bespoke power-score valuation weight — that stayed a balance decision for a later slice. Superseded: the flag and the legacy weapon roller were retired outright, and this registry path made unconditional, in the ROG-1688 slice-3 cutover (see balance-rog-1688-affix-cutover.md); the deliberate no-bespoke-weight decision still stands.
  • Add persistent, flag-gated itemLevel to equipment: stamped on every roll, read (max'd with base tier) only when itemLevelEnabled is on, so anvil reforge and belt-upgrade preserve an elevated tier instead of silently resetting it.: No player-visible change while itemLevelEnabled stays off (default): equipment now quietly carries the tier its affixes rolled at, but nothing reads it yet. When the flag is on, gear that gets a stronger-than-base roll (a gambled jackpot, an elevated affix override) keeps that strength through an Anvil Reforge or a belt in-place upgrade, instead of silently resetting to the item's plain base tier.
  • Persist a compact per-run economyCounters block on the seed-winnability history row (gear/mystery gamble applies, belt-capacity reward outcomes, gold, affix/gear telemetry).: No player-facing change. Sim/telemetry-only: adds a compact economyCounters block to the seed-winnability fleet history row so a balance A/B report can read gambles-per-run, belt-capacity reward outcomes, and end-of-run gold/gear telemetry per arm straight from Postgres, without ad hoc local instrumentation.
  • Internal: scaling declarations extended to all eight classes. No player-visible change.: Continues the gear scaling groundwork (ROG-1600). Every class's cards now declare which attribute and damage element scale them, rather than that being inferred from the skill tree a card happens to live in. Warlock's chaos cards declare that their damage element deliberately has no fixed value, because it rotates between fire, poison and magic as the fight goes on. Three card files were split in two to stay under the project's file-size limit; the cards themselves are unchanged. Nothing reads the new declarations yet, so no card, item or number behaves differently in play.
  • Internal: the charm/equipment scoring reconciliation constant now has one definition instead of three hand-copied ones, and a new deck proficiency-share measure is available to scoring work. No player-visible change; no scoring output moves.: No player-facing impact. Internal scoring plumbing only: the constant that reconciles charm power against equipment power was hand-written in three separate files with nothing checking they agreed, and every charm gold-value derivation multiplies through it. It now has one definition, guarded against re-duplication. The value is unchanged, so no item price, gear score, or recommendation moves.
  • Unified every scroll region on one scrollbar treatment; wiki, vendor and debug surfaces keep their own accent.: Scrollbars now look the same everywhere they appear. Lists that previously fell back to your operating system's default bar — the rift ladder, the campfire wakeup panel and the camp menu among them — are styled to match the rest of the game, and the surfaces that had drifted into slightly different widths and shades are back in line. The wiki, the vendor screens and the debug menu keep their own deliberate colour.
  • Internal: the balance simulator now values cards using their own scaling declarations. No player-visible change.: The balance simulator kept its own private list of which skills benefit from Intelligence, and that list had fallen out of step with the game. Barbarian's war-cry line has scaled with Intelligence for a while now, but the simulator never knew, so it undervalued every card in that lane when weighing up builds. The simulator now reads what each card says about itself instead of consulting a separate list, so the two cannot drift apart again. Nothing in the game changes — this only affects the tooling used to test balance offline.
  • Internal: one shared source for which stats apply to which cards, replacing a hand-copied table.: Internal refactor with no gameplay change. The rules deciding which gear stats boost which cards (Intelligence on spells, Dexterity on bows, and so on) lived inside the combat code, with a second hand-maintained copy elsewhere that had to be kept in sync by hand. Both now read one shared table, so the two can no longer disagree. Damage numbers are unchanged.
  • Internal: per-file type-escape-hatch (any/@ts-ignore/@ts-expect-error) ratchet added to pretest. No player-visible change.: No player-facing change. Adds scripts/check-type-escape-hatches.js (ROG-1508), a per-file ratchet over any/@ts-ignore/@ts-expect-error usage in src/, wired into pretest next to the existing CSS-token/ancestor-variant ratchets. Fails by name if a file's hatch count rises above its committed baseline (scripts/type-escape-baseline.json). The two files named in ROG-1508's initial slice (src/sim/sim-policy-clone.ts, src/quests/world-node-engine-opportunity-resolvers.ts) were audited and found to already use proper unknown-narrowing patterns with no hatches to burn down; the current repo-wide baseline is 0 hatches outside the documented eslint migration carve-out files.
  • scripts/ TypeScript is now type-checked in the default test gate: No player-facing change. npm run typecheck:scripts (the incremental scripts/*.ts/@ts-check on-ramp under tsconfig.scripts.json) now runs as part of pretest, so a broken scripts file fails npm test instead of only failing when someone remembers to run the manual command. Also fixed a pre-existing type error in scripts/lib/arena-record.js that this gate uncovered, and refactored build to share a checks:static alias with pretest instead of duplicating the check-script-load-order/check-test-lane-classification command list by hand.
  • Combat: a single damage effect can declare per-element typed shares that resolve as one landing (mechanism only; no card uses it yet).: Internal only: the combat engine can now resolve a single damage effect that carries several elements as one hit rather than several. No card uses it yet, so nothing in play changes.
  • Consolidated duplicated UI string helpers (title-case, humanize, escaping, icon markup) into render-utils.ts: No player-facing change. Internal cleanup: duplicated UI string helpers (title-case, humanize-label, HTML/attr escaping, icon markup) were consolidated onto the shared implementations in render-utils.ts (ROG-1509).
  • Split the oversized wiki-md-manifest.ts data module into per-class shards (ROG-1505); no wiki content or behavior changed.: No player-facing change. The in-game wiki's markdown content (class pages, build guides, and archive listings) was split out of a single 2,700+ effective-line wiki-md-manifest.ts into per-class shard modules composed back into the same registry the wiki loader reads. Content is unchanged.

Operations

  • Add a pre-push gate that requires every default-off feature flag to carry an owning ticket and a decide-by date (no player-facing change).: No player-facing change. Feature flags that ship default-off are now tracked in a committed registry, and a pre-push check fails by name if a default-off flag has no entry, or if an entry's decide-by date passes while it is still undecided. This closes a gap where a fully built and tested feature could sit unreachable behind a flag indefinitely while reading as live in the code, tests, and docs.
  • Normalize @andrewpopov kit pins to tagged releases (no version change): No player-facing change. The @andrewpopov/db-backup, @andrewpopov/release-kit, and @andrewpopov/eslint-config dependencies now pin the same commits via their release tags (github:andrewpopov/<kit>#vX.Y.Z) instead of raw commit-tarball URLs, so fleet tooling can read the pinned versions.
  • Add a committed pre-push gate now that CI is disabled: No player-facing change. GitHub Actions is disabled across the fleet, so nothing verified a push server-side. A committed .githooks/pre-push now runs this repo's own checks cheapest-first — patch-note hygiene, lint, build, tests — before a push leaves the machine, and is wired through the prepare script so a fresh clone picks it up on install rather than depending on local config. git push --no-verify remains the deliberate escape hatch for a work-in-progress branch.
  • The pre-push gate now verifies that pinned dependencies match what is actually installed, and no longer leaks GIT_DIR into the test suite.: No player-facing change. rouge consumes three github:-pinned dependencies and had no pin check in its pre-push gate. npm resolves a github:owner/repo#tag dependency to a commit in the lockfile and then treats that entry as satisfying any later tag, so both npm install and npm ci no-op on a moved pin and exit 0 — the manifest can read one version while node_modules holds another, with nothing reporting the disagreement. deploy-kit verify-pins now runs as the first real check after install. The hook also unsets GIT_DIR and friends. Git exports them to hooks, so any git -C <somewhere> in a child process silently operates on this repo instead of the directory it names — and this repo has 17 files that invoke git.
  • Add a pre-push check that every sim A/B arm actually reaches the game runtime (no player-facing change).: No player-facing change. Balance experiments compare a feature on against a baseline, which only works if the feature actually switches on inside the simulated run. One experiment arm silently did not, so 450 simulated runs compared a baseline against itself and produced a confident-looking "no difference" result. A pre-push check now enumerates every experiment arm and fails by name if any of them cannot reach the runtime, so a broken arm is caught at commit time rather than after days of compute have been spent measuring nothing.

Angel Snack 0.1.0-alpha.17 Patch Notes

Release date: 2026-08-09

Stage: alpha

Package version: 0.1.0-alpha.17

These notes are gathered from the release fragments in docs/patch-notes/unreleased/.

Gameplay

  • World-map waypoints now track per-zone activation state, with the town return gated on it (currently always reachable).: Zones on the world map now remember whether their waypoint has been activated (any zone you've entered lights up with a small waypoint marker), and the town return button now reflects that state directly. Nothing about how you play changes today — the town return stays available exactly as before — but this lays the groundwork for a future difficulty option that ties town access to how many waypoints you've found.

Balance

  • Flag-gated Quartermaster belt-capacity purchase (candidate lever, default off): Internal candidate lever, disabled by default (beltCapacityShopEnabled). When enabled, the Quartermaster offers up to 3 one-time belt-capacity upgrades (act 2/3/4, 150/400/900 gold), each permanently raising the potion belt by 1 charge. Also fixes a latent bug where a rare exploration-event belt-capacity bonus could push belt capacity past its intended ceiling with no cap at all.
  • Runs now start with a full potion belt (2 charges) before ascension penalties: Runs now start with a full potion belt (2 charges) instead of 1, before the ascension potion-charge penalty is subtracted — so ascension 3+ now starts with 1 charge instead of 0. Promoted from an internal candidate lever via fleet A/B testing: act-1 town stops -45% at ascension 6, winnability concordant/within noise.
  • Sim telemetry rider records healing-belt potion split by target, mercenary alive-at-start/end, and town return-trigger context — observation-only, no scoring impact.: No player-facing change. Extends the sim/fleet telemetry pipeline (ROG-1468 hero-resource ledger) with a few more observation-only signals: how many healing-belt potions each combat spent on the hero vs. the mercenary and how much life they actually delivered, whether the mercenary was alive at the start/end of a fight, and why a run stopped at town (empty belt, low hero HP, dead mercenary, or a planned act transition). Pure telemetry — none of it feeds scoring, decisions, or the sim's RNG.
  • Flag-gated pilot upgrade (mercReviveValueModelEnabled, default OFF): merc-revive decisions fall out of the run scorer's own counterfactual instead of a hardcoded rule.: Autoplay and the sim pilot now weigh a fallen mercenary's actual value to the build when deciding whether to return to town and pay for a revive, instead of always treating a dead merc as an emergency. A low-value merc may stay dead; a strong on-build merc is revived as before. Off by default behind the mercReviveValueModelEnabled flag while the change is validated in fleet A/B runs — no player-visible behavior changes until promotion.
  • Balance sims now measure a fair 'competent' pilot instead of silently defaulting to the RNG-clairvoyant oracle; sim-derived balance numbers may shift accordingly.: No direct in-game change. The balance simulators that inform tuning decisions previously modeled a pilot with perfect RNG foresight, which overstated how winnable some content is; they now model a fair competent pilot, so future balance adjustments will be calibrated against more realistic play.

UI

  • Make Account Hall collections searchable and filterable, improve desktop text legibility, and expand class Trophy details.: Charms and Achievements are now quick to search and filter without losing your place. Account Hall text stays readable on desktop, while Trophy class portraits use the available space and show each class's unlock state, archived runs, and best depth.
  • Card frames fit their text: long titles no longer clip, spellbook Base/Upgrade toggles sit below the card instead of covering rules text, wordy cards fit without scrolling, the combat draw-pile button opens the decklist again, and camp menu items announce their names.: Cards now fit their own text: long names like Crushing Blow no longer clip at the top of the frame, the spellbook's Base/Upgrade switch moved below each card so it stops covering rule text, and wordy cards fit their rules without a hidden scrollbar. The draw-pile button in combat opens your decklist again, and the camp menu's entries announce their names to screen readers.
  • The charter that opens every run is now set at a readable size in both desktop and landscape, and the waking screen no longer shows the same scroll twice.: The blood-sealed charter carries the whole premise of the game, and it was the least readable text in it — roughly 12px of italic script on mottled parchment, in every screen size. It is now set at a readable size and upright, with the italic kept for the closing oath, and one paragraph trimmed so it still fits the scroll without scrolling. The waking screen has been quieted to match: it was showing the sealed scroll twice — once as a picture, once as the thing you actually click — so the duplicate is gone, the prose is left-aligned instead of centred, and the text now sits centred on the screen rather than beside an empty column.
  • More internal styling cleanup: combat effects, enemy inspect, inventory, and animation colors now reference shared design tokens. No visible changes intended.: More under-the-hood styling cleanup: combat effect flashes, enemy-inspect glows, inventory accents, and animation colors now come from the shared design tokens. Every substitution is value-identical, so nothing should look different; report anything that does.
  • Internal styling cleanup continues: affliction, impact-tint, and inventory accent colors are now named design tokens. No visible changes intended.: More internal styling cleanup: affliction glows, per-element impact tints, and various inventory accent colors are now named design tokens. Every value is identical to before, so nothing should look different; report anything that does.
  • Internal design-system cleanup: text sizes and reward-screen colors now come from shared tokens. No visible changes intended.: Under-the-hood styling cleanup: text sizes and the reward screen's color palettes now come from the shared design tokens. Nothing should look different; report anything that does.
  • Complete the desktop and tablet rendered-text floor across character select, town, rewards, merchants, and combat.: Small labels, card rules, merchant details, and decision text now remain readable across supported desktop and tablet layouts without overflowing their controls.
  • Front door: the sign-in and guest controls now sit with the account note in the left column instead of floating over the art, the Daily Challenge label reads consistently, and the footer tagline is easier to read. Keyboard focus outlines added to search and filter inputs across the spellbook, wiki, inventory, and admin screens.: On the title screen, sign-in and guest-play controls moved into the left column beside the account note, so every decision lives in one place and nothing floats over the cover art (phone landscape keeps its corner layout). The Daily Challenge button announces itself consistently, and the bottom tagline is no longer faded below readability. Keyboard players get visible focus outlines on the spellbook search, wiki search, inventory attribute rows, and admin filters.
  • The game menu now carries description subtext only where it tells you something the label cannot — live state, a consequence, or an unfamiliar name.: Most menu entries explained themselves twice — "Report Bug / Suggestion" sat above "Send feedback to the team.", and "Return To Hall" above "Back out of the draft and reopen the account hall." The extra line said nothing the label hadn't, and the uneven mix of one- and two-line rows made the Tools section read as unfinished. Subtext now survives only where it tells you something the label cannot: what abandoning a ranked run costs you, how many skill points you have waiting, the update actually being downloaded, and what the Hero Hall is if you have not opened it yet.
  • After you have been through the opening once, later runs start at the charter instead of replaying the waking scene and the camp introduction.: The opening — waking by the campfire, reading the charter, and being shown around camp — replayed in full every single time you started a run, in a game whose whole loop is starting runs. Your first expedition still gets all of it. After you have been through it once, later runs open on the charter and go straight to the charm and the camp itself. Nothing is skippable and nothing is hidden behind a button: the first time is simply the first time, and after that the game stops re-introducing itself.
  • Expedition setup now states the selected rift depth once instead of five times, and the Rifts ladder no longer prints a band header that only restates its sole rung.: The expedition setup screen used to say the same thing five ways — a "Rift Depth" heading, the tier name, its modifier line, and then a second "Current Hunt" card repeating the tier name and rewording the modifier. The repetition flattened the screen's hierarchy without adding a single fact. Setup now states your rift depth once: the tier, what it does to the run, and whether the next one is unlocked. The Rifts ladder likewise drops the "Normal" band header that sat directly above its only rung, also named Normal.
  • Readability and accessibility pass: card rule text is larger, card art shows a loading shimmer instead of a blank well, world-map encounter badges no longer clip, boss-panel text is higher contrast, and class select, rewards, and enemy targeting now expose proper accessible names.: Card rule text is one step larger everywhere cards render, so hand cards are readable without the tooltip. Card art wells show a subtle loading shimmer while artwork streams in instead of a flat black pane. On the world map, zone encounter badges wrap instead of clipping mid-word, and the act-boss panel text is brighter against its dark backdrop. Screen-reader support improved: class selection, the Begin Hunt button, reward charm selection, and enemy targeting all announce real names now.

Fixes

  • Made the iPhone 16 Pro first-run intro fit its safe area and restored reliable touch targets through camp arrival.: New heroes on iPhone can now rotate into landscape and tap cleanly through the campfire scroll, blood-sealed charter, and opening reward without controls slipping under the notch or home indicator.
  • Menu-screen cleanup — charm rewards show their full text, targeted enemies stop showing their name twice, locked bloodlines stop lighting up, and the camp menu uses the room it has.: A pass over the menus fixed a batch of small things that were quietly getting in the way. Charm reward cards were cutting off their own Select button and the line telling you how much pouch space the charm needs — both are visible now. A targeted enemy printed its name twice on top of its health bar. Locked bloodlines on the hero screen lit up when you moused over them, as though you could pick them. The camp menu squeezed itself into two-thirds of the window and pushed Abandon Run below a scrollbar, the hero and expedition screens showed a scrollbar for content that already fit, the tier list repeated the same unlock sentence on all ten rows, and the bug-report button sat on top of the guest-entry button on the title screen. The Encampment Ledger also now properly takes over from the fight behind it, so tabbing through it can no longer land on the combat underneath.

Tech

  • Internal tooling: generated/src orphan pruning + runtime-window declaration guard (ROG-1513, ROG-1511): No player-facing changes. Build tooling now prunes stale compiled modules for deleted source files (so dead runtime code can't be silently loaded), and a new pretest guard verifies every runtime window export has a matching type declaration.
  • Add a dev-facing component gallery at ?gallery=1 (ROG-1527) — every design-system primitive and card builder rendered in isolation — plus the e2e guard that keeps it honest.: No player-facing changes. Adds a component gallery at ?gallery=1 (ROG-1527): the design system's container primitives, the full button recipe matrix, all eight framed-choice-card presets, merchant-card-v2 across its states, and the hero profile card — all rendered with the real shipped CSS and no run state. main.ts branches to it before any boot side effect, so it loads no seeds, builds no AppState, writes no persistence, and installs no [data-action] delegate; boot/canvas-fit.js bails out so the fixed game canvas doesn't letterbox a long reference page. Unlisted: reachable only by the query param, exposing static fixtures with no debug API and no user data. Also adds tests/e2e/component-gallery.test.js, which asserts boot isolation, full catalog coverage at desktop and phone-portrait viewports, zero console/page/resource errors, and zero horizontal overflow — plus a CSS canary that checks named per-primitive properties (.surface-card's ember border, .panel's border and radius, .primary-btn's border, the .btn--sm/md/lg 28/38/48px min-height scale) rather than a generic "differs from unstyled" comparison, so deleting a primitive's rule fails the lane by primitive name.
  • Internal: split the deck-card frame/body styles out of the cost-rail stylesheet (no visual change): No player-facing change. decklist-overlay-cost-rail.css had grown past the 500-effective-line split threshold and had stopped matching its own name, so the card frame and body rules (title ribbon, name, alt actions, art, type line, rules band) moved to decklist-overlay-card-body.css. Rules were relocated, not edited — 325 declarations and 62 selector blocks before and after — and the new stylesheet loads immediately after the original so the cascade is unchanged.
  • Rouge's CSS design system now syncs to claude.ai/design, so design work starts from the real shipped stylesheets and tokens.: No in-game change. Rouge's design system — all 156 stylesheets, the token scale, and the primitive class vocabulary — is now published to the Claude Design workspace, so mockups and new screen designs are built from the real shipped CSS rather than an approximation of it. That means what gets designed already matches what the game actually renders.
  • Flag-gated deck-cap taper for regular-clear card drafts (default off; fleet A/B pending): Groundwork for deck-size pacing on regular battle rewards: a new boot flag (off by default) makes the after-battle card draft narrow as your deck grows — full 3-card drafts while your deck is lean, 2 cards near the soft cap, and non-card rewards plus Banked Spoils once the deck is full. No player-visible change yet; the flag stays off pending a fleet balance A/B.
  • Flag-gated build-attuned shrine choices (default off; fleet A/B pending): Added an experimental, flag-gated "Attune" option to the five shrine exploration events (Shrine of War, Plenty, Vitality, Shadow, and the Fallen). When a run has committed hard to one build path, an attuned shrine can offer a real-cost choice — HP or gold — that grants a charm matched to that build instead of the usual generic reward. The feature ships off by default while it goes through a fleet A/B; no visible change for players until it's promoted.

Operations

  • Docs audit: superseded push-fleet design docs and the release-assistant plan moved to the Cairn archive; stale Kira references updated to Cairn.: No player-facing changes. Internal documentation housekeeping: superseded push-fleet design docs and the release-assistant plan were archived to Cairn, and stale Kira references were updated to Cairn.
  • Internal: split run-factory into focused modules so the file has room to change again.: No player-facing changes. Internal housekeeping: the run-factory module had grown to the exact line limit the project enforces, which meant the next change to it would have broken the build. Two self-contained pieces — class-tree access and route normalization — moved into their own files, leaving room to work in again. Behaviour is unchanged.

Angel Snack 0.1.0-alpha.16 Patch Notes

Release date: 2026-08-06

Stage: alpha

Package version: 0.1.0-alpha.16

These notes are gathered from the release fragments in docs/patch-notes/unreleased/.

Gameplay

  • Spike: flag-gated second fixed canvas for mobile-landscape (default off): No player-facing impact — spike behind ?mobilecanvas=1, default off. Adds a second fixed-canvas mechanism for mobile-landscape at a 667x375 reference, reusing the existing CSS-zoom approach, for future evaluation.
  • On phones, tapping an enemy now plays the card you have lifted: On phones, lifting a card and then tapping an enemy now plays that card at them, instead of only selecting the enemy and making you tap the card a second time. Tapping an ally casts on the ally the same way, and cards that need several targets show your progress as you pick them. Lifting a different card swaps which one is ready, tapping empty ground puts it back, and rotating the phone quietly puts the card down rather than leaving it half-played.
  • Zones now field authored encounter variants with weighted picks and a no-repeat window — fights vary run to run.: Zones can now serve alternate encounter layouts — a role-rotated patrol, an extra crossfire ambush, or a rotated swarm — alongside the classic base fight, picked with weighted odds and a no-repeat window so you don't see the same fight twice in a row. In sim testing this cut the same-encounter repeat rate from about 48% to about 17% and nudged run completion up slightly, with no increase in per-encounter losses.

Balance

  • Act-1 monsters (Dark Stalker, Hungry Dead/Zombie/Ghoul, Skeleton, Bone Mage) and four nest/sarcophagus spawners now have distinct mechanics instead of sharing one generic attack template.: Dark Stalkers now strike twice for reduced damage each (swift); Hungry Dead, Zombies, and Ghouls release a poison cloud on death; Skeletons explode for a portion of their max life when killed; Bone Mages raise fresh Skeletons on a cadence instead of just healing; and the Blood Hawk Nest, Foul Crow Nest, Mummy Sarcophagus, and Black Vulture Nest now spawn their matching creature on a cadence, giving players a "kill the spawner" objective instead of a passive heal-bot.
  • Act 2-3 monster variety pass (Blunderbore/Embalmed/Preserved Dead/Wailing Beast/Horror Mage/Flesh Hunter/Gloombat/Drowned Carcass) plus a second generic-brute template and act-scaled thorns/regeneration.: Several act-2/3 generic monsters (Blunderbore, Embalmed, Preserved Dead, Wailing Beast, Horror Mage, Flesh Hunter, Gloombat, Drowned Carcass) now fight with a distinct identity instead of a generic role kit — Blunderbore/Wailing Beast telegraph a big smash and go frenzied at low HP, Embalmed/Preserved Dead regenerate, Horror Mage curses before its payoff hit, and Flesh Hunter/Gloombat/Drowned Carcass carry a poison or on-death spawn. Roughly half of the generic brutes across every act now alternate a big telegraphed attack-all smash on a cooldown instead of the standard guard/sunder pattern. Thorns and Regeneration now scale up with the act you're in, so both stay noticeable against late-game life totals instead of chipping for a flat, invisible 2.
  • Act 4 mainline reshaped to 3/4/4 (Chained Bastion shortened): validated fix for the potion-attrition wall that ended many necromancer/amazon/sorceress runs.: Act 4's mainline route is reshaped from an even 4/4/3 fight split to 3/4/4: the Chained Bastion gauntlet drops from 4 fights to 3, and Black Gate picks up one more fight (Demon Forge stays at 4). Chained Bastion had been outsized potion-attrition pressure that ended runs early, especially for necromancer, sorceress, and amazon — this shortens that gauntlet and moves the extra fight to a spot where it doesn't compound the same way.
  • Add an opt-in act4MidZoneShape route flag (3-5 / 3-4-4 act-4 fight redistribution) for fleet A/B of the Chained Bastion attrition wall; default routing unchanged.: No player-facing change yet: act 4 keeps its shipped 4/4/3 zone fight counts. This adds an opt-in experimental flag the balance sim fleet uses to A/B two act-4 fight redistributions (Chained Bastion 3 / Demon Forge 5, or 3/4/4 including Black Gate) aimed at the Chained Bastion potion-attrition wall that currently ends many necromancer, amazon, and sorceress runs. If an arm wins validation, a follow-up change will flip the default and carry its own note.
  • Act-5 monsters (Imp, Snow Yeti, Prowling Dead/Unholy Corpse/Rot Walker, Reanimated Horde, Hell Witch, Vaught Bone Mage, Ancient Barbarian trio) now have distinct mechanics instead of sharing one generic attack template.: Imp now falls back and snipes your weakest party member instead of standing still; Snow Yeti and one of the Ancient Barbarians pile on chill; Prowling Dead, Unholy Corpse, and Rot Walker release a poison cloud on death; Reanimated Horde bursts into a fresh Grotesque Spawn when killed; Hell Witch curses you with a Blood Mana hex before her Blood Star; Vaught Bone Mage raises fresh Skeletons on a cadence instead of just healing; and the Ancient Barbarian trio now reads as three distinct fighters — one buffs its allies, one sunders and corpse-explodes, one chills — instead of three copies of the same raider.
  • Alt-raider slot fallback is now role-honest: a single-raider zone pool only promotes an unclaimed raider/brute member into the second raider slot (Star Archive patrol now doubles Hell Clan instead of a Specter; Worm Tunnels patrol fields a Scarab instead of a Sand Maggot).: Zone patrol packs with only one true raider in their pool no longer press a ranged or support monster into the second raider slot, where it inherited melee scaling and a raider attack pattern its own kit never earned. The slot now takes an unclaimed raider or brute from the pool, or doubles the zone's raider when no melee candidate exists. Two encounters change: Star Archive's patrol doubles Hell Clan instead of fielding a Specter, and Worm Tunnels' patrol fields a Scarab instead of a Sand Maggot.
  • Crit Mark and Focused Strike now scale as Javelin cards, matching their pool-siblings — the dead spear tag was blocking weapon scaling entirely.: Amazon's Crit Mark and Focused Strike were tagged with a weapon proficiency ("spear") that matches no weapon table in the game, so they never benefited from a wielded weapon's bonus damage, effects, or attribute scaling — unlike their Javelin-tagged pool-siblings, which do. Both cards are now tagged Javelin, so they scale correctly with a wielded Spear or Javelin the same way the rest of the Mark payoff line already does. A small, targeted buff; no other card or build is affected.
  • Enemy attack-all abilities now also splash onto alive, non-invulnerable summons alongside the hero and mercenary.: Enemy attack-all abilities now hit your summons too, not just you and your mercenary — every alive, non-invulnerable summon takes the same damage as the rest of the party.
  • Sim deep/strong pilot no longer turtles into defeats vs ramping bosses: calm states now use greedy scoring plus the default pilot's pass-lookahead and close-decision assists (production default pilot unchanged).: Internal balance-measurement change with no direct player-facing gameplay impact: the simulator's "strong" reference pilot (used to judge how close real-game AI decisions are to optimal) no longer throws away winnable ramping-boss fights by turtling. Balance verdicts calibrated against it become more trustworthy; the shipped in-game pilot behaves exactly as before.
  • Enemies can now target hero summons: single-target attacks aimed at the hero can be intercepted by an alive summon instead, capped at 2 intercepts per round.: Enemies can now redirect single-target attacks aimed at you onto your summons instead — an alive summon can take the hit in your place, up to 2 intercepts per round, giving summon-heavy builds a real defensive lifeline.
  • Two act-4 encounters (Ashen Throne, Demon Forge) no longer field a mislabeled melee-slot enemy in their alt-raider slot.: In Demon Forge patrols, ambushes, and swarms, the pack's second raider-slot enemy no longer swaps in a Damned — a ranged unit that was inheriting melee scaling and the raider intent cycle it never earned. It now duplicates a real melee threat (Dark Familiar) instead, so the pack's real threat profile matches what it visibly telegraphs.
  • Buffed the Wardens-exclusive Sigil of the Ancients (grand charm) so its computed power clears the boss floor, keeping its authored boss tier honest with the drop-bucket formula.: The Wardens' Sigil of the Ancients grand charm has been buffed so its power matches its boss-tier drop rating. If you farm bosses for it, the charm you get now earns its slot.
  • Sim 'strong' pilot profile now prices kill progress more aggressively vs ramping bosses (kill-urgency terminal-eval weight 5), fixing deep-beam turtling into defeat; sim-only, no shipped-pilot change.: No player-facing gameplay change. The balance sim's "Strong" pilot (the fair whole-run comparator used by the optimality scorecard) now weighs finishing enemies off more heavily in its lookahead, fixing a bug where it would turtle into pure defense against ramping bosses like the Siege Tyrant and lose fights the standard pilot wins. Balance readings that cite the Strong comparator become more trustworthy on ramping-boss encounters.
  • Bloodspark, Frostbite and cleanse potions now hit the enemy the AI actually chose, instead of defaulting to the first living target.: Throwable utility potions — Bloodspark Vial, Frostbite Flask, and the scenario cleanse brews — are aimed at a specific enemy. The simulated pilot weighed each possible target when deciding to use one, but every path that actually resolved the potion ignored that choice and hit whichever enemy happened to be selected, usually the first one still standing. Choosing one target and hitting another is now fixed end to end, so these potions land where they were aimed. Throwing one at an enemy that is already dead is refused outright rather than silently redirected, and the potion is not consumed.
  • The deck-q75 underplay criterion (ROG-1466) is now the default sim measurement mode — no player-facing gameplay change.: No player-facing change. ROG-1466's underplay-gate criterion (deck-q75 score bar + fatal-encounter-scoped gate) is now the DEFAULT internal measurement mode for the balance simulator, promoted after fleet validation (300 paired seeds, both discordance directions certified). It is purely a measurement annotation — computeRunValidity never changes which action the simulated pilot chooses, only how a completed run's validity is judged for balance telemetry. The pre-promotion whole-act absolute-8 gate remains available as an explicit opt-out (underplay-criterion:legacy-v0). Nothing in gameplay, content, or the UI behaves differently.
  • Zone enemy rosters deepened: 30 zones gain act-native support/ranged/brute reinforcements, so patrols/ambushes/swarms field honest role compositions instead of repeats.: 30 zones across all five acts had thin, shallow per-role monster pools that left patrols, ambushes, and swarms repeating the same one or two enemies for a given role. Each of those zones now draws from a wider, act-native pool of support, ranged, and brute reinforcements already used elsewhere in the same act, so encounters built from them field a more varied, believable enemy lineup without introducing any new monster.
  • Fixed the Chained Bastion attrition wall — act 4's mid-zone encounter bonus no longer piles entirely onto one zone.: Short acts (four mainline zones, like act 4) used to give their one mid-zone slot the full bonus while its neighbors stayed capped — Chained Bastion fielded 5 encounters against Demon Forge's 3, a 1.65x fight dose that made that stretch a genuine ascension attrition wall. The bonus now spreads across the collapsed zone and its neighbor instead, so both carry 4. The act's total encounter count is unchanged; the extra fights just land where players can absorb them instead of stacking on one gate. Fleet-validated ascension A/B: asc:6 Chained Bastion run-loss fell 29.4% -> 14.6% and run completion rose 57.3% -> 71.9%, with no death relocation onto the neighboring zones or the act boss.
  • Fixed a pack-building bug that gave Summit Citadel patrols two heavy casters instead of one, and made that mountain far deadlier than the boss behind it.: Zone encounter packs are built from role slots — two melee, one ranged, one support — but a monster whose family always fights at range could be dropped into the second melee slot and quietly stay ranged. That gave the pack two ranged attackers instead of one, and both also benefited from the pack's backline guard. Summit Citadel patrols were where this landed hardest: two copies of the same high-damage caster firing on the same turn, taking about a fifth of your health in one hit. That one spot on the mountain was responsible for roughly two thirds of all late-game deaths — several times deadlier than the act boss guarding the way past it. Patrols there now field the melee unit the pack was designed around. Necromancer and assassin runs benefit most, since they had the least margin to absorb the burst; classes that were already clearing the mountain comfortably are barely affected. No monster's stats were changed — the pack simply gets the fighter it was supposed to have.

Content

  • Every card now has an illustration: 30 cards that shipped ahead of art get bespoke gpt-image art, and Crown Stone Elder Ancient gets its proper sprite instead of a placeholder silhouette: The last 30 cards that shipped ahead of art — the amazon vigil pair, assassin foretell/primed sets, the barbarian warcry and stance batches, paladin devotion cards, the warlock ledger suite, and a few singletons — now show bespoke illustrations instead of icon fallbacks, so every card in the game (upgrades included) has real art. The Act 5 Crown Stone Elder Ancient also displays its proper greater-mummy sprite instead of a generic silhouette.
  • New 'Ambush (B)' zone encounter variant: zones with a second ranged monster in their pool now field it, adding 20 encounter variants (and returning monsters like the Specter to the Star Archive).: Zones now have a fourth encounter variant, Ambush (B): when a zone's monster pool carries a second ranged creature, it leads the ambush instead of the usual pick. Twenty zones (concentrated in acts 1–3 and 5) gained the variant, and several monsters that never appeared in play — like the Specter haunting the Star Archive — now show up in these packs.

UI

  • Combat figures modestly bigger at phone landscape, standing on a lit ground line with contact shadows, and the tall-phone stage no longer leaves dead space above the tray: Combat on phones in landscape looks more grounded: hero and enemy figures are modestly bigger, stand on a lit ground line with soft contact shadows instead of floating, and on tall phones the stage now uses the space above the action tray instead of leaving it dead. Visual only — no gameplay change.
  • Canvas particle effects are now on by default in combat, with richer burst counts; add ?canvasfx=0 to the URL to opt back into DOM particles: Combat particle effects (blood, souls, embers, frost, sparks, reward bursts) now render on the canvas backend by default — the same eased, palette-shaped particles as before, but with roughly triple the particles per burst at a fraction of the old per-element cost. If anything looks off on your device, add ?canvasfx=0 to the URL once to switch back to the previous DOM particles; the choice persists.
  • Combat card rules text no longer overlaps the type band or clips silently at the reward screen and lifted hand-card inspector.: Fixed a bug (ROG-1443) where a card's full rules text could clip mid-sentence on the reward-screen card choice, and — worse — overlap the card's own type band (e.g. "Attack") on the lifted hand-card inspector in mobile-landscape combat. Long-text cards (multiple conditional effects) now scroll within their own rules region instead of spilling into neighboring parts of the card frame or getting silently cut off by an ancestor container.
  • Character select roster names no longer truncate at phone landscape, and the help button no longer covers the last class row: On phone landscape, the class roster rail is wider so every class name (Barbarian, Necromancer, Sorceress) renders without truncation, and the floating help button no longer covers the last class in the list — the rail reserves scroll room beneath it.
  • Run-start charm draft's primary effect no longer clips on the shortest landscape screens (568x320): On the shortest landscape phones (568x320), the run-start charm draft card compacts its frame padding, eyebrow row, and name so the charm's primary effect text fits fully inside the card instead of clipping at the bottom.
  • Mobile-landscape combat: de-boxed targeted enemy glow, clustered per-enemy intent/traits, right-edge inset, wider target-name readout, and inspector-dock collapses when empty (frees room for 4-5 enemy lane).: On phone-landscape combat, the targeted enemy now reads as a glowing figure with a ground-ring instead of a boxed outline, each enemy's intent icon and status/trait glyphs cluster tightly over its own figure instead of running together at 4-5 enemies, the enemy row keeps a small gap from the screen's right edge, targeted-enemy names no longer truncate mid-word, and the hand-inspector panel collapses out of the way when no card is lifted so the enemy row gets more room to breathe.
  • Combat text on mobile landscape now clears the 12px legibility floor (HP readouts, enemy names, card cost/name, pile labels, Field Log entries), the Field Log toggle moved into the system menu cluster, the Autopilot HUD trigger no longer renders off-screen, and five layout defects (locked front-door CTA overflow, Arena's duplicate setup docket, narrow-viewport hand-card tap targets) are fixed.: On phone landscape, combat text that used to render below a comfortable reading size — HP numbers, enemy names, card costs and titles, discard/exhaust counts, and Field Log entries — now renders at a legible size across every supported phone width. The Field Log button moved next to the other menu icons in the top-right corner so it's no longer hidden behind them, the Autopilot HUD's status button no longer renders off the bottom of the screen, the Battle Arena setup screen no longer shows a duplicate control block, the locked sign-in screen's button no longer pushes the sign-in link off screen, and hand cards on the smallest supported phone size are reliably tappable.
  • Phone landscape: lighter intent chips, allies and enemies share one ground line, smaller hand cards (tap once to preview full card): On phone landscape, enemy intent chips are lighter and flatter, allies and enemies now stand on the same ground line instead of two different ones, and resting hand cards are smaller so the battlefield gets more room — tap a card once to see the full-size preview.
  • Recompose the desktop-canvas combat standoff around the canvas midline and fix a tablet-responsive 5-enemy row overflow: On the desktop game window, your party and the enemy formation now read as a centered standoff instead of a layout that hugged the left edge with empty space on the right — hero, mercenary, and enemies are balanced around the middle of the screen the way they are in other Slay-the-Spire-style card battlers, and the "1/5"-style target-pager arrows stay clear of the enemies instead of crowding the right edge. On mid-size windows (the "tablet" responsive layout, roughly under 960px wide), a 5-enemy fight no longer clips the last enemy off the edge of the formation row.
  • Desktop combat figures (hero, mercs, enemies, minions) are ~1.45x larger for STS-style stage presence: On desktop, your hero, mercenary, enemies, and summons now stand ~1.45x taller on the combat stage, giving fights the figure presence of the phone-landscape shell instead of small sprites lost in the backdrop. Boss and miniboss framing scales up to match, and full 5-enemy formations still fit the stage.
  • Desktop combat hand floats over a full-bleed battlefield — STS-style centered fan, corner piles, larger energy orb: Desktop combat no longer reserves an opaque bottom tray: the battlefield art now runs the full height of the screen, and your hand floats over it on a soft scrim as a centered fan of larger cards. The draw pile shrinks to a compact bottom-left stack, discard/exhaust to a bottom-right cluster under the End Turn button, and the energy orb grows to a proper Spire-style orb beside the fan. Visual only — cards, piles, and buttons all work exactly as before.
  • Raised small decision-relevant text to a readable floor on the desktop canvas: On desktop, several small but decision-relevant labels — charm-effect trigger lines, merc/vendor hire stats and eyebrows, town NPC role tags, world-map waypoint labels/progress and "you are here" chips, and the run top bar's level readout — rendered as small as ~7-9px effective size at common window sizes, making them hard to read while deciding. These now hold a consistent 12px design-px floor on desktop, matching the mobile-landscape legibility pass from ROG-1373.
  • Expedition setup gets the full-bleed backdrop and framed treatment of its sibling screens: The expedition screen — where you draft a new run or resume a saved one — now opens onto a full atmospheric backdrop instead of a small card floating on empty space, matching the framed presentation of the rest of the hall.
  • Fixed inventory overlay phone-landscape layout: compact single-row tab strip, scrollable section content, and removed a duplicate hover-preview label that painted ghost text over the Attributes list.: The Inventory overlay on a phone held sideways (landscape) no longer opens into the portrait layout. The five section tabs (Loadout, Pack Contents, Active Relics, Skill Tree, Attributes) now sit in one compact, scrollable row across the top instead of stacking as five full-width buttons that used to eat roughly half the screen. The rest of the overlay now gets that space back, so gear, pack contents, and the skill tree/attribute lists fit or scroll cleanly instead of being squeezed into a clipped sliver at the bottom. We also fixed a bug where the Attributes list could show overlapping "ghost" text: a hover-style info card meant for desktop was popping up over neighboring content on tap; it's now suppressed in this compact landscape layout since its information is already shown inline on each row.
  • Mobile-landscape combat: hand cards are compact thumbnails; tap once to see a card full-size, tap again to play it.: On phones in landscape combat, hand cards now show as small recognition thumbnails (art, cost, and name) instead of cramped full-size cards you couldn't read. Tap a card once to see it full-size in a dock on the right side of the board — its damage numbers update live as you change target — then tap it again to play it. Everything else (drag-to-play, keyboard shortcuts, desktop and tablet layouts) is unchanged.
  • Enemy and ally intent chips are compact at phone landscape (smaller icon, tighter pill) so monsters read as the subject: Intent chips on enemies and allies are more compact at phone landscape — smaller icon, tighter pill — so the monsters themselves stay the visual subject of the fight instead of being crowded out by their own UI.
  • Mobile-landscape mute button now shares the top-right chrome slot with future system controls: On phones in landscape combat, the mute button now sits in the top-right corner instead of floating at the bottom, so it no longer needs a special case to dodge the End Turn button. This is the first control mounted into the shared top-right chrome slot other mobile-landscape controls will join later. Desktop and tablet are unchanged.
  • Every player-facing control drops the slow OS-native tooltip in favor of styled in-game tooltips, visible labels, and screen-reader labels: Hover hints across combat, the inventory, the hall, the wiki, and the arena lobby no longer use the browser's slow, unstyled native tooltip. Where a hint repeated what was already visible it's simply gone; where it carried real information it now appears in the game's own styled tooltips (instant, readable, and working on keyboard focus), and screen readers get the same details through proper labels.
  • Clarify class selection, skill-tree timing, achievement rewards, and route choices.: Class selection now keeps each hero's playstyle visible in landscape, skill points explain when they can be spent, achievements lead with their rewards on phones, and route choices no longer repeat the same encounter details.
  • Enemy trait icons join the overhead intent readout at phone landscape, and Field Log actor chips respect the 12px text floor: On phone landscape, enemy trait glyphs now render alongside the overhead intent readout instead of being dropped, and Field Log actor chips no longer shrink below the 12px legibility floor.
  • Combat particle fx can now render through an optional canvas backend (probe, evidence-only) instead of DOM/CSS particles: Behind-the-scenes only (ROG-1423 evidence probe): combat particle effects (blood, death, status, guard, and reward bursts) CAN render through an alternate canvas rendering path instead of the existing DOM/CSS particle elements, but this is off by default for every player — it only activates behind an explicit opt-in (?canvasfx=1, persisted like the existing ?canvasfit= debug flags) used for evidence-gathering, not shipped gameplay. No player sees any visual change from this change alone; it is being evaluated for a future performance decision.
  • Canvas particle backend (behind ?canvasfx=1, still opt-in) gained eased travel/scale/opacity parity-plus with shapes, gravity, and a higher live-particle cap.: No player-visible change in this milestone: the canvas particle backend stays behind the opt-in ?canvasfx=1 gate, off by default. This lands internal quality work only — the canvas backend now matches the DOM particle effect's eased travel/scale/opacity curve, adds palette-appropriate shapes and a gravity option, and raises its live-particle cap well above the DOM path's, ahead of a future decision on whether to enable it by default.
  • Phone-landscape combat gets a thin full-width top bar: the charm pouch moves into it, and Inventory/unspent-points fold into the menu, freeing vertical space above the battlefield.: At phone-landscape combat, the top chrome collapses into a thin full-width bar that reclaims the space it used to reserve above the battlefield: the charm pouch button moves into the bar's left side next to a compact Act/zone readout, and Inventory and unspent skill/attribute points fold into the menu instead of sitting as separate bar buttons (the menu toggle shows a small badge when points are waiting to be spent). Nothing changes at any other screen size — desktop and tablet keep today's bar.
  • Phone-landscape combat: enemy intent/trait/mark readouts drop their pill background entirely, reading as bare icon+glyph with a legibility shadow instead: Enemy intent icons, trait badges, and the mark badge no longer sit inside a raised pill in phone-landscape combat — they read as bare glyph + number with a drop shadow, so the monster art underneath shows through instead of being covered by chrome.
  • Combat's hand of cards now overlaps the battlefield along the bottom edge (a translucent scrim, STS-style) instead of sitting in an opaque tray, and End Turn shrinks to a compact in-scene button.: At phone-landscape combat, your hand of cards now floats over the battlefield along the bottom edge — a soft scrim gradient behind the cards, with the scene running full-bleed behind them, instead of sitting inside an opaque bottom bar. End Turn shrinks to a small in-scene button in the corner. The battlefield itself now uses the full screen height.
  • Combat figures at phone landscape grow to STS-parity size (hero ~145px, enemies ~130px tall), rank rows gain horizontal overlap, and the energy orb's clipped label is folded into its accessible name (aria-label).: Hero, mercenary, and enemy sprites at phone landscape combat now read at STS-parity size (hero ~145px, single-row enemies ~130px tall), ranked 4-5 enemy formations overlap horizontally like a real monster rank, and the energy orb's clipped "ENERGY" label was folded into its accessible name (aria-label) so grown ally name labels no longer collide with it.
  • Mobile-landscape combat: STS-style rest-state readout diet plus a one-row uniform enemy rank at 4-5 enemies: On phone landscape, combat sprites no longer show a permanent name/HP label under every ally and enemy — the HP bar thins to a rest-state strip, and the currently targeted enemy gets a compact floating name + HP readout instead (at every enemy count). The 4-5-enemy formation is redesigned as a single horizontal rank: all enemies at one uniform scale on one shared ground line, art overlapping laterally like a real mob, HP strips sized to each sprite — replacing the old two-row front/back thumbnail split that read as a vertical jumble.
  • Combat: 4-5 enemy figures grow into the dead space next to the party at mobile-landscape, and ally HP strips slim to match the enemy strip's proportions: At phone-landscape combat with 4-5 enemies on the field, enemy figures are noticeably bigger and the row now fills the space that used to sit empty between the party and the enemies. Ally HP bars on the hero and mercenary are also trimmed down so they read lighter and match the enemy HP strips visually.
  • Combat landscape polish: capped hero growth at tall phones, themed the Field Log button, fixed zone-variant enemy art falling back to white glyphs, and removed the dark tiles behind intent icons: On tall phone-landscape screens (844x390 and taller), the hero sprite no longer grows past its normal size and pushes up into the top status bar — it now caps at the same size as every other landscape height. The Field Log button in the combat top bar is themed to match the other top-bar chips instead of rendering as a plain white square. Enemies from zone-variant encounters (patrol/ambush/swarm variants) once again render their real dark art instead of a flat white cartoon glyph — their template ids were falling through the sprite resolver to an SVG fallback. Intent icons above enemies no longer sit on small dark squares; the icon art's baked-in black background is blended away in landscape combat.
  • Desktop-canvas targeted enemies drop the boxed rounded-rect frame in favor of figure-anchored glow + ground ring, matching the container-less STS-parity read mobile stage 2 shipped.: At the desktop-canvas combat viewport, clicking an enemy to target it no longer wraps the sprite in a heavy rounded-rect card. The targeted enemy now reads via a stronger figure-anchored glow and a brighter ground ring under its feet — the same container-less, Slay-the-Spire-style marking mobile-landscape already shipped for combat figures. Elite/boss name readouts also drop their boxed panel background at desktop, matching the plain bar + text look used everywhere else.
  • Improved desktop Wiki names and glossary readability, and compacted sparse Spellbook cost bands.: The desktop Field Wiki now keeps full monster names visible and gives keyword explanations a more comfortable reading size. The Grand Spellbook also compacts single-card cost bands so the next tier of cards remains visible without scrolling.
  • Spread act-map waypoint routes across the painted canvas: Act 1, 2, and 4's world-map routes previously ran along flat horizontal lines (every mainline waypoint sharing the same y%), so early in an act the visible waypoints huddled in one narrow band instead of reading as a road winding across the painted backdrop. Their mainline waypoint y-positions now undulate gently (Act 3 and 5 already had this variation) while staying comfortably clear of each act's side-branch nodes, so the route traverses more of the full-screen art at both desktop and mobile-canvas sizes.
  • The world map's you-are-here town waypoint is now clickable and returns you to camp: The "you are here" town marker on the world map is now a real button instead of dead art. Click it to head straight back to camp — no need to hunt for another way in. It works exactly like the other return-to-camp options already in the game, it's just reachable from one more place now.

Fixes

  • Act maps repainted as landscape art that fills the screen; the route now travels across the painting instead of a narrow center strip.: All five act maps were repainted as widescreen landscape art. The paintings now fill the whole map screen on desktop and landscape phones, and the route travels across the artwork's real landmarks instead of pillarboxing into a narrow center strip with waypoints floating on empty letterbox.
  • Character select's mobile-landscape pass: legible flip-back text, no page-level scroll, a reachable flip hint, and a commit button that never truncates.: Character select on landscape phones no longer scrolls the whole screen to see the last line of a class's Signature Paths preview, and flipping to that campfire-reading view no longer strands its closing hint below the visible frame. Doctrine copy, lane badges, and role/complexity chips are legible instead of sub-12px, and the "Choose <Class>" button and hero name plate no longer clip for the longer class names.
  • Landscape character select now keeps hero choices and run-start actions tappable.: Landscape character select now keeps hero choices, Back, Builds, and the run-start action visible and tappable.
  • Combat's TR system cluster and lifted card sit clear of the frame edge again on phone landscape: On phones held sideways, combat's menu/settings/mute cluster and the enlarged view of a tapped card could sit right at the top edge of the screen — close enough to feel cramped against the notch or the edge of the glass. Both now keep a clear margin from the top of the frame at every phone size, without giving back any of the enemy row's or the hand tray's room.
  • Landscape phone combat cards are now sized to fit the hand tray instead of overflowing it.: On landscape phones the hand cards were rendering far larger than the command tray, so they overflowed and clipped each card's cost and name off the top — leaving only the empty lower frame visible. They now scale down to fit the tray as a straight, scrollable row, with the cost, name, and art readable and more of the hand on screen at once.
  • Landscape phone combat no longer overlaps party and enemy names or buries the enemies behind your hand.: On landscape phones, the party and enemy rows are now anchored to opposite halves of the battlefield, so combatant names and HP bars no longer collide (previously "Sorceress" could overlap "Zombie"), and the energy orb no longer clips the hero's own name. On the shortest landscape screens the hand tray also stays compact instead of growing tall enough to hide the enemies you are targeting.
  • Combat now stays playable with tap-sized controls on landscape phones.: Landscape phone combat now keeps the battlefield and command tray within the screen, with tap-sized pile, card, targeting, and turn controls. Hand overflow remains explicitly navigable without relying on hover.
  • Combat discard and exhaust pile controls now have reliable phone-sized tap targets in landscape.: On landscape phones, the Discard and Exhaust pile controls now have full-sized tap targets, making it easier to inspect your card piles without accidental misses during combat.
  • Desktop Wiki and Spellbook now fill the game canvas with readable controls, compact filters, clearer reference content, and safer menu hierarchy.: Desktop archive screens now use the full game canvas, keep controls readable at laptop resolutions, and present monster families, class skills, and gear as clear reference material. The in-run command menu also keeps Abandon Run separated beneath ordinary tools so a destructive action no longer dominates the menu.
  • Keep desktop decisions readable and prevent class-name and charm-badge collisions at laptop viewports.: Desktop expedition choices now stay readable on shorter laptop screens: hero names no longer truncate, charm pouch badges no longer cover reward titles, and key front-door, approach, and combat-card labels keep a clear text size.
  • Encounter ask/counter tags now describe the pack that actually gets built, not the recipe: zone encounters gained the tags they were missing entirely, phantom tags whose modifier binds nothing are gone, and two mechanically-false modifier mappings were retired.: The counter-play tags shown on an encounter now describe the enemies you will actually face. Previously they were inferred from the encounter's recipe and the *names* of its battlefield modifiers, so a pack whose composition differed from its recipe advertised the wrong ask — and 147 zone encounters showed no tags at all. Route and zone fights now surface the asks their real pack makes, tags whose modifier does not bind anything no longer appear, and two mappings that were false against the underlying mechanics (war drums claiming a support threat, court reserves claiming a summoner) are gone. Act boss identities are unchanged.
  • Enemy trait badges no longer overlap the intent value on phone landscape (badge column starts below the intent chip): On phones in landscape, enemy trait badges could stack on top of the intent value, hiding what the enemy was about to do. The badge column now starts below the intent chip, so both the traits and the incoming intent stay readable at a glance.
  • Bug-report launcher stays put when clicked: The floating bug-report button now stays under the pointer when clicked or dragged, including when the game canvas is scaled to fit the window.
  • Quarantined and draining fleet hosts are now visibly distinct in the /fleet dashboard instead of reading as healthy.: The sim fleet dashboard now shows when a host has stood itself down. A host that has quarantined itself renders red and a host that is draining renders amber, and both take precedence over the ordinary online/offline states — a broken host that had also gone quiet used to read simply as "dark", which sent whoever was looking off to check a machine that was merely powered off instead of the one that had actually failed. Submitting an experiment now also reports fleet health up front and stops rather than queueing work into a fleet with no capacity to claim it.
  • Fixed the guest-closed front door's Google sign-in button being clipped at short phone-landscape heights (568x320-932x430).: When guest play is closed, the title screen's Google sign-in button no longer hangs off the bottom of the screen on phones in landscape — the sign-in panel now fits (and scrolls if it must), so you can always reach it.
  • Landscape phone play now keeps Begin and Resume Expedition visible and tappable.: Landscape phone play now keeps Begin and Resume Expedition visible and tappable without scrolling through the front door.
  • Keep the Hall's primary expedition action reachable in phone landscape.: The Account Hall now stays contained after rotating a phone, so its Choose Hero action is visible and touchable in the first landscape view.
  • Character-select roster no longer truncates long class names (Necromancer): The character-select roster rail is slightly wider so the longest bloodline names (Necromancer) display in full instead of truncating with an ellipsis.
  • Mobile-landscape screens no longer scroll the page vertically: On phones held sideways, the whole page could rock up and down by about 24 pixels — a stray sliver of dead space above and below the frame that no control needed and nothing used. Town, the world map, combat, rewards, and every other landscape screen now fill the frame exactly, edge to edge, with no page-level wobble. Scrollable panels you're meant to scroll — the map, the character-select rail — still scroll normally.
  • Landscape route, reward, and event decisions now prioritize choices and the advancing action.: Landscape route, reward, and event decisions now prioritize choices and the advancing action instead of a full-height decorative rail.
  • The lifted hand card on phone landscape no longer sits on top of enemies.: On phone landscape, tapping a hand card to read it full-size used to pin the card right over the enemy lane — exactly where you need to tap next to aim it. The lifted card now appears to the left of center instead, where it never covers an enemy, the energy orb, the draw pile, or End Turn, so you can read a card and act on it without anything getting in the way.
  • World map text on phone landscape is now legible instead of rendering as small as 8px: Reading the world map on a phone in landscape no longer means squinting. Zone names, the "you are here" marker, encounter counts, the act-progress line and the map's own buttons were rendering as small as 8px — well under the size anything is comfortably readable at — because the map had no landscape styling of its own and fell back to sizes meant for a desktop monitor or a portrait phone. They now all render at a proper minimum size, with the labels reflowed so the bigger text does not crowd its neighbours. The act-progress bar and the boss preview have also moved off the bottom of the map and into a slim strip along the top. They used to sit in the same band as the zone labels and overlap them — "Boss of Act 1" would print straight through "You are here" — and on a short landscape screen that band is exactly where the route is. Up top they stay out of the map's way, and the act label and zone count read in shorter form to fit. The Parchment View toggle has moved up into the same top-right cluster as the rest of the system buttons. On wider phones it used to sit half-underneath that cluster — you could see the label, but tapping the middle of it opened the menu instead, and only a thin strip along its bottom edge actually worked. It is now a normal button in the row, tappable anywhere on it. The boss preview is now a tap instead of a permanent banner: the strip shows the boss's name, and tapping it opens a panel with the damage types and signature threat. That keeps the information a tap away instead of spending a third of the top row on it at all times, which is what let the rest of the strip fit on the narrowest phones. Desktop and tablet are unchanged.
  • Keep the act-transition continue action visible and usable on landscape phones.: Act transitions now foreground the destination and Continue action in phone landscape, so players can advance to the next town without scrolling past a long cinematic layout.
  • Keep Battle Arena reachable and its first setup choice tappable on landscape phones.: Battle Arena remains available from the compact landscape front door, and its setup now keeps the first class choice in view on short phone screens.
  • Fix landscape-phone combat (End Turn no longer hidden by the Muted badge) and the run-start charm draft (cards now fit the screen in a readable horizontal row instead of a clipped vertical stack): On phones held in landscape, the End Turn button is no longer covered by the "Muted" indicator during combat, and the opening charm draft now lays its charms out as a readable horizontal row that fits the screen — showing each charm's name and effect — instead of an oversized vertical stack you had to scroll past. Desktop and tablet layouts are unchanged.
  • Mobile-landscape enemy formation no longer overflows its lane or slides under the top-right menu at high enemy counts: On phones in landscape combat, a full field of enemies now arranges itself into two neat ranks instead of spilling past the edge of its own lane — with five enemies on screen, the extras used to render outside their visual boundary, overlap the tappable area of the top-right menu, and (in the worst case) even crowd toward the hand tray. Every enemy stays fully visible, individually tappable, and clear of the surrounding chrome no matter how many are on the field. Desktop and tablet are unchanged.
  • Hardened the mobile-frame system-cluster/scroll-toggle/Focus-overlay mount machinery (no player-visible behavior change).: Internal hardening only, no observable gameplay change: the TR system-cluster's owned-node reinsertion, the world-map scroll-toggle patch's target lookup, and Escape's generic overlay-close fallback are now robust against nested/duplicate mounts and stacked overlays — follow-ups from the ROG-1336 code review, made safe for the mount machinery's next user rather than fixing an observed bug. Player-visible follow-up (mobile-landscape world map, act 3): a near-top waypoint's caption (e.g. Spider Hollows, Hunter Village) no longer clips behind the top progress strip — its label and progress badge are now fully readable on their own plate.
  • Keep the compact phone-landscape command tray tappable and verify a real combat turn advances.: The compact phone-landscape command tray now keeps its deck pile from pushing the hand below the play surface, while automated touch checks verify that a real combat turn can be completed at both supported phone landscape sizes.
  • Fix Arena entry and event/checkpoint choices being unreachable at the 568x320 smoke-tier viewport (ROG-1378, ROG-1379): On the smallest supported landscape phones (568x320 and similarly short viewports), the Battle Arena entry on the front door and the choice cards on checkpoint/event decision screens could render partly or fully off-screen and untappable. Both now stay reachable at every viewport in the mobile-landscape matrix, with no change to layout on larger phones.
  • Phone play now opens in landscape with a clear rotate prompt in portrait.: Phone play now opens in landscape with a clear rotate prompt in portrait, keeping the game controls at a usable size.
  • Mobile-landscape combat hand cards now render at a readable, fixed scale and clip against the command tray instead of shrinking to fit it.: On phones in landscape combat, hand cards were shrunk down to tiny, unreadable thumbnails to fit inside the command tray. They now render at a fixed, legible scale and rest against the tray like cards rising out of a hand of cards, with only the excess height clipped away — cost and card name are always readable at a glance, and cards you can't afford to play show a red cost gem instead of shrinking.
  • The muted indicator is now a tappable unmute button (icon-only on landscape phones), instead of a passive 'press M' badge you couldn't use on touch: The "Muted" badge is now a real unmute button instead of a passive reminder: tap it to unmute on phones (it shows just the speaker icon in landscape), or click it on desktop. The M key still toggles mute/unmute exactly as before.
  • Autopilot and feedback controls now stay clear and recover safely after phone rotation.: Autopilot and Report Bug controls now use separate phone-landscape corners, remain tappable, and recover into view without overlapping after rotation.
  • Keep the persistent run-summary exit touch-sized on landscape phones.: The persistent return control in the run summary now meets the landscape-phone touch target, so players can exit a completed expedition without reaching for a tiny control.
  • Keep Inventory, camp commands, Hall navigation, and secondary overlays usable in phone landscape.: Phone-landscape players can now open Inventory, Spellbook, and Settings during a run, while Hall navigation and overlay exits remain on-screen and touch-sized.
  • Keep secondary overlays contained and their close controls tappable in phone landscape.: Secondary dialogs now stay within a phone held horizontally, with compact safe edges and reliably tappable close controls for inventory, card lists, town services, spellbook, wiki, and act-transition panels.
  • Town service screens are now fully readable on phones instead of washing out behind the camp: On phones in landscape, opening a town service — the blacksmith's workboard, the vendor's stock, the mercenary captain — rendered it half-transparent over the camp behind it, so item names and prices washed out and were hard to read. Services now take over the whole screen on a solid background: the shopkeeper and their flavour sit on the left, their wares fill the right as one comfortably tappable list, and a Leave control sits in the same top-left corner for every service.
  • Charm reward titles no longer run under the pouch-slots pill: On charm reward screens, long charm names (like Grand Charm: Storm Lance) no longer run underneath the "N pouch slots" pill in the card corner — the title now wraps clear of it.
  • Fix mobile-landscape reward/charm-draft layout: portrait no longer covers the leftmost choice, all choice cards stay on-screen, the pouch-slot badge no longer overlaps the card title, and the choice row is centered with a small header prompt and a bottom-right take/commit action.: On phones in landscape (e.g. the run-start charm draft), the reward screen no longer hides a choice behind your hero's portrait or pushes a choice off the right edge of the screen. All choices now sit centered on screen, sized to read clearly, with the pouch-slot badge on charm cards no longer overlapping the card's title.
  • Ranked lobby: a legacy no-period saved run no longer resumes the wrong attempt, and a leaderboard reply for a different period than the status leg is no longer shown as the current board.: Fixed two ranked-lobby edge cases around period changeover. A ranked run saved before periods were tracked (or one from an already-expired period) could previously be offered as "Resume" for a different current attempt started on another device — it's now correctly recognized as not this attempt once the lobby knows its period. Separately, the lobby's status and leaderboard load independently and could straddle a daily/weekly rollover; the board no longer shows entries from a different period than the one your attempt status describes — it now shows a load-error state instead of stale, mismatched rows.
  • Extend the desktop-canvas legibility floor to combat, town, reward, and merchant meta/badge text that was rendering under 12px effective size.: On smaller desktop windows (1440x900 and below) the game canvas scales down, and supporting text — combat badges, corpse-pile counts, waypoint labels, merchant stats and hints, reward tags — was shrinking below readable size along with it. Those elements now hold a fixed minimum rendered size no matter how small the window gets, so decision-relevant details stay legible on compact laptops and half-screened windows.
  • Fixed unstyled layout on tablets and small desktop windows: Playing on a real tablet in portrait (or a half-screened desktop window) previously dropped you into a completely unstyled layout — tiny text, buttons that were hard to tap, and controls that could render off to the side. The front door, character select, town, world map, reward, and combat screens now get a proper responsive layout on these mid-sized screens: readable text sizes, comfortably tappable buttons, and no more elements escaping the frame.
  • Two crafted puzzles (Freeze the Room, Bone Barrage) work again after the zone renames, and the monster codex reflects the current roster: The Freeze the Room and Bone Barrage crafted puzzles crashed after their zones were renamed out from under them — both are playable again with their original enemy lineups. The monster codex (registry and lore) has also been resynced to the current roster, so recently added monsters show up and retired ones no longer linger.
  • Internal: monster registry art reference regenerated (greater_mummy); no gameplay change.: No visible change: a stale internal art reference in the monster registry was regenerated.
  • Ruined Watchtower's pool no longer force-classifies every monster as support from the zone slug's own "tower" keyword; classifyRole now scans the monster's own slug/name: Ruined Watchtower packs now field a proper mix of roles. The zone's own name was tripping the "tower" support keyword, so every monster in its pool was treated as a support unit and patrols could never include a true raider. Dark Archers there are now correctly ranged and Devilkin are raiders — expect the zone's fights to feel like the rest of Act 1 instead of a wall of support enemies. No other zone's composition changes.
  • Internal content-identity refactor: campaign zones now carry stable authored ids (no gameplay change).: No visible gameplay change: campaign zones now carry stable internal ids, so future zone renames can't silently reshuffle encounters, routes, or saved-run references.
  • Four monsters return to the wild and the Drowned Causeway gets its proper denizens: Four monsters that had been quietly locked out of every encounter — Dark Lancer, Specter, Blood Wing, and Corpse Spitter — are back in the wild across acts 1 through 4. The Drowned Causeway (Act 3's flooded sewer side path) now spawns its own proper denizens instead of an empty pool. Under the hood, a new validation gate keeps a zone's monster pool from silently losing a monster to a role-slot or naming conflict again.
  • Grand Spellbook now lays out properly at phone-landscape: compact single-row header and a true multi-column card grid across both book pages (previously one clipped card and blank pages at 667x375).: On phone-landscape screens the Grand Spellbook previously showed a single clipped card in the bottom-left with both book pages otherwise blank — the header ate a third of the screen and cards rendered at desktop size. The header is now a single compact strip (title, search, filter, close on one row) and cards shrink to fit, so each cost band reads as a real multi-column grid you can actually browse.
  • Expedition setup screen gets a fitted two-column phone-landscape layout with Begin Hunt always on-screen.: The expedition setup screen (rift depth and current hunt) has a proper phone-landscape layout: the header no longer clips, the dead space is gone, and Begin Hunt is always visible without scrolling.
  • Fixed campfire wakeup CTA overlapping narrative text and the opened-scroll charter page clipping content at phone-landscape sizes: The campfire intro no longer hides its own story text behind the giant Reach for the Scroll button on phones in landscape, and the opened charter page is now genuinely readable and scrollable instead of clipping its text.
  • Charter scroll text keeps a quiet margin off the torn parchment edges at phone landscape.: The opened charter page keeps its story text clear of the torn parchment edges on phones in landscape, so lines no longer crowd the artwork border.
  • Charm draft: the pouch-fit status line no longer clips off the bottom of the card at phone landscape.: On the charm draft, the green pouch-fit line no longer spills off the bottom of the card at phone-landscape sizes — long charm effects scroll inside the card while the fit line stays pinned and readable.
  • Fix zone route-decision (approach) cards overflowing the viewport at phone-landscape widths.: Zone route choices (Scout Ahead / Charge Forward / Follow the Trail) now fit on screen on phones in landscape as a swipeable row with their art restored, instead of running off the bottom of the screen.
  • Combat: the tapped-card preview keeps its true card proportions at phone landscape instead of squashing.: Tapping a card in combat on a phone now shows the enlarged preview at its true card proportions instead of a squashed wide frame.
  • Combat: the turn banner sits under the top bar at phone landscape, clear of enemy intents.: The Combat Phase / Enemy Turn banner now appears just under the top bar on phones in landscape instead of covering the enemy figures and their intents.
  • Route choices, Inventory, and critical combat/class text now stay readable and reachable across supported displays.: Route checkpoints keep each path's consequence and reward visible before you commit, the Encampment Ledger remains fully usable on compact landscape phones, and critical class-unlock and Guard projection text is easier to read on desktop displays.
  • Boss data slimmed to what the game actually uses: No player-visible change. data/seeds/d2/bosses.json carried ~561 unrendered wiki-scrape strings (Diablo II page titles, tactics/trivia prose, image filenames, variant blocks) left over from the original import; only id/name/bossProfile are ever read at runtime. Stripped the rest, shrinking the seed file from 346,549 to 15,268 bytes. Verified the generated encounter catalog (521 encounters / 463 enemy templates) is byte-identical before and after.
  • Monster lore now names the world's own places and orders: Enemy flavor text across the roster now names our world's own zones, orders, and courts instead of leftover placeholder place names — the Blackwood Covenant's renegade rangers, the Fever Marsh's bramble giants, the Idol Court's ruling junta, and dozens more now read consistently with the shipped map and the rest of the game's lore.
  • Single-choice rewards on phone landscape are now centred instead of pinned to the left edge.: When a reward screen offers just one card to take — most commonly "Collect Spoils" after a fight — playing in phone landscape used to leave it stranded near the left edge with a big stretch of empty backdrop on the right. That single card now sits centred in the frame like the rest of the reward screens, with no change to how multi-card reward rows behave.
  • Skill-tree nodes and town portal/exit/badge controls drop the banned native title= tooltips in favor of visible labels + aria-labels: Skill-tree investment nodes and the town's return-portal, exit-gate, and NPC badge controls no longer rely on the slow, unstyled OS-native tooltip. Everything those tooltips said is already visible on the controls themselves, and screen readers now get the same information (including the option count on NPC badges) through proper labels.
  • Town square text is now readable on phone landscape, and NPC pins no longer overlap each other or the feedback button.: On phone landscape, the town square's NPC role labels, service-count badges, and the World Map gate label rendered too small to read, and the World Map label could hang off the bottom of the screen. NPC portraits could also crowd into their neighbors closely enough that tapping one risked hitting the wrong vendor, and at some screen sizes the feedback button could sit on top of an NPC portrait entirely. All of these are fixed: labels and badges are legible, the World Map button stays on-screen, and every NPC portrait now has its own clear tap area.
  • Town NPC disabled-state reasons now use the sanctioned tip system instead of native title=, and Dagan's disabled copy states the real reason he's inert.: Camp NPC pins (Mireya, Braska, Murn, Veyra, the Stash, and the travel caravan) now show their "why is this greyed out" reason through the game's styled tooltip system instead of the browser's native title tooltip, so the reason appears instantly on hover and also on keyboard focus instead of after a ~1s OS delay. Dagan's disabled copy no longer reads like an open invitation to travel — it now explains that the road east opens at the World Map gate, not through him.
  • Fix mobile-landscape legibility in the merchant, blacksmith, and healer town-service screens: sub-12px text raised to the floor, a portrait grid-collapse bug that hid the vendor/blacksmith name and role restored to visible, and a duplicate footer removed.: Town service screens (merchant, blacksmith, healer) are now readable on landscape phones: every label and count meets the 12px text floor, the vendor and blacksmith name/role panel — previously collapsed to zero width by a layout bug — is visible again, and overlapping labels were untangled.
  • Keep active tutorial controls reachable after rotating a phone into landscape.: Active tutorial controls now reposition when a phone rotates into landscape, keeping the next and skip actions reachable instead of leaving them at portrait coordinates.
  • The Ascent and Lower Court now fight their authored monster packs instead of act-generic fills.: Two zones — The Ascent and Lower Court — were silently falling back to generic act-filler encounters instead of their authored monster packs, because their legacy zone-key remap pointed at misspelled/incorrect keys that don't exist in the source data. Both zones now spawn their intended Patrol/Ambush/Swarm packs. Also removed 11 vestigial legacy-key remap entries (7 dead zone names plus 4 named-miniboss zones whose content actually comes from a separate system) that pointed nowhere and did nothing.

Tech

  • Dev tooling: rouge now sources shared lint rules from the @andrewpopov/eslint-config kit (no behavior change).: No player-facing change. Rouge now depends on the shared @andrewpopov/eslint-config kit and sources its common style-rule battery from it, so future standard-lint changes propagate automatically. Rouge keeps all its bespoke rules, its documented max-lines grandfather lists, the prefer-services-bag rule, and the worker_threads ratchet unchanged (verified byte-identical lint config).
  • Add default-off aoeSplashesSummonsEnabled flag so enemy AoE can optionally hit summons (fleet A/B only, no player-facing change yet): Nothing changes in the game yet. Behind a default-off flag, enemy area attacks can be made to hit summoned minions as well as the hero and mercenary — today summons are structurally immune to AoE, which silently nullifies summon-based mitigation against volley-heavy packs. The flag exists so the balance fleet can A/B the change; if promoted, area attacks will become a genuine counter to summon builds while spreading their pressure off the hero.
  • Recalibrate charm-scoring drawback weight so trade-off charms (e.g. glass_cannon) price their downside commensurately with offense, fixing over-selection in default meta-build loadouts (sim-side scoring only, no player-facing change).: Internal simulator tuning: trade-off charms (like Glass Cannon) now price their drawback properly in automated build scoring, so simulated loadouts stop over-picking them. No change to gameplay.
  • Post-review hardening of the desktop STS shell: targeted-ring cascade fix + tightened UI test guards: Code-review follow-up to the desktop STS shell: the enlarged targeting ground ring no longer gets shrunk back by a later equal-specificity rule, and the UI test suite closes three guard gaps found in review (orb-size upper band outside desktop-canvas, design-space geometry comparison, non-null elite art assertion). No gameplay change.
  • Triaged the rotted e2e mobile lane and added a documented pre-push gate for UI changes.: No player-facing change. Deleted the phone-portrait e2e tests boot/canvas-fit.js (ROG-1126) made permanently unreachable, retargeted the surviving mobile e2e assertions from portrait (390x844) to landscape (844x390) to match the mode the app actually serves, fixed a born-failing touch-target guard, and added npm run test:e2e:gate as the documented pre-push convention for changes touching src/ui/, styles/, index.html, or boot/ (ROG-1367).
  • Balance sims now record which monsters filled each pack and how the hero's HP came off turn by turn.: Nothing changes in the game itself — this is instrumentation for the balance sims. Per-encounter results now carry the monsters that actually filled the pack, the hero's HP loss broken out turn by turn, and how many potions were in the belt going in. Previously a fight only reported its outcome, its length and where the hero's HP ended up, which could not tell a pack that opens with a huge burst apart from one that simply grinds a run down — so a difficulty spike in a single zone could be seen but not explained.
  • Propagate the D2 IP scrub into monster seed data (zone-monsters.json, enemy-pools.json) so the registry/lore generators emit scrubbed output; extend the scrub guard to cover seed files and monster-roster.ts.: Fixes a handful of monster names that had slipped through the earlier IP-scrub pass: Horadrim Ancient, Zakarum Priest/Zealot, Zakarumite, Worldstone-prefixed Act 5 variants, Baal Taunt, and Baal's Minion now consistently read as their re-canonized names (Ashen Ancient, Idol Priest/Zealot, Idolite, Crown Stone-prefixed variants, Siege Effigy, Siege Tyrant's Minion) everywhere they appear, including monster placement data and the wiki archive.
  • Stop generating unreachable zone encounters under legacy source-data zone names (ROG-1400): 165 dead Patrol/Ambush/Swarm entries removed from the encounter catalog, no routed content changed.: No player-facing change: the encounters removed here were never reachable. The registry was building every zone's fights twice — once under the zone's shipped name, once under the internal source-data name it was renamed from — and only the shipped-name copy was ever routed. The duplicate half (165 encounters, over half the zone-encounter catalog) is gone. Every zone you can actually visit fights exactly as it did before.
  • Add default-OFF minion-aggro redirect probe (__minion_aggro_v1__) for the ROG-1307 A/B — inert unless armed by a sim arm: No player-facing change. Adds a default-OFF combat probe (__minion_aggro_v1__) that, when armed by a sim arm, redirects single-target enemy attacks aimed at the hero onto an eligible summoned minion (creatures/tanks, not traps or support) with a one-interception-per-minion-per-round budget — the groundwork for an A/B testing whether minion body-blocking fixes the necromancer's early-burst floor (ROG-1307). Inert until armed; AoE is unaffected.
  • Add __minion_aggro_v2__ probe: minion-aggro redirect + a 2/round global intercept cap (curbs the wide-board over-buff, default-OFF): No player-facing change. Adds a default-OFF combat probe (__minion_aggro_v2__): the same single-target hero-attack -> minion redirect as v1, plus a global cap of 2 hero-side intercepts per round. The v1 benefit scaled with board width (a wide summon board could block nearly every hit); the cap curbs that for wide-board classes (e.g. druid) while narrow boards (necromancer) keep their intended floor-fix. Inert until armed by a sim arm; part of the ROG-1307 A/B.
  • getPriorityEnemyTargets gains a probe-gated 4th disruptor priority-target slot (default OFF, byte-identical), letting a same-binary CRN A/B measure whether enumerating a mid-life support/curse/summon enemy alongside the existing 3-slot pick helps the pilot 'kill the curse-spreader'.: Sim tooling only; no player-facing change (the probe is default-OFF and never set in production). With 4-5 living enemies the existing getPriorityEnemyTargets 3-slot cap (marked / lowest-effective-life / highest-threat) can exclude a mid-life mid-threat support/curse/summon enemy — scoreSingleEnemyThreat already prices these heavily, but there is only one highest-threat slot and raw attack damage usually wins it, so the pilot never enumerates a card against "the curse-spreader." Behind trait-foresight:__disruptor_target_slot__ (__ROUGE_SIM_TRAIT_PROBE, SYNTHETIC_PROBE_KEYS), a 4th slot is appended (never displacing/reordering the original three) by scanning the already Oath-excluded, already-sorted highest-threat ordering for the first qualifying enemy not already chosen. This is a pilot-STRENGTH change, not a parity fix, hence the probe gate — flipping it needs its own same-binary CRN A/B.
  • Boot-config gate zoneAltRaiderMeleeFallbackEnabled (default ON) makes the ROG-1451 melee-honest alt-raider fallback fleet A/B-able; no default behavior change.: No player-facing change: encounter generation is identical by default. Adds an internal boot-config switch so the balance fleet can measure the ROG-1451 alt-raider fallback change (melee-honest enemy picks in two act-2 patrols) against the behavior it replaced.
  • Hardened the zone encounter role-fallback selector to prefer a role-honest unused entry before an arbitrary pick (no player-visible change; verified zero catalog delta).: No player-facing change. spreadAcrossRoles (encounter-registry-builders-zones.ts) previously filled an empty role slot with any unused pool entry regardless of its role — the same role-blind fallback bug class as ROG-1451/ROG-1460, one level up. It now prefers an unused entry whose roster row matches the role being filled, closing the selector hole that historically let a ranged-override family wear the SUPPORT slot (ROG-1383). Verified via full pre/post encounter-catalog dump-and-diff: zero encounters differ on today's live zone rosters (ROG-1414's pool-depth pass already fixed the two observed instances).
  • Mobile canvas letterbox bars now show a blurred stage-bleed of the act map (flag-gated): On phones, the letterbox bars beside the mobile canvas no longer sit as flat black voids — they now show a blurred, darkened bleed of the current act's map art, so the play area feels framed by the world instead of floating in dead space. Flag-gated; visuals only, no gameplay change.
  • Sim underplay-gate telemetry now records WHICH cards were left unplayed (per-turn ids + per-encounter early-turn histogram) and names the score bar as a constant; gate behavior unchanged.: No player-facing change. The balance sim's run-validity ("underplay") gate now records the identity of the cards it counts — per-turn card ids and a per-encounter early-turn histogram — instead of a bare count, so gate decisions are auditable from the canonical store (ROG-1360). The score bar is now the named MEANINGFUL_CARD_SCORE_BAR constant with a runtime-vs-mirror parity guard; counts, rates, and gate outcomes are byte-identical.
  • Internal hardening: missing warlock card-pool modules now fail loudly at load instead of silently dropping cards.: No player-facing change. If a warlock card-pool module ever fails to load (broken build output or script ordering), the game now fails immediately naming the missing module instead of silently shipping a warlock deck with absent cards.
  • Selection upgrades behind the zone-variants flag: weighted encounter picks and a no-repeat-within-3 window.: ROG-1411: three upgrades to the existing ROG-225 banded encounter picker, all behind the opt-in zoneEncounterVariantsEnabled flag (no player-visible change while it stays off). When on, a zone's encounter pool now includes the ROG-1410 curated variants (weighted via each variant's selectionWeight, base recipes implicitly weight 1) instead of only the original three per zone, and the picker avoids re-fighting an encounter id it fought within the last 2 clears (falling back to the unfiltered pool for a single-variant zone so nothing ever fails to resolve). Reload-before-clear stays byte-identical (idempotent), and an all-weight-1 pool picks exactly as it did before this change.
  • Migrate the world map onto the ROG-1382 mobile canvas behind a flag; no default player-visible change.: No default player-facing change. The world map now supports rendering on the flag-gated ?mobilecanvas=1 mobile-landscape canvas (ROG-1382, still off by default) instead of only the responsive layout — a ?mobilecanvas=1 player now sees the map render at a uniform scale across 667x375 through 932x430 phone widths (a real 740x360 previously mispositioned the map's fixed-position UI relative to the letterboxed canvas). The default responsive world map is byte-identical; 568x320 continues to render responsively even with the flag on, since it falls below the readable-scale floor for the mobile canvas.
  • Groundwork: authored zone-encounter variants behind a default-off flag (inert until enabled).: No player-facing change. ROG-1410 adds curated zone-encounter variants (a rotated-pack patrol, a modifier-swapped ambush, and a rotated-pack swarm per zone) behind a new zoneEncounterVariantsEnabled boot-config flag, default OFF. The variants are enumerated into the encounter catalog for validation and future tooling, but are never appended to a zone's resolvable encounter pool in this change, so no run can ever select one yet — this is groundwork for a follow-up ticket that will A/B them into rotation.

Operations

  • Deploy seeds candidate env from live release: No gameplay change. The atomic-staging deploy (ROG-1298) builds an isolated candidate whose fresh checkout has no .env.production (it is gitignored), so the manually-provisioned GOOGLE_CLIENT_SECRET was absent and the candidate startup smoke crashlooped. Deploys now seed the candidate .env.production from the live release before ensuring the managed keys, so the secret is preserved; the live env file is only read and is never moved by the promote.
  • Deploy staging confined to a rogue-owned dir: No gameplay change. The atomic-staging deploy (ROG-1298) built its candidate release in root-owned /srv, which the confined rogue service user cannot write; deploys now stage the candidate, versioned releases, and the current-dist symlink under a single root-provisioned, rogue-owned /srv/rogue-staging directory, so the deploy keeps its build-outside-live isolation without granting the service any write access to /srv.
  • Sim-fleet hosts install production dependencies only (npm ci --omit=dev), removing the devDependency toolchain that bricked three hosts.: No player-facing change. Sim-fleet hosts now install with npm ci --omit=dev instead of pulling the entire devDependency tree into every pin directory, which is what caused the 8-day, 3-host balance-run outage (a private git+ssh eslint package that no sim ever loads). The packages the fleet genuinely needs at runtime — typescript, @types/node, linkedom — moved into dependencies, since the fleet compiles TypeScript as normal operation. The production server's dependency install grows by those three; nothing else about the deploy changes.
  • Internal @andrewpopov dependencies now install from https tarballs pinned by commit sha — fleet hosts no longer need GitHub SSH credentials to build a pin (ROG-1345): No player-facing change. The three internal @andrewpopov packages (db-backup, release-kit, eslint-config) moved from git+ssh:// specs to sha-pinned GitHub archive tarballs, so any build or fleet host can npm ci without a GitHub SSH credential. This retires the failure class that silently bricked 3 of 5 fleet hosts in July (ROG-1345).

Angel Snack 0.1.0-alpha.15 Patch Notes

Release date: 2026-07-19

Stage: alpha

Package version: 0.1.0-alpha.15

These notes are gathered from the release fragments in docs/patch-notes/unreleased/.

Gameplay

  • Quest sites now cache a rune for your runeword project instead of forging the whole thing, and vendors stock a rune from your recipe rather than exactly the one you need next. The hunt is back.: Quest sites no longer hand over a fully forged runeword — they cache a single rune drawn from your project's recipe, which might even be one you already used. Town vendors likewise stock a rune from your recipe rather than exactly the one you need next. Between drops, caches, and vendor stock the funnel still points at your runeword, but finishing it is a hunt you can lose, not a delivery.

UI

  • Hall tabs now use the standard button styling: The tabs on the hall / front-door screens (section, archive, character, and unlock tabs) now use the game's standard button styling and selected-state highlight, matching the tabs used elsewhere (gear, inventory, arena). Behavior is unchanged — this is a visual consistency pass; the selected tab now shares the common ember highlight instead of a one-off style.
  • Buying from a town service (healer, blacksmith, mercenary, corven vale) now patches the open overlay instead of rebuilding the whole screen, and the overlay keeps your scroll position after a purchase.: Buying, selling, or otherwise using a town service — the healer, blacksmith, mercenary captain, or Corven Vale — no longer rebuilds the whole town screen for each purchase. The open service window updates in place, and if you had scrolled down a long list (e.g. vendor stock or the forge workboard), that scroll position is preserved instead of snapping back to the top after every click.
  • Town purchases now show a success toast: Buying from a vendor, selling or consigning gear, and using healer or quartermaster services in town now shows a brief confirmation toast (e.g. "Purchased", "Sold", "Restored", "Refilled") in the corner of the screen, so a successful purchase or service always gives clear feedback — even when the item card or overlay updates immediately after the click.

Fixes

  • Combat card previews show accurate damage/guard numbers: The damage and guard numbers on a card's preview chip now always match what the card will actually do. Previously the preview could disagree with the real play in a few cases: cards whose effect is gated by a condition (e.g. a form- or confluence-locked guard bonus) showed the full value even when the gate wasn't met, targeting a non-first enemy could show the wrong (or zero) damage, and forced-overpay cards understated their scaled damage. The card face now derives these numbers from the same engine the actual play uses, so the preview can no longer lie.
  • Card previews show accurate numbers for counter-scaling and AoE cards: The damage/Guard preview chip on hand cards now reads correctly for every card, derived directly from what the play would actually resolve rather than a fixed list of effect types. This fixes cards that previously showed "Resolve" or omitted their Guard/line numbers (counter-scaling, mark-payoff, AoE-counter-spend, and polymorphic effects like Chaos Surge), cards that mix a single-target hit with an area effect no longer double-count the selected enemy's damage into the area total, secondary damage from an active system (such as Barbarian War Howl's aura splash) now shows up in the line total, and Guard grants now attribute to self vs. party based on who actually received Guard rather than which card effect granted it. An area-of-effect card no longer wrongly splits out a "single target" number just because an enemy happens to be selected on screen, and Guard a mercenary gains entirely on its own is no longer mislabeled as shared "party" Guard.
  • Fix overlapping pill/title on charm rewards and tutorial popups: On the charm reward screen, the yellow "N pouch slots" pill no longer overlaps the charm name, and the tutorial popup's × close button no longer overlaps its step counter. Both now reserve space so the text stays readable.
  • Combat potion/End-Turn rejects now announce a spoken reason, hand-card labels speak the resolved outcome, paper-doll equipment slots are keyboard-operable, and run-summary filter changes preserve focus.: Screen-reader and keyboard-only players get four fixes: combat potion and End Turn rejections (and the End Turn "queued behind your remaining plays" defer) now announce a spoken reason instead of only flashing the button; a hand card's spoken label now states the resolved outcome (matching the number on screen) instead of the card's unresolved base text; inventory paper-doll equipment slots can now be activated with Enter or Space, not just a mouse click; and changing a run-summary filter pill no longer drops keyboard focus back to the top of the page.

Tech

  • Probe-gated T5-6 affixed-enemy pack cap softening (default-OFF) for the ROG-1230 necromancer T6-floor A/B: No player-facing change yet. This is a default-OFF ascension balance probe (softens the T5-6 affixed-enemy pack cap 2->1 when armed) added so simulations can A/B-measure the necromancer T6-floor fix before it is considered for normal play.
  • Necromancer balance: landed the Summoner's Ward summon-guard lever behind a default-OFF A/B probe (__necro_summoners_ward_v1__). Inert until validated + promoted; no player-facing change yet.: No player-facing change yet. This is a default-OFF balance probe for a Necromancer summon-guard passive, added so simulations can measure the lever before it is considered for a normal run.

Operations

  • Release follow-up hardening: complete patch-note copy, isolate GnuPG state, and remediate the production audit advisory: No gameplay change. Published alpha.14 patch notes now contain finished copy, encrypted backup state is kept outside the deploy checkout, and the production dependency graph overrides the vulnerable js-yaml release to the fixed version. The release-note package stays in production dependencies because the live feedback route imports it.
  • Deployment and release safeguards now fail closed before maintenance: Deployments now stay pinned to the build that passed local validation, prove the pruned production server can start before maintenance, and reject release or backup state that violates publishing and checkout-safety rules.
  • Production deploys now build and smoke-test in an isolated candidate checkout before atomically promoting the release during maintenance: Deploy preparation no longer rewrites files used by the running game. A candidate release is built and smoke-tested in isolation, then its static bundle is switched with an atomic pointer during maintenance; failures restore the exact prior release.

Angel Snack 0.1.0-alpha.14 Patch Notes

Release date: 2026-07-18

Stage: alpha

Package version: 0.1.0-alpha.14

These notes are gathered from the release fragments in docs/patch-notes/unreleased/.

Gameplay

  • Act 4's roster gains ranged threats — the ash no longer only charges at you (ROG-1215): Act 4's rank-and-file learned some discipline. Black Lancers, the Damned, and Urdar no longer just charge the Wanderer every turn — they now fight like skirmishers, falling back behind Guard and sniping whoever on your side is closest to death. Their stats are untouched (same life, same damage), but the pressure feels different: instead of trading blows at the front, you'll need to shield a wounded mercenary or a low-life hero from picked shots while cracking their guard. Watch the intent telegraphs — the target markers tell you who's in the crosshairs.
  • Assassin Shadow counter glow now marks the real breakpoints (5/10/15/18 — spender range, burst range, Death Sentence, Overdraw) instead of 10/20.: The Assassin's Shadow counter now highlights the thresholds that matter in play: spender range at 5, burst range at 10, Death Sentence at 15, and Overdraw at 18. The glow is a better prompt for when to cash in or keep building.
  • Axes are now a real weapon family: 5 axes drop across acts 1-5, Barbarian favors them, and the Steel and Pattern runewords roll on axe bases.: Axes can now appear throughout acts 1–5 as a real weapon family, with Barbarian builds favoring them and Steel and Pattern accepting axe bases. They add another meaningful gear path instead of being decorative loot.
  • Skipping a card reward now banks Spoils — each stack adds an extra choice at your next boss reward (ROG-1209/1214): Skipping a card reward is no longer just a refusal: it banks a Spoils stack that adds an extra option to your next boss reward. That makes restraint a real deckbuilding decision rather than a dead end.
  • Mastery Hall is now a real choice — earn points, pick your path, chase capstones (ROG-1211): Mastery Hall gives long-term progress a clearer shape: earn points, choose a path through its tiers, and work toward capstones. Your account progression now offers distinct strategic commitments instead of a flat unlock list.
  • Paladin: Defiance now costs 2 (was 1); Holy Freeze now applies 2 Slow (was 1 Freeze) — it chills the pack instead of freezing it solid.: Paladin's Combat Zeal lane traded a bit less pack-clear immunity for the same core plan: Defiance still taunts, guards, and generates Faith, but now costs 2 Energy instead of 1, so it no longer slots into a full-cantrip turn for free. Holy Freeze still hits for 14 cold AoE and draws a card, but its status effect changed from 1 Freeze (fully skips the enemy's turn) to 2 Slow (delays but doesn't cancel it) — packs will still act against you, just a beat slower.
  • Paladin: Holy Freeze now deals 14 (was 20) and applies 1 Freeze (was 2); Defiance grants 10 party Guard (was 14) and deals 4 (was 6). Their + versions scale accordingly.: Paladin's strongest pack-control tools are less overwhelming: Holy Freeze deals less damage and applies one Freeze, while Defiance grants less party Guard and deals less damage. The tools remain powerful, but enemy packs have more room to answer them.
  • Six new runewords give every class a play-pattern lane: Fury (barbarian), Harmony (amazon), Beast (druid), Venom (assassin), Destruction (sorceress), Famine (warlock). Pyrostaff now rewards spell cadence instead of hoarded energy.: Six new socketable runewords each build toward a class's core card cadence — Fury rewards the barbarian's every-other Attack, Harmony and Venom pay off the amazon's and assassin's third Attack, Beast reinforces the druid's first summon each turn, and Destruction and Famine detonate on the sorceress's and warlock's third Spell. Pyrostaff also switches its finisher from "unspent Energy at turn end" to "your third Spell each turn," so it now rewards active spellcasting instead of holding Energy back.
  • Runeword hunting is a real gamble again: rune drops are biased less heavily toward your target, and bosses only guarantee a rune from act 3 onward while you have an active runeword project.: Rune drops still lean toward the runeword you are hunting, but far less heavily, and the free rune every boss and miniboss used to hand over is gone — only act 3+ bosses still pity-drop one, and only while you have an unfinished runeword project. Completing a runeword should now feel like winning a directed gamble rather than collecting a delivery.
  • Paying life for power now has its own sound, and overlapping combat sounds resolve by priority (ROG-1195): Life-for-power effects now have their own audible cue, making a costly play easier to recognize in a busy turn. Combat sounds also resolve by priority so the most important feedback is less likely to be buried by overlap.
  • Sixteen signature skills gain hand-crafted rank-5 upgrades that change how they play (ROG-1219).: Investing 5 skill ranks into one of sixteen class-signature skills (two per class — your starter identity cards and their closest partner) now upgrades that card into a hand-crafted rank-5 version with a real rule change, not just a bigger number: Barbarian's Bash spends banked Rage for bonus damage, Necromancer's Raise Skeleton reforms your last fallen minion, and so on across every class. This was fleet-tested and comes back stronger overall with no downside to how winnable runs are, so it's on by default.
  • Town arrivals now rotate through fresh narration each run (ROG-1196): Arriving in town now rotates through fresh narration instead of repeating one welcome every run. The safer moments between fights should feel less mechanical without getting in the way of play.
  • Four new large charms offer real trade-offs — power now, paid for in blood or ceiling (ROG-1208): Four new large charms offer stronger immediate effects with a real cost, asking you to trade life or capacity for power. They create more interesting loadout decisions than pure upgrades.
  • 48 skills reconnect to their tree ranks — investing points now empowers every card it should (ROG-1217): Investing in 48 skills now improves the cards those tree ranks promise to support. Skill points more reliably translate into visible build growth instead of silently missing part of their intended payoff.
  • Warlock's trees gain evolution paths and planning depth to match the roster (ROG-1216): Warlock's three trees now have fuller evolution paths and clearer decisions that match the rest of the roster. Building around a Warlock specialization should feel more deliberate from early picks through capstones.
  • Zone environments shape exploration flavor again — moors, tombs, jungles and hellscapes each read differently (ROG-1198): Exploration event flavor text now varies by where you actually are — a forge, shrine, or trader you meet in the moors of Act 1 reads differently than the same encounter deep in an Act 4 hellscape or an Act 5 ice cavern. This had quietly stopped working for nearly every zone after an earlier zone-title revert; it's fixed now, and rename-proof going forward.

Balance

  • Stealth runeword power reduced: The Stealth runeword's power has been reduced — less bonus max life, and it no longer buffs your max energy. Fleet A/B testing confirmed the trim is win-rate safe (95% vs 97.5% untrimmed) while raising resource pressure, so it now reads as an accessible enabler rather than an easy power spike. With this change, both Stealth and Steel have had their enabler-trim numbers baked in permanently, and the __runeword_enabler_trim__ sim A/B lever used to tune them has been retired.

Content

  • The world fully speaks its own names now — every boss, zone, and lore entry uses Blood Rogue canon: Blood Rogue now uses one consistent vocabulary across the game: enemy names, zones, story, and lore all refer to the same world. This removes leftover imported names that made the setting feel stitched together and makes discoveries easier to recognize wherever they appear.
  • Every recurring story beat now varies across runs, and your class has its own voice (ROG-1210): Recurring story moments now rotate instead of repeating the same line every run, and many gain a class-flavored variation. Town arrivals, transitions, and other familiar beats should feel more like part of the current character's journey.

UI

  • Enemy intent chips use the styled tooltip (hover, keyboard focus, and touch) instead of the native browser title, and intent threat colors are keyed to the intent kind.: Enemy intent chips now explain themselves through the game's tooltip system on hover, keyboard focus, and touch, rather than a browser-native title. Their threat colors also reflect the actual intent kind, making the next move easier to read quickly.
  • Buttons show a distinct focus ring for keyboard users, separate from hover.: Keyboard focus has a distinct visible ring, separate from hover styling. It is easier to see where the next keypress will land without changing how pointer users read buttons.

Fixes

  • Made Autopilot interruption reliable and simplified Battle Arena setup on phones.: Pause and Stop now cancel queued Autopilot work before it can take another combat, route, reward, or town action, and Stop remains authoritative if the HUD redraws. Battle Arena setup is also more compact and readable on phones, with one progress model and the first real choice visible sooner.
  • Ascension ladder tier picks and hero-rail preview clicks no longer rebuild the whole screen — the ladder keeps its scroll position and keyboard focus, and the rail no longer flashes/re-decodes portraits.: Tapping a rung in the Rifts (ascension) ladder, or clicking through hero portraits on the bloodline-select rail, used to rebuild the entire character-select screen on every click. That reset the ladder's own scroll position (later tiers scrolled back out of view right after being tapped) and dropped keyboard focus out of both controls. Both now update only the piece of the screen that changed, so the ladder stays scrolled where you left it, the hero rail keeps its scroll position, and focus stays on the control you just used.
  • An invalid gear drag now shows why it was rejected (wrong slot, pack full, etc.) instead of only shaking.: When a drag-and-drop gear action cannot happen, the game now says why—such as an incompatible slot or a full pack—instead of only shaking the item. That turns a confusing failed gesture into a clear next step.
  • The vault and pack Discard button now requires a confirm click (Really discard?) before permanently destroying an item, and is styled as destructive.: Discarding an item from the vault or field pack used to destroy it permanently on a single click, styled identically to safe moves like Withdraw to Pack or To Stash. Discard is now visually marked as destructive and requires a second "Really discard?" confirm click (with a Cancel option) before the item is actually gone — protecting the between-runs vault from the costliest possible misclick.
  • Hovering an item in the pack or on the paper doll shows its stat tooltip again — the preview was built but never wired to appear.: Item tooltips are reachable again from both pack and equipped slots, so you can inspect stats without opening another surface. The existing preview data now appears where players expect it.
  • Merchant portraits no longer show the fallback sigil bleeding behind a loaded portrait (a CSP-blocked inline handler is now a CSP-safe load listener).: Loaded merchant portraits now stand on their own instead of showing a fallback sigil behind them. The image fallback uses a CSP-safe listener, so stricter browser security no longer leaves the visual artifact behind.
  • Scroll-map toggle, act-transition scroll overlay, and loadout-candidate switches now patch in place instead of forcing a full app-shell re-render, preserving scroll/focus.: Changing the scroll map, act-transition scroll, or loadout candidate source now updates only the affected surface. Your scroll position and keyboard focus stay put instead of the entire app visibly rebuilding.
  • Run-end summary charts (floor gauges, sparklines, power/trend lines) render again — a stray tag rename had left them blank.: Run-end floor gauges, sparklines, and power/trend charts render again, so the summary once more explains how the run developed instead of leaving its analysis area blank.
  • Vendor Buy tab now splits equipment vs rune stock by item data, so no purchasable item can silently vanish when preview copy changes.: Vendor stock now separates equipment from runes using the item data itself, so a purchasable item cannot disappear just because its preview copy changes. Shopping inventory stays complete and predictably categorized.

Operations

  • Bump db-backup and release-kit for the pkg-18 shared-package convergence: No player-facing change. Updates the shared @andrewpopov/db-backup (v0.17.1 -> v0.18.0) and @andrewpopov/release-kit (v0.1.0 -> v0.1.3) dependencies to their latest additive releases as part of the cross-repo package convergence.
  • Add the Summit Wardens' "Sigil of the Ancients" relic behind a default-off probe (not yet obtainable): Internal/measurement only. Adds a Wardens-exclusive grand charm — "Sigil of the Ancients" (combat start: +12 Guard; every 4th turn: recover 10 Life and deal 8 magic damage to all enemies) — as a guaranteed drop from the Summit Wardens, gated behind the wardenRelicEnabled probe (default OFF) and the warden-relic sim arm. The charm is poolExcluded, so it never enters the random reward pool for any class and cannot be obtained in normal play until the probe is promoted. This lands the ROG-1182 lever-#1 instrument so the fleet can measure whether a commensurate visible reward makes the (optional, brutal) Wardens worth taking. No change to shipped gameplay.
  • Sim-pilot routing fix — the pilot no longer force-feeds itself optional superbosses. No player-facing change.: The sim pilot was a completionist: it cleared every reachable non-boss zone before the act boss was even a candidate, so it walked into the optional Summit Wardens every single run and died there. That one encounter caused roughly 70% of all run losses and contaminated every winnability number in the corpus — most of what looked like class imbalance was this routing artifact. The optional-miniboss readiness floor now defaults to 1.25 (was 0 = off), calibrated on 8 classes × 150 CRN-paired seeds: barbarian 68.7% → 96.7%, necromancer 58.0% → 86.7%, and nothing regresses. Both neighbouring values are worse — 0.9 still lets barbarian walk into the Wardens, and 1.5 over-skips and costs necromancer 7.4pp of forfeited miniboss rewards. Internal only: this changes how the *simulator* routes, not the game. It does fork the comparabilityKey, so winnability numbers measured before this commit are not comparable to ones measured after it — the corpus needs re-baselining.
  • Sim wall detector: every winnability read now reports per-encounter loss share; no player-facing change.: Internal balance-tooling only; no gameplay, RNG, or persistence change. Every LOCAL seed-winnability read now reports which encounter each run died in, and raises a WALL warning when a single encounter accounts for more than 40% of a class's trusted losses (gated on the Wilson lower bound, so tiny samples cannot trip it) — scripts/run-loss-site-report.js runs the same detector over any existing Postgres slice. (Fleet-sharded corpora needed a follow-up, ROG-1188, to get the same warning — see that patch note.) This closes the blind spot behind ROG-1186: the sim pilot force-took the OPTIONAL Summit Wardens every run and died there — 57 of 91 roster losses (63%) — which silently depressed every winnability number we balanced against. Also reworded a comment in sim-encounter-runner.ts that false-positived the engine-mirror ratchet and had been failing npm test on master.
  • Sim wall detector now fires on the fleet path too; fleetctl status/pooled report are the new default way to read fleet results.: Internal balance-tooling only; no gameplay, RNG, or persistence change. The ROG-1187 wall detector (warns when one encounter causes more than 40% of a class's trusted losses) was structurally inert on the fleet path: fleet experiments shard at 2 seeds/shard, each shard runs in its own process/accumulator, and the detector needs at least 3 concentrated losses to clear its Wilson gate — a 2-seed shard can produce at most 2. fleetctl-pg.js status --experiment <id> (the command every agent/doc already runs to watch a fleet experiment) and run-seed-winnability-pooled-report.js --experiment <id>/--seed-salt <salt> now run the same detector scoped to one fleet corpus and print it next to the per-class win rates it would invalidate. Both prefer the fleet_experiment_id provenance column stamped by the fleet ingest (server-side, authoritative); pre-migration or --crn-salt-collided corpora fall back to a seed_salt join and say so explicitly rather than silently guessing. docs/fleet/FLEET-GUIDE.md and the balance-master skill now point at these commands as the default way to read fleet results — a raw psql read has no channel to print a warning at all, so it stays an escape hatch for ad-hoc exploration, not the documented read path.
  • Consolidate the three hardcoded named-boss drops into one data-driven loot-table system (no player-facing change): Internal/refactor only. Replaces three parallel hardcoded drop hacks — Countess -> rune, Nihlathak -> Anya's Scarf, and the Summit Wardens -> Sigil of the Ancients (the ROG-1182 probe) — with a single data-driven LOOT_TABLES keyed on a bossId now stamped on miniboss enemy templates (never string-parsed, so it can't rot on a zone/display rename like ROG-1204 did). Adding a boss's exclusive loot is now a table row. Countess and Nihlathak drops are byte-identical to before; the Sigil stays behind its default-off wardenRelicEnabled probe (it now arrives as a main reward choice rather than a follow-up-cache choice — invisible until the probe is promoted). Fail-loud validation rejects a typo'd loot key at catalog load. No change to shipped gameplay.
  • Internal sim margin/dominance telemetry (hero/merc life-floor, potions, turns); no player-facing change.: Adds per-seed margin telemetry to the winnability sim — hero-life floor, mercenary-life floor, potions used, and turns — surfaced through the sim report and the fleet history row. Purely observational (it only reads combat life values via a shared sampler after every turn-advance path; no gameplay, RNG, or persistence change), so it lets the fleet measure how dominant a build is when winnability WR is ceiling-blind (both arms ~99%) — e.g. the ROG-779 stealth over-power question and future over-mitigation A/Bs.
  • Sim Lab runs list distinguishes concurrent fleet experiments: Dev tooling: the Sim Lab runs list now keys each row on its fleet experiment scope, so two concurrent experiments on the same commit appear as separate rows with their own labels and detail views instead of pooling into one. Balance reads (CRN pair reports, pooled winnability, sim-tools) are experiment-scoped the same way. No player-facing gameplay change.
  • Fleet submit rejects capability-mismatched runner flags loudly: Fleet infra: the sim-fleet flag-emission contract is now capability-honest — the daemon never emits a flag a runner can't parse, and a submitter-intent flag set for a runner that doesn't support it (arms/specs/through-act/throughput-mode/arm-filter/main-realm/decision-sweep) is rejected loudly at submit (both CLI and the HTTP API) and, as a backstop against direct-queue insertion, terminated cleanly at the worker instead of silently dropped. No player-facing change.

Angel Snack 0.1.0-alpha.13 Patch Notes

Release date: 2026-07-13

Stage: alpha

Package version: 0.1.0-alpha.13

These notes are gathered from the release fragments in docs/patch-notes/unreleased/.

Fixes

  • Keep End Turn visible on portrait combat without covering battlefield controls.: Portrait combat keeps the turn-ending control reachable while preserving access to the battlefield.
  • Keep rotated phones in a readable responsive layout instead of shrinking controls below the usable size floor.: Rotated-phone layouts preserve readable controls instead of compressing them below a usable size.
  • Keep the sign-in action visible when guest play is closed.: When guest play is unavailable, the front door now keeps the sign-in action beside the explanation instead of leaving it below the cover.
  • Give Sim Lab jobs collision-resistant IDs and bound captured JSON output.: Sim Lab safely retains useful job results without allowing oversized output to consume unbounded memory.
  • Keep timeout and underplay exclusions mutually exclusive across simulator result views.: Sim Lab run summaries now use consistent exclusion counts across list and detail views.
  • Reject forged or stale Sim Lab balance-profile selections before launch.: Sim Lab validates the currently available balance profile before creating a job.

Tech

  • Sim-only oracle answers whether a run that died in an optional side zone would have finished the game had the pilot skipped it — default-off, no change to shipped routing.: The oracle reruns an identical seed with its fatal optional side zone banned, making routing artifacts measurable without changing normal simulation behavior.
  • Hardened the ascension affix-scaling implementation for release validation.: Improved the reliability of the optional high-tier ascension balance probe without changing its default behavior.

Balance

  • Steel runeword power reduced: The Steel runeword's power has been reduced — less bonus damage, and it no longer buffs your mercenary's attack. It's still a solid early-game option, but reads as an accessible enabler rather than an easy power spike.

Angel Snack 0.1.0-alpha.12 Patch Notes

Release date: 2026-07-12

Stage: alpha

Package version: 0.1.0-alpha.12

These notes are gathered from the release fragments in docs/patch-notes/unreleased/.

Fixes

  • Keep launcher position restoration compatible with lightweight shell roots.: The saved bug-report button position now restores only when the active shell exposes a real queryable DOM root, avoiding noisy failures in lightweight render surfaces.

Angel Snack 0.1.0-alpha.11 Patch Notes

Release date: 2026-07-12

Stage: alpha

Package version: 0.1.0-alpha.11

These notes are gathered from the release fragments in docs/patch-notes/unreleased/.

Operations

  • Keep deploy lint scoped to the checkout being deployed.: Production validation now lints only the checkout being deployed, so unrelated sibling worktrees cannot block or contaminate a release.

Angel Snack 0.1.0-alpha.10 Patch Notes

Release date: 2026-07-12

Stage: alpha

Package version: 0.1.0-alpha.10

These notes are gathered from the release fragments in docs/patch-notes/unreleased/.

Balance

  • Barbarian's sim pilot no longer skips its own Blood Rite life-to-Rage engine — a scorer mispricing fix is now the shipped default: Barbarian's Blood Rite ("Lose 4 life, gain 4 Rage") was being priced by the sim pilot's static card-sorting heuristic as plain self-damage instead of the life-to-Rage conversion it actually is, which could make the pilot skip or under-value its own signature engine. The corrected weight — previously an opt-in A/B lever — is now barbarian's unconditional default. A fleet A/B on the correction showed win rate holding steady (non-inferior) with no shift in barbarian's skill-progression ladder. No other class is affected.

Tech

  • Keep movable bug-report launcher behavior within the UI module-size safety limit.: The movable bug-report button retains its saved-position behavior while its drag handling now lives in a focused, independently bounded UI module.

Angel Snack 0.1.0-alpha.9 Patch Notes

Release date: 2026-07-12

Stage: alpha

Package version: 0.1.0-alpha.9

These notes are gathered from the release fragments in docs/patch-notes/unreleased/.

Fixes

  • Restore the movable bug-report launcher position without dynamic HTML interpolation.: Saved bug-report button positions continue to restore correctly while keeping the launcher markup safe and compatible with the production security gate.

Operations

  • Internal-only sim lever to A/B a steel/stealth runeword stat trim; no player-facing change.: Adds a default-off __runeword_enabler_trim__ sim probe that, when armed on the fleet, resolves the steel and stealth runewords with reduced enabler-band stat bonuses (steel dmg 6→3 / drop merc-attack; stealth life 8→5, guard 3→2 / drop max-energy) through the shared runeword-bonus resolver — so both combat and the pilot's item valuation see the trimmed stats. Byte-identical when the probe is off (the real-player default), so there is no gameplay change; it exists solely to fleet-A/B the ROG-779 easy-and-strong runeword trim before deciding whether to bake it in.

Angel Snack 0.1.0-alpha.8 Patch Notes

Release date: 2026-07-12

Stage: alpha

Package version: 0.1.0-alpha.8

These notes are gathered from the release fragments in docs/patch-notes/unreleased/.

Gameplay

  • The Daily Challenge is now playable from the front door — one seed, one attempt, everybody on the same board.: A new 🏆 Daily Challenge button on the title screen opens the ranked lobby. Every player of a class runs the exact same seed for the period, so the board is a real comparison rather than a race for a lucky roll. Pick your class, switch between the Daily and Weekly boards, and see the current top runs before you commit. You get one attempt per board, per period, and starting the run consumes it — so the lobby says so plainly before you begin, and shows you how long is left until the board resets. If you have already run today's board, the lobby tells you where you landed instead of offering a second attempt. A run still in progress can be resumed from here. Abandoning a ranked run now warns you that it forfeits that attempt, rather than quietly throwing it away behind the usual "abandon your run" prompt.
  • Ranked runs now show a RANKED badge in combat and a scored result panel when the run ends.: While a ranked run is in progress the combat header carries a RANKED · Daily (or Weekly) marker, so it's always clear which board you're spending your attempt on. When the run ends — win or lose — a Ranked Result panel shows your score straight away. The score is final the moment the run is over; it's worked out from how far you got, and nothing about it is up for revision. What takes a moment is your *place* on the board: the server re-runs your game to confirm it. Until that finishes the panel shows where you're projected to land ("Projected #7 of 23") and quietly firms up to a verified rank while you watch. If confirmation is taking unusually long, the panel tells you your run is safe and to check the board later rather than spinning forever. Fall in Act 3 and your score still posts. Finish first on an empty board and it says so.
  • The in-run "Abandon Run" menu option now actually works (and warns before forfeiting a ranked attempt).: Choosing "Abandon Run" from the in-game menu used to do nothing — it set a flag that only the title screen knew how to draw, so mid-run the click just silently failed. It now shows a proper confirm right there in the menu, with Keep Run / Abandon Run buttons. For a ranked run it spells out the consequence first: abandoning forfeits your one attempt on that board until it resets.
  • The Daily Challenge no longer quietly throws away another run, and it confirms your rank against the right board.: Beginning a Daily or Weekly Challenge used to overwrite whatever run you had going, without asking. If that run was another ranked attempt, it was gone for good — you only get one per board. Now the game asks first, and says plainly what you'd lose. "Resume your ranked run" now only appears for the run you're actually looking at. Before, an Amazon Daily lobby would happily offer to resume a Warlock Weekly attempt — or an ordinary expedition — and clicking it took you somewhere you didn't mean to go. And when a challenge board rolls over while you're finishing a run, your result is now checked against the board you actually played, instead of the new one that just opened.
  • View Board" from a finished ranked run now opens the board you actually played, even after it resets.: If a ranked board rolled over (a new day or week started) between finishing your run and tapping "View Board" on the results screen, it used to open the fresh, empty board where your run doesn't appear. It now opens the board you actually competed on, with your run on it. As soon as you switch class or cadence on that screen, it goes back to showing the current board.
  • Starting a Daily Challenge and then quickly switching to another run can no longer abandon the wrong one.: There was a narrow timing window where starting a ranked run, then immediately leaving and resuming a different run before the server responded, could abandon the run you'd just gone back to and drop you into the ranked one instead. Now, if you've navigated away by the time the ranked run is ready to start, it simply doesn't — your current run is left exactly as it was.
  • Buffed two lagging act-5 builds — Amazon's Valkyrie/Passive summoner and the Assassin's Shadow discipline.: Two under-performing late-game builds get targeted help: Amazon "Valkyrie Vigil" (Passive): the Valkyrie's base strike power is raised (4 → 11), and while Passive Mastery is active your Amazon summons now pierce a little enemy Guard — so the summon-tank plan can actually close out act-5 fights instead of chipping against the Guard wall. Assassin Shadow — Shadow Crisis Guard: once you've played Shade Cloak, dropping to critically low life (or taking a hit that would) caps that incoming hit at 65% of its raw value. Shadow's glass-cannon frame no longer gets deleted outright by the act-5 Summit Wardens' simultaneous burst — it now has a fighting chance in the fights that used to be unwinnable, without softening its normal play.

Balance

  • Druid Shifter Bruiser's Guard over-generation is trimmed so final bosses can pose a real threat: Druid's Shifter Bruiser was piling up too much Guard from sources that never asked you to do anything for it. Werebear no longer grants the party a free 8 Guard on top of its own Guard, Slow, taunt, form-shift, and draw, and Oak Sage's chained Spirit Wolf no longer ticks 3 Guard every hero phase on top of the pack it already summons. Both cards keep everything else they did. A fleet A/B on this trim showed win rate holding steady (non-inferior) while removing the padding that was letting Druid shrug off even the final bosses.

UI

  • Bug reports now include sanitized diagnostics for faster alpha triage: Alpha bug reports now attach a safe snapshot of the current run, screen, build, and recent actions so crashes and stuck states are easier to reproduce without a follow-up.
  • Combat resource chips and the Autopilot controls stay legible when the game is scaled down.: The run resource chips, the combat header, and the Autopilot panel drew their text at sizes that shrank into the low single-digit pixels on a laptop screen. They now hold a readable size no matter how far the game is scaled to fit the window, and the Autopilot speed buttons match the Display Settings speed control they mirror.
  • The Field Log reads clearly — messages and the Close button are legible when scaled.: The open Field Log's messages and its Close button were drawn at a tiny size that shrank further on laptop screens. They now hold a readable size regardless of how far the game is scaled to fit, and the panel sizes to the game canvas instead of leaving a large empty gap below the log.
  • Settings controls are readable — available options no longer look disabled.: The Display Settings choices and toggles were drawn in a barely-visible faint tint, so an available option looked greyed-out until you selected it. They now use a readable label colour that stays clearly a step below the bright selected state, and the text holds a legible size when the game is scaled down to a laptop screen.
  • Inventory item names, stats, and tab labels are legible instead of tiny.: With the inventory's full height recovered, its meaningful text is enlarged to a readable size across every tab — item names and stats in the Pack, skill descriptions, attribute names and effects, and the tab labels themselves no longer shrink into unreadable single-digit pixels on a laptop screen. The Pack grid now scrolls internally so the larger labels never clip, and the hero portrait fills the recovered space.
  • The Inventory (and other overlays) no longer leave a large black gap on laptop screens.: Opening the Inventory on a scaled-down window used to leave a big empty band below the panel — the layout was sizing itself to the shrunken viewport and then getting shrunk again. It now fills the game canvas properly, so Loadout, Pack, Relics, Skill Tree, and Attributes get the full height they were meant to have. The same fix cleans up the gap under the Wiki, Training, Spellbook, and Merchant overlays.
  • A prev/next target strip with a live count when the enemy row is crowded.: When three or more enemies share the battlefield, a compact prev/next target strip now sits under the row with a live "which of how many" count, so switching targets no longer means hunting across a horizontally-scrolling lane — and the same control works by pointer or keyboard. On phones the hand also fades at its edges to show there are more cards to scroll to.
  • Pick and switch enemy targets from the keyboard, with the choice announced.: Combat targeting is now fully keyboard-operable. Tab lands on the current target (or the first enemy), the Left/Right arrows move between enemies, Home/End jump to the ends, and Escape drops the target — each change is announced for screen readers with the enemy's intent and remaining life. Playing a numbered card keeps focus on your target so you can keep acting without reaching for the mouse.
  • Full-screen overlays now fully hide the game behind them from keyboard and screen readers.: When a story, arrival, or boss overlay is open, everything behind it is now removed from the keyboard tab order and the screen-reader tree, so focus and narration stay on the one surface you are meant to be reading. The full-screen cinematics — cold-open, town arrival, boss threshold, act guide — are now proper modal dialogs, and Escape can no longer reach a control hidden behind them, while a dialog's own click-anywhere backdrop still dismisses it. On the hero-select screen, only the visible face of a hero card — portrait or campfire reading — is reachable now, so the hidden side no longer clutters keyboard and screen-reader navigation. The same isolation backs every modal in the game, built on the existing overlay focus system rather than a parallel one.
  • Charm reward cards now spell out pouch capacity instead of an orphaned "Fits" label: Charm reward cards used to show a bare "Fits" label and a plain "N slot(s)" badge with no sense of how full your pouch already was. The fit note and slot badge now say the slot cost, how many slots are free, and your used/capacity count — for example "Fits your pouch · uses 2 slots of 4 free (8/12 filled)" or "Needs 3 slots · 10/12 filled — make room to take it" — matching the numeric language the charm pouch overlay already uses. The onboarding tutorial's charm-intro step was also corrected: charms occupy a pouch slot (per the ROG-906 slot-budget system), so the old "no pouch slot required" line was stale and is now accurate.
  • The cover now tells you which account mode "Begin/New Expedition" will start in.: The cover's main "Begin Expedition" / "New Expedition" button always started a run without asking, but it wasn't clear whether that meant playing as a guest or continuing your signed-in account. A short note under the button now says which one it is, and the "Continue as Guest" option is retitled "Keep playing as a guest" to read as the secondary choice it always was.
  • The first-camp walkthrough no longer appears inside Veyra or tells you to recruit a mercenary you already hired.: The first-run camp walkthrough now begins the moment you enter town and its beats follow one another in order, holding your input until each is dismissed — so town actions can't slip in between them. The walkthrough can no longer pop up inside the Mercenary Captain's window right after you hired someone and insist you still need to recruit. It's also trimmed to what you can actually do on a first visit — recovery, mercenary, and heading out — and the Blacksmith, Vendor, and Stash now introduce themselves the first time you open them, instead of all at once up front.
  • Internal onboarding-engine groundwork (no visible change yet).: Laid the groundwork in the tutorial engine for smarter onboarding: steps can now declare themselves irrelevant for the current run/profile state, a session snapshots its relevant steps up front so it can't desync mid-session, and the engine can notify listeners when a tutorial session ends. No tutorial content uses any of this yet, so nothing changes for players in this release.
  • The ranked result screen no longer claims a rank or a posting it hasn't confirmed.: The run-end ranked panel was occasionally getting ahead of itself. It could show an impossible projected rank (worse than the whole field), call an unverified run "first on the board", say "score posted" before the server had acknowledged the run, and promise "your run is safe" even when it had never reached the server. The score itself was always fine — it's computed locally and final the moment the run ends — but the rank and the "we have your run" messages now wait until the server actually confirms them. A projected rank is always drawn from a field that includes your own run, so it can never read as "#24 of 23"; "first on the board" is reserved for a verified #1; and if verification can't reach the server, the panel says your score is saved locally rather than promising it's safely posted.

Fixes

  • Keep the bug-report launcher visible, separate from the mute badge, and draggable to a saved screen position.: The floating bug-report button now stays available after the report dialog closes, starts above the muted-sound badge, and can be dragged to a preferred position that is restored on the next visit.
  • The first-run walkthrough now blocks keyboard and screen-reader input, not just mouse clicks.: A blocking step in the opening town walkthrough dimmed the screen and refused mouse clicks, but a keyboard user could still tab straight to a town NPC and act mid-walkthrough. Blocking steps are now true modals: the rest of the screen is removed from keyboard and assistive-technology focus while the step is up, and focus returns to where it was once you continue.
  • Fixed overlays like Feedback leaving the game frozen behind them after closing.: Closing an overlay that patches in place (Feedback, and any similar surface that removes itself without a full screen re-render) could leave the game behind it unresponsive to clicks and keyboard input. The background is now correctly un-frozen the moment the overlay closes.
  • Hovering (or tabbing to) an enemy's trait badge now shows what it does.: Enemy trait/affix badges on the battlefield sprite carried a hover tooltip that never actually appeared — you had to open the enemy inspect panel to learn what a trait like Frenzy or Cursed does. Hovering, or tabbing to, the badge now shows its name, "Trait," and a plain description right on the battlefield, matching the inspect panel's tooltip.
  • Front-door copy no longer calls a device-local start "a guest," and the guest button doesn't claim a brand-new visitor is "keeping" a session that never existed.: The signed-out front door said the primary "Begin/New Expedition" button "starts as a guest," but that button never talks to the server at all — it's a device-local start with no account, distinct from the separate "Continue as Guest" button that really does create a server-backed guest account. The note now says what actually happens ("Starts on this device — no account needed."). The guest button itself said "Keep playing as a guest" even for a visitor who had never played anything; it now only says that when there's existing local progress on the device for the new guest session to carry forward, and offers a fresh-start phrasing otherwise.
  • Field Log entries no longer overlap when the panel is full.: Opening the Field Log with a long history no longer squeezes every entry into a sliver and spills its text across neighbouring rows. Each entry now sizes to its own content and the panel scrolls as one clean list, so the log stays readable at laptop and phone widths alike.
  • On phones, the Field Log opens on-screen and the hero status chip stops clipping.: In portrait, the Field Log used to open centered below the bottom of the screen (you had to scroll to find it), and the hero's status chip in the top bar cut off its text. Both are fixed: overlays now anchor to the actual screen on narrow layouts, and the status chip sizes to its content.
  • Cover, character select, rewards, and the world map now fit phones and portrait tablets.: The out-of-combat screens now reflow to the screen you are on instead of clipping or shrinking to an unreadable size. On phones the sign-in row no longer covers the menu, hero selection keeps Back, Builds, and Commit on screen, reward choices and their confirm button stack into one readable column, and the world map fills the height with room to pan rather than crushing every stop into one corner. Portrait tablets that used to snap to a tiny zoomed-out canvas now use the readable phone layout instead, so controls stay large enough to tap across the whole range.

Tech

  • Harden database restores and discard corrupt backup snapshots.: Bumped @andrewpopov/db-backup to v0.13.1. Two fixes land with it: restoreBackup now takes the advisory lock (so a scheduled backup or prune can no longer race a restore mid-rename — rouge's db:backup:restore goes through the package CLI, so it gains this), and a corrupt snapshot is now discarded rather than left in the backup directory under a valid name, where it could occupy a retention slot and evict a good backup.
  • Added a server-issued, signed, single-use ranked seed mint endpoint (no player-visible change yet).: Ranked runs will soon use a seed the server mints and signs rather than one the client picks, so a player can no longer seed-fish or replay a favorable seed. This step adds the minting side only: a new POST /api/ranked/seed endpoint that authenticates the caller, generates a cryptographically random seed and nonce, stamps the current engine version, persists the token, and returns an HMAC-signed, time-limited token. Consuming the token at run submission and wiring the client to request it land in follow-up steps — nothing player-facing changes yet.
  • Added the server-side loader that reassembles and validates a sealed ranked submission's input log (no player-visible change yet).: First step of the ranked replay-verify worker: a new server module reads a sealed ranked submission's stored segments, reassembles them into the full ordered event log, and gates on chain integrity (a recomputed hash chain must match what was sealed), stored-hash agreement between the submission and its seed token, log length, and engine-version parity with the current build. It also extracts the trusted seed/class/mode from the seed token and the claimed run outcome from the terminal event. This step only loads and validates — actually re-simulating the run through the game engine to compare outcomes lands in a follow-up step.
  • Ranked runs are now version-gated on a verifierHash covering the full replay surface, so a re-sim can never be judged against a different engine build (no player-visible change).: The ranked replay-verify version gate previously compared a run's sim comparabilityKey (content + scorer + combat/sim/run/rewards behavior). But a ranked replay dispatches recorded events through the real production action-dispatcher, which also drives app/UI/state/town/items/meta/character/content code — a change there could alter a replayed outcome without forking the key. Ranked seed tokens now carry a verifierHash covering the entire replay surface (all of generated/src + the compiled replay-harness helpers + the seed JSON the harness loads at startup), stamped at mint and cross-checked at seal. The verifier gates on it: a run whose verifierHash doesn't match the current build (including pre-upgrade tokens that lack one) is flagged as version-skew and never silently ranked, instead of being re-simulated against an engine the player never ran. Multi-version pinned re-sim (verifying old runs against their original build) remains deferred infrastructure.
  • Content-manifest startup preflight no longer bricks dev/test/clean-checkout servers (fatal only in production).: The ROG-1060 content-manifest startup preflight used to throw whenever generated/content-manifest.json was missing or stale — but that file is a npm run build artifact that npm test/pretest never generate, so a clean checkout, a fresh worktree, or CI would fail every server-spawning test with "Missing content-manifest.json". The preflight now degrades gracefully: in production a missing or stale manifest is still FATAL (the server refuses to start until npm run build regenerates it), but in dev/test it logs a one-line warning and returns a "manifest unavailable" status instead of throwing. When the manifest is unavailable the shadow-mode profile state validator is simply not wired, so profile saves still work (the shadow validator was logging-only anyway). No player-facing change.
  • Ranked runs now start from a canonical, account-independent state so the server's replay-verifier can reproduce them (foundation for comparable ranked scores).: A ranked run's construction-time state is now a pure function of {classId, seed, mode} with no account-derived input: it uses a fixed canonical mercenary (not the player's selected one), an empty canonical profile view (no account charm/potion unlocks, no tree-access from account progress), and clamps ascension against that canonical view. This is the same view the W4 replay-verifier reconstructs from an empty profile, so honest ranked runs stop false-mismatching in shadow — the foundation for comparable ranked scores (W7e daily/shared seeds) and a real leaderboard. Casual, arena, and puzzle runs are unchanged (the canonicalization is gated on ranked mode). A single production module (ranked-run-canonical) is the one source of the canonical view, used by both the ranked start and the replay driver so they can never diverge. This is Phase 1 (construction-snapshot pools + mercenary + ascension); later phases canonicalize the live per-decision reads (card rewards, economy/loot/town). Part of ROG-1082 / W7.
  • The default-OFF sim focus-fire gradient now brace-gates its kill-proximity bonus under a telegraphed alpha strike, fixing an amazon burst-death regression found in fleet A/B.: Sim-pilot only; no player-facing change (the __focus_fire_gradient__ probe is never set in production, so the shipped pilot stays byte-identical). A fleet A/B of the focus-fire gradient found it reduced Summit-Wardens losses for 5/6 classes but regressed amazon via a rare tail of 4-turn burst deaths — the pilot chased the kill-gradient instead of building guard against a telegraphed alpha strike. The kill_proximity state-delta bonus now attenuates to a brace fraction when a heavy single hit is telegraphed (≥50% of hero maxLife) and incoming is unblocked (guardGap > 0), so a needed guard/heal play outranks it. Reuses the existing heavyIncomingMultiplier/guardGap survival signals; efficacy re-validated via a higher-N fleet A/B. Part of ROG-1086.
  • Arena write endpoints now reject blocked users (not just unsigned requests), closing a balance-data / public-board pollution hole.: The /api/arena/record and /api/arena/run-summary write endpoints previously accepted any request with a valid token signature — they skipped the account block check that run-complete telemetry already does. A blocked user could therefore keep writing arena balance rows and user run-summaries (a public-board source). Both handlers now route through the same unified resolveIdentity path: a blocked account gets a 403 (and an audit log entry), and anonymous visitor cookies / no-identity requests get a 401 — arena writes require a real signed-in account. Part of W7 (ranked ops & anti-cheat second layer).
  • Ranked seed issuance now caps how many live seed tokens one account can hold at once, closing a seed-farming avenue.: The ranked seed-mint endpoint was already rate-limited per IP (velocity), but over a token's 3-hour lifetime an account could still accumulate a large pool of unconsumed seeds and cherry- pick favorable ones (seed farming). Minting now rejects with 429 once an account holds the maximum number of outstanding (unconsumed, unexpired) seed tokens — 16 by default, env-tunable via ROGUE_RANKED_ACTIVE_TOKEN_MAX. Consuming or letting a seed expire frees a slot. A real player holds one or two at a time, so this is invisible in normal play. Part of W7 (ROG-1061).
  • Hardened the run-complete and arena run-summary write endpoints — body cap, rate limit, and idempotent run-summary submits.: Three abuse-surface closures on the telemetry/arena write paths (W7 / ROG-1061): run-complete body cap — the endpoint now caps its request body at 1 MB (was inheriting the 5 MB global default), matching the other authenticated writes. run-complete rate limit — added a per-IP limiter (60/min, env-tunable) so the endpoint can't be flooded; a real finished run posts far below this, and the existing per-visitor DB cap + idempotency already bound the rest. arena run-summary idempotency/api/arena/run-summary now accepts an optional client_summary_id; a replay with the same key on the same profile is deduped to the original row (returns it, idempotent: true) instead of inserting a second public-board entry. Keyless submits behave exactly as before. Backed by a nullable column + a UNIQUE(profile_id, client_summary_id) index on the balance DB.
  • The ranked input log now captures a per-decision timestamp (outside the integrity hash) to feed future human-plausibility checks.: Each recorded ranked input-log entry now carries a capture timestamp (t, ms). It is stamped on the entry itself, deliberately OUTSIDE the hash-chained canonical payload, so it never affects chain integrity or the server's replay/verify byte-parity — it just rides along as advisory metadata. This gives a later anomaly-detection pass the raw timing needed to spot implausibly fast inter-decision deltas (bot/TAS play). Capture only; the statistical detection itself is deferred. The clock is injectable for deterministic tests. Part of W7 (ROG-1061).
  • Rate limiting and IP logging now key on a non-spoofable client IP, closing an X-Forwarded-For bypass.: Per-IP rate limits and visit-IP logging previously trusted the first hop of the X-Forwarded-For header — which is attacker-controlled (a client can send its own XFF and Cloudflare/cloudflared only appends to it), so anyone could forge or rotate their apparent IP and slip past every per-IP limit. Both paths now resolve the client IP from a trusted source in order: Cf-Connecting-Ip (set by Cloudflare's edge, which overwrites any client value, so it can't be forged) → the last X-Forwarded-For hop (edge-appended, not the client's injected leading hops) → the socket peer. The three duplicated IP-resolution helpers (rate limiting, visit logging, feedback logging) are unified into one, and rate limiting only exempts a genuine loopback *socket* with no proxy headers — never a header-derived loopback. Part of W7 (ROG-1061) ranked ops & anti-cheat hardening.
  • The ranked verify worker now pauses between re-simulations so it doesn't starve the game server on shared hardware.: Each ranked verification is a full run replay through the game engine — minutes of CPU. The shadow verify worker ran them back-to-back with no pause, which on a single Raspberry Pi (server + worker on the same core) could spike gameplay latency. The worker now pauses between items (default 250 ms, ROGUE_RANKED_VERIFY_PAUSE_MS) so requests that queued during a replay get served before the next one starts, and scans a smaller default batch (ROGUE_RANKED_VERIFY_MAX_BATCH, default 10). This is the software throttle; running the daemon niced or off-box remains a deploy-side choice. Part of W7 (ROG-1061); found by the fable anti-cheat design review.
  • Arena block-check no longer costs a DB lookup per row, and a blocked client can't amplify audit-log writes.: The blocked-user gate on arena writes did one DB lookup per submission (the highest-volume write path) and logged a "blocked attempt" per request — so a blocked client hammering the endpoint became a DB-write amplifier. Block status is now cached per account for a short TTL: one lookup per user per window instead of per row, and the blocked-attempt audit log fires only on a fresh (uncached) detection — at most once per window. A hard cap keeps the cache bounded. Part of W7 (ROG-1061); found by the fable anti-cheat design review.
  • Balance sim defaults now preserve class-grand identity, reject ambiguous multi-seed arguments, and treat alpha-readiness outputs as disposable current-run evidence.: Internal balance runs now keep a class-signature grand charm in every representative meta-build loadout, reject ambiguous space-separated seed lists instead of silently under-sampling, and require fresh alpha-readiness evidence from the current build. The Arena Training Dummy remains available as an endless build-testing target and is now represented intentionally in the canonical monster list.
  • Surface failed best-effort sim-context DB writes instead of silently swallowing them: Internal (Sim Lab) only, no gameplay impact. The sim-context DB write is best-effort: on failure it logged a console warning and carried on, so the Sim Lab could imply a job's provenance had been durably saved when it silently had not. The write now reports its outcome (durable / skipped / failed), which is recorded on the job metadata, returned by the sim API, and shown as a "provenance not saved" badge in the Sim Lab when the write failed.
  • Full Revalidation is now classified as a remote tool, since launching it with default settings runs the suite over SSH on another machine rather than locally.: The Sim Lab groups tools by blast radius. Full Revalidation was grouped with local jobs even though its default host is a remote machine and its launch command shells out over SSH, the same shape as the other remote suites. It now sits with the remote tools, and a test derives that expectation from the launch plan — any tool whose default command reaches another host must be classified remote — so the grouping can no longer drift away from what the tool actually does. The remote group is renamed from "Remote reads" to "Remote hosts", since several of its tools write on the machine they reach.
  • Sim Lab tool safety metadata is now server-owned so the Launch tab can no longer be blanked by catalog drift, and CLI diagnostics forward their arguments untouched.: The Sim Lab Launch tab grouped tools by blast radius using a hand-maintained client-side severity map, which had drifted nine tools behind the server catalog; because the grouping filter looked up every tool, one missing entry threw and blanked the whole tab. Severity now lives on the tool catalog itself, is projected through the API, and an unclassified tool renders into the production-writes group tagged "Unclassified" rather than throwing. The sim front door also parsed diagnostic arguments into an object and rebuilt them, which silently dropped positional arguments and short flags, collapsed repeated flags, and rewrote digit-bearing flags such as --top-5. Diagnostics now receive their argument tokens exactly as typed. Commands remain argument arrays; nothing passes through a shell.
  • Launching a production-write sim tool now requires an explicit confirmation on the server, so the typed confirmation is a real gate rather than a prompt the interface draws.: The Sim Lab asks you to type PROD before it runs a tool that writes to production, but that prompt lived entirely in the browser: a request sent directly to the run endpoint started the job without it. The endpoint now derives the tool's blast radius from the server's own catalog and refuses to create the job unless the request carries the typed confirmation. The check sits at the single point where every sim job is created, ahead of any file or scheduler work, so a rejected launch leaves nothing behind and any future caller inherits the gate. The confirmation must be a property the request itself carries, not one merely inherited from a prototype, and it is compared exactly — a truthy flag or a differently-cased word will not stand in for it. The token is never stored in the job's values, metadata, or logs.
  • The Sim Lab Runs view reported zero wins for every experiment and the runs report inflated win rates to 99%; both now agree with the dominance report on what a win is.: Three parts of the balance toolchain disagreed about which finished runs count as wins. The Runs detail view looked for an outcome the database never stores, so it showed no wins and a zero win rate for every experiment, even ones with tens of thousands of victories. The Runs list counted through-act checkpoints alongside full clears. The runs report treated a hero's death as an infrastructure failure and dropped it from the denominator, reporting a 99% win rate where the real figure was near 60%. All of them now resolve a win the way the dominance report already did: a full clear only, with through-act checkpoints excluded from both sides of the rate. The Runs view additionally applies the same trusted-loss rule the dominance report uses, so the two now print the same number, and the runs that were set aside — underplayed, timed out, or stopped at a checkpoint — are reported alongside rather than quietly dropped. The list also stopped labelling an eight-class sweep with one arbitrary class.
  • Decision-sliced forced-candidate harvests no longer poison the RG002 canonical when a slow/contended host hits the run wall-clock ceiling.: The forced-candidate EV harvest (ROG-1066/A decision-axis slicing) replays a full act-1→5 run while capturing ~1900–3000 restorable decision snapshots. Under fleet core-contention that harvest could exceed the simulator's 10-minute run wall-clock hang guard, which returned a "successful" empty harvest. That empty manifest (sha256 of the empty kept-list) skipped all rollouts, finished fastest, won RG002's first-writer race, and poisoned the canonical — so every legitimate full harvest of that seed was then RG002-rejected, holing the dataset across all classes. Two fixes: (C) a wall-clock-truncated harvest now FAILS the shard (throws → the daemon retries) instead of emitting an empty manifest, and the harvest's own wall-clock ceiling is raised to 90 minutes (explicit, so a stray ROUGE_SIM_RUN_WALL_MS can't change harvest results) — well above any legitimate harvest, well below the ~3.5h daemon watchdog. (B) RG002 now lets a real (non-empty) manifest atomically UPGRADE an empty canonical (safe — an empty canonical ingested zero rows), while still rejecting a genuinely-divergent full-vs-full mismatch, closing the race the read-then-update version had. No player-facing change.
  • The ranked leaderboard no longer shows a stale board or paints itself over the menu after you leave.: The ranked leaderboard screen had two async races (the same ones the Daily Challenge lobby was already fixed for — the lobby was written by copying this screen). Rapidly switching class back and forth while a slow request was in flight could let an out-of-date response overwrite the current one, and clicking "Back to menu" before the board finished loading could let the late response repaint the board over the menu. Both are now guarded by a request-sequence check, so only the newest load ever commits and a load abandoned by leaving the screen commits nothing.
  • The sim pilot can now route around an optional miniboss it isn't strong enough to win (opt-in miniboss-skip arm), removing the artifact where it auto-walked every class into the act-5 Summit Wardens.: The sim pilot scored every miniboss zone a flat 320, so it always routed into the OPTIONAL act-5 Summit Wardens (the hardest fight in the game — enemy-power ~3241, above the act-5 boss). A human skips it when under-geared; the pilot's exhaustive-clear made it the #1 loss for the weak classes and substantially inflated their measured weakness (excl-Wardens, assassin/necro baseline WR jump 57→81). The fix adds a per-build routing-readiness gate: readiness = scorePartyPower(run) / max enemy-power in the zone — the project's own powerRatio instrument (loss-attribution's 0.7/0.9 cuts), class/build- relative by construction (the build's own power is the numerator). An OPTIONAL miniboss whose readiness is below a floor is FILTERED out of the reachable set (a score penalty can't skip it — the pool rule fights every non-boss before the boss), so the pilot routes on to the boss and the run stays winnable. The hero-power input recipe is extracted into one shared helper (buildRunHeroPowerInput) so routing and loss-attribution read the same numbers. Ships opt-in and default-OFF (floor 0 → byte-identical routing) behind the fleet A/B arm miniboss-skip:<floor> (e.g. miniboss-skip:0.85), for CRN-paired calibration before flipping the default. The default floor lives as a hashed literal in run-progression-simulator.ts so a later flip forks the comparabilityKey (a versioned recalibration, like the ROG-1093 town-topk flip). No player-facing change; no measured-balance change until the default is flipped.
  • Ranked screens no longer hang when the leaderboard is slow to load.: The ranked lobby and the run-end result panel each fetch two things: the board (a nice-to-have) and your own status (which decides whether you can start a run and whether your run is verified). A slow or dead leaderboard request used to be able to hold up the status you actually need — the lobby could sit on "Loading…" with no Begin button, and the result panel's verification could stall. The two are now fetched independently, so status lands as soon as it's ready, and every ranked request gives up after a few seconds instead of waiting forever.
  • Hardened ranked run identity so a stale mint or a restored run can't hijack the wrong lobby or result panel.: Two narrow race/identity fixes in the ranked flow, both invisible in normal play. Starting a Daily Challenge is asynchronous; leaving and reopening the lobby while that request is in flight could let a second attempt begin or let the first request touch the wrong screen — a begin is now bound to the exact lobby it was launched from, and a second begin is blocked until the first settles. Separately, resuming a saved run now tears down any leftover result panel from a previous run, and the ranked result panel/poll now identify a run by its unique attempt key rather than a class-plus-seed id that two different runs could share.
  • The per-encounter sim drivers (run-meta-build-combat-quality / run-alpha-readiness) can now thread a --trait-foresight probe key to the pilot scorer, enabling per-encounter A/B of flag-gated foresight terms.: Sim tooling only; no player-facing change (the probe is default-OFF and never set in production). The winnability runner could already enable a flag-gated pilot-scorer probe (__ROUGE_SIM_TRAIT_PROBE) via its --arms trait-foresight:<key> mechanism, but the per-encounter drivers could not — blocking measurement of per-encounter play-quality effects (e.g. focus-fire at multi-enemy boards) that don't move full-run winnability. This adds a --trait-foresight <key> flag to run-meta-build-combat-quality.js (validated against the same KNOWN_TRAIT_IDS/SYNTHETIC_PROBE_KEYS sets the winnability arm uses) and run-alpha-readiness.js; the key rides the already-serialized options/crafted-spec path (no new cross-worker plumbing, mirroring strength) and analyzeSpec sets the probe on the pilot window for the scoped duration of its encounter loop, restoring after — exactly mirroring the winnability runner's scoped set/restore. Byte-identical when the flag is absent. Part of ROG-1149 (Task 1: the plumbing).
  • Forced-candidate-EV sizing no longer under-shards long-combat classes into watchdog censoring, and the rollout recovers the ~57% of decisions it was silently discarding as "duplicate_identity".: Two fixes to the forced-candidate expected-value pipeline (ROG-1066/A decision-slicing, the ROG-940 dataset that ROG-941's scorer refit consumes): ROG-1150 — cost-model sizing. The decision-shard auto-sizer used a barbarian-calibrated PER_ROLLOUT_MINUTES = 0.55, which is 2–3× low for long-combat classes: warlock D=5 sub-shards ran 82–212 min and the tail exceeded the 3.75h daemon watchdog → SIGKILL survivor-censoring (the exact failure decision-slicing exists to prevent). Bumped to 1.2 (warlock's measured cost), so the sizer now picks a slice size that fits even the expensive classes under the watchdog. A blunt global bump — the real fix is class-aware / measured sizing from live wall-time (deferred). ROG-1151 — duplicate_identity recovery. The rollout keyed candidate identity on (kind, optionId), but optionId is the cardId — target-blind and kicker-blind. So the same card enumerated once per living enemy (different target, different EV) and base-vs-kicked variants all collided on one key and were excluded as "duplicate_identity", which — via the paired-complete rule — zeroed the entire decision's Δ. This silently discarded ~57% of every decision in the dataset. The fix threads the full play identity (targetId + extraEnergySpent) through the harvest candidate summary and the target-verification surface: different-target / kicked arms are now distinct and each rolled + verified independently (recovered as real data), while genuinely-identical copies collapse to one representative (saving the redundant rollout). Rollout-layer + additive summary fields only — snapshot.digest and the harvest manifest are unchanged, so RG002 / harvest determinism are unaffected. No player-facing change.
  • Clear the 23 pre-existing lint errors on master so CI can enforce eslint: Internal only, no player-facing impact. Cleared the 23 pre-existing ESLint errors on master (no-param-reassign, nested ternaries, require-imports, unused vars, prefer-services-bag, a file over the max-lines budget, and a few others) with behavior-preserving edits, so the CI lint step can be flipped from advisory to blocking.
  • Run eslint as part of pretest so lint is enforced locally while CI is disabled: Internal only, no player-facing impact. ROG-1167 cleared the lint backlog and made the CI lint step blocking, but CI is currently disabled (out of Actions minutes), which left lint enforced nowhere. Folding npm run lint into the pretest chain means every npm test now fails on any lint error or warning, so the clean state can't rot while CI is off.
  • Sim-lane parity guard so the pilot's SPEND_ALL_EFFECT_KINDS set and its test-helper mirror can't silently drift: Internal only, no player-facing impact. The sim pilot's spend-all counter-cashout effect kinds were hand-duplicated between the runtime scorer and its test-helper mirror with nothing guarding parity; a new sim-lane test now fails if the two sets drift, so the pilot keeps valuing minSpend counter-payoff cards correctly.

Operations

  • Adopt @andrewpopov/db-backup for the prod DB backup instead of a bespoke script: No player-facing change. The prod game-DB backup now uses the shared @andrewpopov/db-backup package (as bewks/smarthome/sano-os do) via a thin policy wrapper, replacing a ~200-line bespoke script. Gains WAL-safe snapshots, integrity verification, retention, a content-based freshness stamp, rclone offsite to R2, and db-backup restore; runs as the rogue DB owner under a systemd timer.
  • Pi deploy now generates the content manifest before reloading production: Production deploys now run the same content-manifest generation step as local builds before PM2 reloads the app, preventing alpha deploys from starting against a checkout that is missing generated/content-manifest.json.
  • Delete the dead prod-pull/prod-push/run-clone/worker-merge ssh sync layer; guard db-import against the game DB: No player-facing change. Removed the ssh sim-sync tools (prod-pull, prod-push, run-clone, worker-merge) and their runners/aliases — inoperable since the 2026-07-01 host move and superseded by the fleet's Postgres canonical. This also removes the last API-launchable DANGER tool that could ssh-write the prod game DB (skill-balance-promote remains the sole DANGER tool). The surviving db-export/db-import archive primitive now routes its import through the balance-store guard, so it can never write data/rouge.db (ROG-1137).
  • Crafted/meta-build sim loadouts now respect the real ascension-scaled charm-pouch budget instead of a hardcoded 8: No player-facing change (the runtime charm budget itself is unchanged — it never force-drops over-capacity charms, so this was never a live-game bug). The crafted/meta-build sim path (scripts/lib/meta-build/charm-loadout.js, meta-spec-builder.js) hardcoded a flat CHARM_POUCH_CAPACITY = 8 for every ascension, instead of reading the runtime source of truth (ROUGE_CHARM_SYSTEM.getRunCharmBudgetCapacity: base 12, minus 1 slot per 2 ascension tiers, floor 7). At ascension 0-7 this understated the real budget (12/10/9 vs the hardcoded 8); at ascension 10 it overstated it (7 vs 8) — a measurement-fidelity bug, not a balance one. Both the generated (knapsack) loadout and the explicit --charm-loadout CLI path now derive capacity from the runtime per-spec ascension and fail loudly if the runtime harness doesn't expose the budget function, instead of silently falling back to 8. Fleet re-baseline note: charm selection is still deterministic (no new RNG hazard), but bigger/smaller loadouts change combat state, which changes combat RNG draw counts. Existing 8-slot crafted/meta-build fleet baselines and A/B comparisons are no longer directly comparable to results generated after this change — re-baseline before drawing balance conclusions from a mix of pre/post-fix crafted-lane data.
  • Internal-only sim levers to A/B the Summit Wardens' damage split and Unbroken Oath threshold; no player-facing change.: Adds two default-off sim probes so the fleet can A/B whether the Act 5 Summit Wardens (ancients miniboss) fight is overtuned on its damage side or its death-prevention threshold — without touching live play. __wardens_damage_split__ splits each Warden's damage-bearing intent value (attack, sunder_attack, attack_and_guard, charge) by the count of living Ancients members, so 3 bodies deal roughly 1x combined output instead of 3x. Gated at runtime inside resolveEnemyAction (combat-engine-enemy-turns.ts) rather than at content-catalog build time, because the catalog is baked before the fleet arms the probe — a build-time gate would silently never fire on the fleet. summon_minion (War Horn) is excluded: its value derives the summoned unit's HP/attack, not damage. __wardens_oath_threshold__ raises the Unbroken Oath release threshold above the default 0.25 via a single gated getter (getAncientsOathThresholdPct, combat-anchor-constants.ts) that all 3 read sites — the death clamp, its duplicate lookup, and the sim pilot's pickAnchorEqualizationTarget — route through, so focus-fire partially pays off without the pilot aiming at a different peer than the death clamp protects. The threshold is clamped to the open interval (0, 1): a value at or below 0 would make the fight unwinnable (the first Warden could never die), and a value at or above 1 fully disables the Oath. Both probes are byte-identical to today when unset (the real-player default), so there is no gameplay change — they exist solely to fleet-A/B whether the Wardens fight's damage side and Oath threshold are overtuned before deciding whether to bake either change in.
  • Internal sim telemetry for runeword completion cadence; no player-facing change.: Adds per-seed runeword completion-cadence telemetry to the winnability sim (an additive run.progression.runewordCompletionLog recorded at socket-activation time, surfaced through the sim report and the fleet history row behind an opt-in --runewords flag). Byte-identical for normal gameplay — the log is only ever created when the runewords-and-sockets subsystem is enabled (off by default), so there is no gameplay, RNG, or persistence change for players. It exists to let the ROG-779 runeword tuning be validated against real completion-rate curves on the fleet.
  • Internal sim fleet-arm addition for natural-play runeword cadence experiments; no player-facing change.: Adds a runewords:natural arm dimension to the sim's --arms grammar (scripts/lib/sim-arm-dimensions.js). It enables the runewords-and-sockets subsystem for a run WITHOUT forcing any starting gear — distinct from the existing gear:<slot>=..@rw:<id> arm, which also enables the subsystem but pre-equips a specific socketed item (forced-equip delta-EV measurement, not natural pacing). Since the fleet submit path (scripts/fleet/fleetctl-pg.js submit) already forwards --arms verbatim to the runner, this composes with no further plumbing: an experiment like --arms baseline,runewords:natural measures the ROG-779 completion-cadence telemetry (report.summary.runewordCompletions) under free assembly, CRN-paired against baseline. Opt-in and additive — absent from an arm label, behavior is byte-identical to before this change.
  • Sim storage docs reorganized around four planes; bare sim:server-sync / sim:db-transfer aliases removed: No player-facing change. SIM_RUN_DATA_WORKFLOW.md is now organized around the four storage planes the code actually implements — the game DB (data/rouge.db, never a sim target), the local sim store (artifacts/balance/balance-runs.db), the fleet's Postgres canonical, and the file artifacts — replacing guidance that named the game DB as the default sim store. The two bare passthrough aliases sim:server-sync and sim:db-transfer are removed: each forwarded an unlabelled --mode to a runner backing both a safe and a production-writing tool, so sim:server-sync -- --mode push could become a production write while reading like a routine sync. (The remaining ssh sync aliases — sim:prod-pull / sim:prod-push and the clone/merge tools — were then removed entirely in ROG-1140; sim:db-export / sim:db-import is the surviving archive pair.)

Angel Snack 0.1.0-alpha.7 Patch Notes

Release date: 2026-07-09

Stage: alpha

Package version: 0.1.0-alpha.7

These notes are gathered from the release fragments in docs/patch-notes/unreleased/.

Gameplay

  • Combat RNG is now seeded deterministically from the run seed and persists its draw cursor across saves.: Runs now keep combat randomness tied to the run seed across save/load boundaries, reducing drift when a run is resumed and making tricky combat outcomes easier to reproduce during alpha debugging.
  • Internal: combat input capture wired for a future run replay/audit log (no player-visible change).: This is internal replay/audit plumbing for future ranked-run verification. Players should not see a behavior change yet, but combat inputs now have a stable capture path for later replay validation work.
  • Softened the Rift ascension top-tier difficulty wall so the highest tiers are hard but winnable, not brick walls.: The upper Rift ascension tiers were an near-unwinnable wall at the top (Tier 10 in particular). This pass eases the act-5 boss scaling tail, lowers the Tier 5 elite encounter rate, reduces the Tier 8 max-life penalty, holds the +2 affix-count bump to the highest tiers, and caps Tier 10 pack-wide affixing to a few enemies instead of the whole pack — keeping the top of the ladder demanding without cliff-ing entire classes to zero.

UI

  • Alpha builds now include a floating bug-report launcher with best-effort screenshot capture for submitted bug reports.: Alpha players can now open a bug report from a floating question-mark button without digging through the game menu. Bug report submissions try to attach a browser-captured screenshot when permission and browser support allow it, while still sending the report normally if capture is unavailable.

Tech

  • Fleet reap now also clears stale "active" attempt rows left behind by uncleanly-killed daemons.: The fleetctl reap command now cleans a second leak in addition to stranded shards: attempt rows left active after their daemon died mid-run (kill -9 / OOM / power loss) when the shard itself has since gone terminal. These orphaned rows accumulated for days and polluted fleet monitoring reads. Only attempts older than a hard 5-hour floor (well past the 3.75h shard watchdog, so a live run can never be touched) are flipped to abandoned. Dry-run by default; reap --apply cleans them.
  • Durable server-side storage for the input-log integrity chain — ranked-run tables plus a verified segment-upload endpoint.: Adds the app-DB storage substrate for ranked-run verification (ROG-1059, epic ROG-1053): the ranked_seed_tokens, ranked_run_submissions, and run_input_log_segments tables (migration 0005), an atomic single-statement seed-token consume, and an authenticated POST /api/input-log/segment endpoint that ingests the client's ordered input-log segments. The server recomputes the canonical hash chain byte-for-byte against the client contract and rejects any gap, reorder, tamper, or cross-user upload, so a stored log is provably the one the player produced. Internal/tech only — no player-facing behavior yet; consumed by the signed-seed (W3) and replay-verification (W4) work.
  • Shadow-mode server-side profile validation: Added a build-time content manifest and a shadow-mode server-side validator that checks saved profiles for unknown ids, out-of-range progression, and debug-flag usage. Logs findings only — no client-visible behavior change yet.
  • Sim fleet can now shard a heavy forced-candidate-EV seed along the DECISION axis so it fits under the watchdog: The forced-candidate-EV runner is combinatorial per seed (~decisions × candidates × replicates rollouts), so a full-fidelity seed (~200min) blows past the 3.75h shard watchdog even at one seed per shard — and a kill→retry silently censors the longest-surviving seeds. Submit can now expand each seed into K decision-range sub-shards (--decision-shard-size D, or the opt-in cost-aware --decision-shard- auto), each seed_count=1 and each rolling out only its slice of the seed's kept decisions after re-harvesting the full seed. The per-seed manifest (Phase 1) plus the cross-host equality guard (Phase 2) keep the reassembled seed trustworthy across a mixed macOS-ARM / Windows-WSL fleet. Non-sliced submits — every other runner and forced-candidate-EV without the new flag — are byte-for-byte unchanged.
  • Sim fleet daemon now clamps its concurrency to a host's real core count, always reserving at least one core: The fleet worker daemon no longer trusts ROUGE_FLEET_CONCURRENCY blindly — it now clamps the effective sim concurrency to logical cpus - ROUGE_FLEET_CORE_HEADROOM, always reserving at least one core, so a misconfigured or copy-pasted concurrency value can never oversubscribe a host (the prior wintop-wsl concurrency=14 incident that slowed the ROG-940 EV shards past the watchdog). Interactive/shared hosts an operator actively uses can reserve more cores via the installer's new --core-headroom flag or the ROUGE_FLEET_CORE_HEADROOM env var. The heartbeat's reported concurrency (and the ROG-1070 oversubscribed flag) now reflect this effective, clamped value.
  • Sim fleet submit now hard-rejects a pin that isn't on origin/master: fleetctl submit/rebaseline --submit/charm-sweep --submit and the admin POST /api/fleet/experiments route now verify a --sha/sha pin is actually an ancestor of origin/master before enqueueing. Previously an unmerged-branch pin enqueued cleanly and every one of its shards was silently quarantined at claim time by the worker's own ancestry gate. A bad pin is now rejected immediately with an actionable "merge it first, or pin to a master sha" message.
  • Sim fleet heartbeats now report real host cores/load/mem, and flag oversubscribed hosts: The fleet worker daemon's heartbeat now carries real host-resource telemetry (cpu count, 1-minute load average, free memory) alongside the pre-existing configured concurrency. fleetctl status and fleetctl doctor (plus the /api/fleet/hosts dashboard data) now surface an oversubscribed flag when a host's configured concurrency exceeds its real core count — previously this was only inferable, never measurable, and slowed the ROG-940 EV shards past the watchdog on a host running concurrency well above its real cores. Old daemons that haven't self-updated yet simply omit the new fields — never a false OVERSUBSCRIBED alarm.
  • Sim fleet daemons can now be drained and restarted gracefully via the DB, with no wasted in-flight work: fleetctl-pg.js drain-restart --host <id|*> signals a fleet worker daemon (or every freshly heartbeating host at once, via --all) to finish its current shard(s), stop claiming new work, and re-exec — through Postgres, no SSH. This replaces the prior hard-restart-only path, which SIGTERMed any in-flight shard and forced a retry, wasting up to hours of watchdog-bounded work. The re-exec also re-triggers the existing startup self-update, so drain-restart is the way to roll out a daemon code change without a hard kill. --concurrency/--core-headroom apply a one-shot override on that restart only, so a host's concurrency can be right-sized remotely with no SSH access.
  • forced-candidate-EV runner supports decision-range slicing + per-seed manifests (fleet-inert): scripts/run-forced-candidate-ev.js (the fleet-backed forced-candidate ΔG EV sweep) can now slice each harvested seed's rollout to a --decision-offset/--decision-count sub-range, laying the groundwork for sharding a heavy seed's rollout matrix across multiple sub-shards. Every run also emits a per-seed manifest (the full ordered list of harvested decision digests) that a future ingest step will use to verify sub-shards agree on which decisions they targeted. The flags default to a no-op, so this ships inert — no fleet or player-facing behavior changes.
  • forced-candidate-EV fleet ingest now rejects cross-host harvest drift instead of landing it silently: The fleet ingest for the forced-candidate ΔG EV sweep now cross-checks every sub-shard of a seed's decision-range harvest against the per-seed manifest ROG-1074 started emitting. Sub-shards of one seed can run on different hosts (macOS/ARM vs. Windows/WSL x86), where floating-point transcendentals aren't always bit-identical, which could previously make two sub-shards target different decision sets and land gappy, mis-attributed EV data with no warning. A mismatch is now rejected loudly and retried (a later attempt, possibly on a different host, can heal it), and any affected seed is flagged so the EV report can exclude it. No player-facing or fleet-operator behavior changes beyond this data-integrity guard.

Operations

  • Compact Discord patch-note announcements: Discord patch-note announcements now stay short and readable by posting a compact release summary, a few highlights, release-area counts, and a link to the full notes instead of flooding the channel with full changelog text.

Angel Snack 0.1.0-alpha.6 Patch Notes

Release date: 2026-07-08

Stage: alpha

Package version: 0.1.0-alpha.6

These notes are gathered from the release fragments in docs/patch-notes/unreleased/.

Fixes

  • Admin Console now safely returns sessions that lose admin access back to the hall.: If an Admin Console session loses its admin authorization, it now returns safely to the hall instead of leaving the player stranded on an unusable restricted screen.

Angel Snack 0.1.0-alpha.5 Patch Notes

Release date: 2026-07-08

Stage: alpha

Package version: 0.1.0-alpha.5

These notes are gathered from the release fragments in docs/patch-notes/unreleased/.

Gameplay

  • Fix: Necromancer curse debuff-stack bonus damage (Soul Eruption) now correctly triggers Soul Leech healing.: Necromancer curse cards that deal bonus damage scaled by debuff stacks (e.g. Soul Eruption) were not triggering Soul Leech lifesteal on that bonus damage, even though their base damage did. Soul Leech now correctly heals off the full hit, including the stack-scaled bonus.
  • Skeleton Mastery now grants a persistent summon-hit aura for the rest of combat, applying to skeletons summoned afterward too.: Necromancer's Skeleton Mastery card no longer grants a one-turn summon-damage bump. Instead, each cast now permanently adds +3 damage to every skeleton's ally-phase strike for the rest of the fight — including skeletons you raise afterward. Repeated casts stack.

UI

  • Admin Console sidebar now groups admin pages into clearer operational sections.: Admin users now see the Admin Console sidebar grouped by Operations, Player Records, and Observability, making Settings, Sim Lab, player data, reports, and audit logs easier to scan as the console grows.
  • Admin Console now includes a Sim Lab tab for launching, monitoring, and reviewing simulation work.: Admin users can now open Sim Lab directly from the Admin Console sidebar to launch simulations, monitor fleet progress, and review completed experiment data without relying on the debug-only hall shortcut.
  • Sim Lab fleet progress now prioritizes attention-needed experiments and preserves authenticated writeup attribution.: Sim Lab fleet monitoring now keeps attention-needed experiments visible ahead of ordinary active runs, including mixed running/failing shard states, and completed experiment notes preserve server-side admin attribution.

Fixes

  • Block signed-out and guest gameplay entry when guest accounts are disabled.: When guest accounts are disabled, signed-out players and existing guest sessions now see a locked front door instead of being able to start, resume, or enter arena gameplay. Registered Google accounts continue to play normally.

Angel Snack 0.1.0-alpha.4 Patch Notes

Release date: 2026-07-08

Stage: alpha

Package version: 0.1.0-alpha.4

These notes are gathered from the release fragments in docs/patch-notes/unreleased/.

Gameplay

  • Higher ascension tiers tighten the charm pouch — fewer slots as the difficulty climbs: The charm pouch shrinks as you climb Rift Tiers: you lose a slot every couple of ascension levels (from 12 at the base game down to 7 at the top), so higher-difficulty runs force sharper charm choices. It's a new kind of ascension pressure — on your build assembly, not just on enemy stats and skills.
  • Chain Reaction now shows its fire+lightning trap synergy in the card text: The assassin card Chain Reaction has always dealt bonus Burn and Paralyze to all enemies when you control both a fire and a lightning trap, but that synergy was invisible on the card — the text only read "Volley 16. Burn All 3." Its card text now advertises the build-around: "If you control a fire trap and a lightning trap, apply 3 Burn and 2 Paralyze to all enemies." No mechanical change — this makes an existing assassin trap payoff discoverable (ROG-970).
  • Charms now share a slot budget — pick your loadout instead of hoarding every charm: Charms are no longer unlimited. Your pouch has a 12-slot budget — small charms cost 1 slot, large and grand charms cost 2. When you pick up a charm that won't fit, open the pouch to discard one and make room, or pass on it. It's a real assembly decision: a build-defining grand crowds out a couple of smaller charms, so your loadout is a choice, not a pile. Charm rewards show their slot cost, the pouch shows what you're carrying, and an over-capacity charm's reward card lets you make room on the spot. Higher ascension tiers will tighten the budget further as a difficulty modifier.
  • Arena runs now include a Training Dummy for safe damage testing: The Arena now includes an endless, unkillable Training Dummy that heals to full every turn, so you can test a build's damage output with a live damage-per-turn readout. A debug toggle can make it hit back when you want to stress-test defenses.

Balance

  • Large Charm of Cleaving is now a Rare charm (was Boss-rarity): With Cleaving fixed to actually work, its drop rarity was re-tuned to match its real power: it's now a Rare charm rather than a Boss-tier one, so it turns up a bit more often. (Under the hood, the charm scoring model also now values a few bonus types it previously ignored, so future charms bucket at the right rarity.)
  • Grand Charm Earthshaker toned down — its opening stun no longer gives a free first turn: Earthshaker was over-performing for the Barbarian. Its start-of-combat stun handed you a free opening turn against bosses, so it now triggers on your first kill each combat instead — still a strong crowd-control tool against packs, but no longer a guaranteed free turn against a lone boss. Its execute bonus against the lowest-life enemy is also reduced from +6 to +3.
  • Rift ascension affixes now correctly start in act 3 (were spiking acts 1-2, making Rift Tiers unwinnably hard from Tier 2).: Rift Tier 2's headline modifier — "normal enemies gain +1 random affix" — is meant to kick in from act 3 onward, but it was firing from act 1. That handed act-1 and act-2 normal packs (which normally have no affixes) an extra affix each, spiking the early game right where your build is weakest and making every Rift Tier from 2 up effectively unwinnable. Affix pressure now correctly begins in act 3, so the early acts of a Rift run stay close to Normal and the difficulty builds over the run as intended.
  • Rift ascension affixes now hit only a few enemies per pack (scaling with tier), not the whole pack at once.: Rift Tier 2's "+1 random affix" was landing on *every* enemy in a pack, so an act-4 swarm of five became five affixed enemies at once — a brutal spike that made the low Rift Tiers effectively unwinnable. The affix boost now hits only a capped number of enemies per encounter, and that cap grows as you climb: 1 enemy through the early tiers, 2 in the middle, 3 in the high tiers, and the whole pack only at the very top. The rest of the pack rolls Normal affixes, so the ladder ramps up smoothly instead of spiking.
  • Large Charm of Volley now rains arrows across all enemies (was a focused three-shot): Volley had become nearly identical to the Amazon's Strafe grand. It's now the area-suppression bow charm — every 3rd attack looses an arcing volley for 5 physical damage to all enemies — while Strafe keeps the focused, auto-aiming triple shot into the weakest foe.

UI

  • Sim Lab now presents fleet progress, run review, and launch tools in a cleaner lab workspace.: Sim Lab now shows live fleet progress, worker checkouts, completed experiment review, and risk-grouped launch tools in a cleaner operator workspace.

Fixes

  • Arena autopilot now plays each deck with its own build identity instead of a generic balanced pilot: Arena autopilot previously played every deck as a generic "balanced" character, so a deck built around summons, javelins, curses, or any other specialization was piloted without the priorities that build is meant to reward — and its measured performance reflected that mismatch, not the build. Autopilot now reads each deck's build identity and plays to it, so arena runs show how a build actually performs when played to its strengths.
  • Autoplay and autosuggest now follow your actual build instead of playing every character as a generic balanced archetype: Autoplay and the card-suggestion highlight previously scored every character as a generic "balanced" archetype, so a build committed to summons, demons, curses, traps, or any other specialization never got the play priorities that build is meant to reward. They now read the tree you've actually invested in and weight the recommended plays toward your build's identity — so watching autoplay (or following the suggested card) reflects how your character is supposed to be played, not a one-size-fits-all default.
  • Autoplay/autosuggest now follows assassin-traps and sorceress-cold build identity: Autoplay and card-suggestions for assassin Traps builds and sorceress Cold builds now activate that build's identity instead of playing as the generic class default.
  • Large Charm of Cleaving and the Warform Grips unique now actually work: Two effects that hooked a combat trigger that was never wired up were silently doing nothing, and now fire correctly: Large Charm of Cleaving — "First attack each turn: draw 1 and gain 2 Guard." Warform Grips (unique gloves) — "Every 3rd attack: deal 12 damage and heal 6."
  • Route combat executions and direct DoT through shared death-prevention and stop countdown spillover after combat ends.: Combat executions, Poison, piercing Burn, and countdown detonations now respect the shared death-prevention rules. Training dummies and protected bosses no longer get bypassed by direct combat effects, and queued countdown cards stop resolving once the fight is already over.
  • Audit Game settings wiring, restore inert controls, and align Autopilot speed controls with named pacing presets.: Game settings for Autopilot now update the same backing settings the rest of the game reads, so HUD controls, debug AI Assist, skip-FX, and named speed presets stay in sync. The Game tab also exposes Autoplay and Autosuggest switches even when they are off, and pressing Stop persists both Autopilot entry points as off so a reload cannot quietly bring automated play back.

Tech

  • Adopted the shared release-kit package for patch notes and release tooling: Internal maintainability change — replaced the inline release-note engine (scripts/lib/release-notes-core.js, scripts/release-notes.js, scripts/cut-release.js, scripts/check-release-hygiene.js) with the @andrewpopov/release-kit package, configured to reproduce this repo's exact prior behavior byte-for-byte. No change to patch notes, versioning, or the release-hygiene gate; normal play is unaffected.
  • Internal refactor — split the combat damage engine into two modules under the line-cap (no manual-play change): Internal maintainability split (ROG-1031). The combat damage engine had grown past the project's per-file line cap, which was blocking the test suite. Its incoming-damage / mitigation calculators were moved verbatim into a sibling module, leaving the damage-application logic and every runtime behavior byte-for-byte identical. Pure refactor — combat math, logs, and outcomes are unchanged; normal play is unaffected.
  • Split Sim Lab launch rendering into the launcher module: Internal maintainability change: the Sim Lab Launch tab renderer now lives with the launcher card module, keeping the main Sim Lab shell under the TypeScript line cap without changing player-facing behavior.

Operations

  • Discord deploy announcements load local env files: Production deploys now read the ignored local Discord env files before posting patch-note announcements, so configured release bots announce shipped builds without requiring operators to export the token by hand.

Angel Snack 0.1.0-alpha.3 Patch Notes

Release date: 2026-07-06

Stage: alpha

Package version: 0.1.0-alpha.3

These notes are gathered from the release fragments in docs/patch-notes/unreleased/.

Gameplay

  • Full charm pouches now pause the reward claim instead of losing the charm, so you can drop one and retry: Internal groundwork only (ships dark — no visible UI change yet): when the charm pouch slot budget is enabled, claiming a charm reward with a full pouch no longer errors or silently drops the charm. The reward now waits so a future update can let you drop a charm and retry, or skip the reward outright.
  • Charm pouch slot budget groundwork (ships dark behind a debug flag): Internal groundwork only (ships dark behind debugMode.charmPouchBudget): runs can now track a charm-pouch slot budget, with small charms and grand charms consuming different amounts of space. The default production experience is unchanged until the flag is enabled, but the saved-run and reward plumbing is in place for the upcoming pouch-capacity UI.
  • Charm Pouch overlay: view your slot budget, discard charms, and make room for a reward that doesn't fit: Internal groundwork only (ships dark — behind the same debug flag as the pouch slot budget): adds the Charm Pouch overlay UI, reachable from combat, reward, and town screens. It shows your slot capacity as pips, lets you discard a charm (locked during combat, since bonuses are baked at fight start), and — when a reward charm won't fit — opens straight into a "make room" view where you can free a slot and take it, or decline the reward outright.
  • Refreshing the page mid-combat now resumes your fight instead of dropping you to the world map: Reloading the game during a fight used to discard the encounter and drop you back on the world map. Your combat is now saved and restored, so a refresh (or coming back later) resumes the fight exactly where you left off. If a saved combat is too old to restore safely, we keep your run and return you to the world map instead of losing the run entirely.

Balance

  • Charm focus pass — grand charms now center on one build-defining effect, themes spread out so a class's grands feel distinct, plus targeted dedup: Grand charms got a focus pass. Each one now centers on a single build-defining effect with at most a couple of reinforcing riders, instead of a pile of unrelated bonuses — so equipping a grand tells you what your run is about. Their themes were also spread out so a class's grands pull toward different playstyles (execute, hard crowd-control, summon-army, traps, curses, guard-walls, energy economy, lifesteal, damage-over-time) rather than several variations of the same "every few cards, hit everything" effect. Grand Charm: Eldritch Hunger (Warlock) no longer overlaps Chaos Debt. It now leans into the void: each card you exhaust drains 4 magic damage from the target and heals you 3, and the first Exhaust each turn still draws a card and banks Energy — a single-target sustain engine. Small Charm of Drumbeat now grants +2 Mercenary Attack and +1 Damage (previously a duplicate +2 Damage). Small Charm of Arcane Battery now grants +1 Spell Damage and +5% Crit (previously a duplicate +2 Spell Damage).
  • Blacksmith Temper (-1 Energy) and Hone (+Draw 1) upgrades are now much pricier (240g / 200g) — premium mods are a rare splurge, not a routine buy.: The Blacksmith's two strongest card upgrades are now premium purchases: Temper (card costs 1 less Energy) rises to 240 gold and Hone (card gains Draw 1) to 200 gold. Energy and card draw are the game's most powerful levers, so these are meant to be a rare, deliberate splurge rather than something you buy on every card. The mild stat upgrades — Sharpen (+3 damage) and Fortify (+3 Guard) — stay cheap at 50 gold.
  • Removed the Blacksmith's Refine service; card upgrades (card+) now come only from skill-tree ranks and the miniboss Forge Scroll, not gold.: The Blacksmith no longer offers Refine, the option that bought a card's upgraded (card+) form for gold. Card upgrades now come from the two intended channels only: investing 5 ranks in a skill, or claiming a Forge Scroll from a miniboss reward. This keeps your skill trees the meaningful path to stronger cards rather than something gold can shortcut. The Blacksmith still offers card Evolutions and generic stat Upgrades.
  • The 8 class-signature attribute charms now cost 1 charm slot instead of 2: The class-signature charms that grant a permanent attribute (Blood Oath, Aegis Pledge, Huntress Mark, Silent Strike, Nature's Blessing, Bone Pact, Arcane Keystone, Demon Pact) are small charms and now cost a single charm slot, matching every other small. They previously charged 2 slots — a leftover from before they were re-tiered — which only mattered once the charm-slot budget is in play.

Content

  • 18 new charms fill the freeze, bow, trap, curse, and defensive gaps — earned from existing achievements: Eighteen new charms join the pool, closing coverage gaps and opening play patterns the roster was thin on: Freeze / crowd-control: Coldiron (pierce status resistance), Winterlock (frost when you're hit), Stillfrost (freeze when you end a turn untouched), and the barbarian grand Earthshaker (an opening stun). Bow / multi-hit: Fletching, Volley (a three-arrow salvo), and the amazon grand Strafe (auto-aims the weakest enemy). Traps / delayed payoff: Slow Fuse (a turn-4 timebomb), the Hourglass (refills Energy every 10 cards), and the assassin grand Tripwire (trap tempo + control). Curses: Afflictor's Edge (each status you land adds damage) and the necromancer grand Soulleech (afflictions heal you). Defensive: Stoneskin (flat damage reduction), Rampart (keep some Guard between turns), Lifeline (a once-per-run emergency heal), and the paladin grand Crown of Thorns (ramping retaliation). Plus the warlock grand Blood Ledger (pay Life for cards) and Wayfarer's Purse (gold + cheaper shops). Each is unlocked from an existing achievement track; the six class grands come from clearing all bosses with that class. Icons for the new charms are coming in a later update.

UI

  • Add an admin feedback inbox for submitted bugs and suggestions.: Admins now have a Bugs & Feedback tab that lists player-submitted bug reports and suggestions newest-first, including contact details and captured run context. This makes in-game feedback actionable after submission instead of disappearing into raw server storage or Discord-only alerts.
  • Full-screen character and run-end surfaces now share the canvas-fit height contract.: Hero selection, expedition setup, and other full-screen cinematic surfaces now use the same canvas-fit height contract, removing the short bottom gap that appeared on the character flow.
  • Keep feedback form input actions covered by the UI dispatcher audit.: Feedback form typing now uses registered input-dispatcher actions covered by the UI action audit. The visible form behaves the same, but future input refactors are less likely to silently break message/contact entry or force unnecessary full-screen rerenders while the player is writing a report.
  • Add in-game bug report and suggestion submissions with Discord bot notifications.: Added a feedback option to the game menu so players can submit bug reports or suggestions without leaving the app.
  • Restyled the Terms and Privacy pages with richer legal-page backdrops and bordered document panels.: The Terms and Privacy pages now use darker scene backdrops, stronger document-panel borders, and clearer legal navigation so the alpha service pages feel more like the rest of Angel Snack.
  • Adds a carved stone door backdrop outside the game frame.: The letterbox space around the game now uses generated carved-stone door art, giving the app shell a darker dungeon-threshold frame instead of a generic warm wash.
  • Adds thematic art backdrops to previously generic screen surfaces.: Combat Puzzles, puzzle results, Training, and Sim Lab now use curated thematic art layers instead of plain shell gradients, so those secondary screens feel anchored in the same carved-door, gothic campaign presentation as the rest of the game.

Fixes

  • Repair review hygiene and boss-readiness scoring: Cleaned up review-blocking lint/type issues and corrected boss-readiness scoring so balance reports judge boss pressure from the intended score terms. This is mostly behind-the-scenes, but it makes the generated balance guidance more trustworthy before tuning changes reach players.
  • Exploration charm rewards gracefully decline instead of stalling when the charm pouch is full (flag-gated): When the charm pouch slot budget is enabled, finding a charm during exploration while your pouch is full no longer gets stuck on a dead choice — the charm is declined and the encounter continues normally. This system is currently flag-off in production.

Tech

  • Added a cross-domain boundary ratchet that freezes private-namespace reach-through (no manual-play change): Internal architecture guardrail (ROG-989). Documented the enforceable module boundary — a domain's __ROUGE_* namespaces are private, and its public read surfaces are the blessed cross-domain entry — and added a pretest ratchet that counts how often UI/sim code reaches into another domain's private internals and fails the build if that number grows. Existing coupling is frozen, not rewritten, so it can only shrink over time. No gameplay impact.
  • Parity-guard several hand-mirrored tables/sets so silent drift between duplicate copies fails the build: Internal maintainability (ROG-943 drift-sweep). Several constants exist as hand-mirrored copies across the sim, UI, and runtime layers with only weak (or no) tests, so the copies could silently diverge. Added guards so drift fails the build: full-table equality for the runtime vs canonical PROFICIENCY_SCALING_ATTRIBUTE (ROG-979); an intersection parity guard between the player-facing armed-glow counter thresholds and the sim threshold specs (ROG-977); and structural invariants plus provenance breadcrumbs for the arena recommended-level-by-act table vs the XP schedule (ROG-978). No player-facing change.
  • Internal maintainability pass — single-sourced duplicated constants and hardened combat-save restore (no manual-play change): Maintainability hardening (ROG-943/980). Several values that were hand-copied across files are now defined once and shared (joint-status counter IDs, the Barbarian discipline stances, the combat-log tone set, the fnv1a32 seed hash, and the XP curve), so they can no longer silently drift apart. Achievement-unlock evaluation used during profile migration was aligned to the canonical rule, and resumed combats now backfill any fields that a save predates, so older saves restore cleanly. These are internal correctness/robustness changes; normal play is unaffected.
  • Server ignores + self-removes a stale read-only maintenance flag so a crashed deploy can't wedge the host: Internal ops hardening (ROG-1006). The server's read-only maintenance guard now ignores and self-removes a maintenance.flag older than 30 minutes (configurable via ROUGE_MAINTENANCE_MAX_AGE_MS). Previously a flag left behind by a crashed or killed deploy would keep every write returning 503 on that host until someone manually cleared it. The threshold stays well beyond the real deploy read-only window (~1–3 min) so it never fires mid-deploy. No player-facing change.
  • Autoplay/sim now value a mercenary's aura and behavior fit when hiring (no manual-play change): The in-game autoplay and the balance sim now judge a mercenary contract by how well its aura and behavior fit the current deck, not by raw attack and life alone — so a merc whose aura is live for your build is preferred over one whose aura is dead for it. Manual play is unaffected.
  • Faster autoplay/sim decisions: memoized card-tree and base-card-id lookups (no gameplay change): Internal performance pass for autoplay and simulation: repeated card-tree and base-card-id lookups are cached and reused during decision scoring. Gameplay decisions remain the same, but larger sim and planner runs spend less time recomputing static card metadata.
  • Sim diagnostic to measure whether the pilot needs foresight terms for enemy traits (no gameplay change): Adds an internal balance-sim diagnostic (trait-injection-ab) that measures, per enemy trait, whether giving the auto-pilot a foresight term for it would change its decisions — via per-decision divergence plus a positive control — so we only add pilot logic where it demonstrably matters. All new scoring terms are diagnostic-only and off by default; manual and normal auto-play are unchanged.

Operations

  • Deploy Discord announcements: Deploys now attempt a once-per-version Discord patch-note announcement after the live server passes health checks, with a retry-safe ledger to avoid duplicate posts.
  • Add a dry-run workspace cleanup helper for local clutter.: Maintainers can now dry-run and apply safe local workspace cleanup for ignored scratch folders, empty agent worktree leftovers, and the stray :memory: SQLite file without hand-written deletion commands.

Angel Snack 0.1.0-alpha.2 Patch Notes

Release date: 2026-07-04

Stage: alpha

Package version: 0.1.0-alpha.2

These notes are gathered from the release fragments in docs/patch-notes/unreleased/.

UI

  • Added Terms, Privacy, and License pages to the front door.: Added front-door links to dedicated Terms of Service, Privacy Policy, and License pages so players can review alpha access terms, Discord bot terms and data-use notes, privacy choices, and the ISC source license from the shipped build.

Operations

  • Discord release bot: Added Discord bot tooling for patch-note announcements, slash-command registration, signed interaction handling, and allowlisted release/API status checks.
  • Discord bot help command: Added a /help slash command for RougeBot and documented why legacy !help prefix messages need a separate Gateway listener.

Angel Snack 0.1.0-alpha.1 Patch Notes

Release date: 2026-07-04

Stage: alpha

Package version: 0.1.0-alpha.1

These notes are gathered from the release fragments in docs/patch-notes/unreleased/.

Fixes

  • Small charm cleanup: Removed duplicate small charms from the reward pool and made removed-charm rewards skip safely so old pending rewards cannot block a claim.

Operations

  • Agent release hygiene enforcement: Added an agent-facing release hygiene gate so release-relevant changes must include a patch-note artifact before test and deploy checks pass.
  • Release page and cut command: Added a generated public patch-notes page plus a one-command alpha release cut flow for publishing fragments and bumping the game version together.

Angel Snack 0.1.0-alpha.0 Patch Notes

Release date: 2026-07-04

Stage: alpha

Package version: 0.1.0-alpha.0

These notes are gathered from the release fragments in docs/patch-notes/unreleased/.

Operations

  • Patch notes and alpha versioning: Introduced package-level alpha semver, a repeatable fragment-based patch-note workflow, release publication commands, and a first published patch-note index for future alpha builds.