TestCatalogGlobal existed only to give the test host one [CultGlobal] routed to the catalog. VerseGrammar is the
game's first, so the test-only type is deleted and every fixture authors a VerseGrammar instead (63 call sites; the
missing-global tests assert on aetheria.verse_grammar). Stale comments about the test type are rewritten.
Builds (not yet run when committed).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
F4: a hit that breaks the shield usually also cooks it (TakeHit's own
AddHeat), which can knock the item thermally offline in the same tick. The
reserve's recharge and its Broken-clearing check lived inside Execute, which
Entity.Update only runs while Item.Active is true -- so a shield broken by a
hit that also shuts it down could never come back, no matter how long
RestoreDuration allows for. That logic now lives in Shield.Update
(IAlwaysUpdatedBehavior), which Entity.Update calls every tick unconditionally
(Cooldown.cs already relies on the same interface for the same reason).
F5: CanTakeHit broke the shield and drained the reserve as a side effect of
the query itself, on the premise that every caller queries it exactly once
per hit. That premise was false: RaycastAll/SphereCastAll/OverlapSphere hand
every caller under Assets/Scripts/Gameplay/Weapons both the shield collider
and the hull collider for one shot, so the same shield's CanTakeHit was
queried twice per hit. CanTakeHit is now a pure read (Broken + the reserve's
own CanSpend); the mutation moved to a new Shield.Break(), idempotent, called
by each weapon file exactly where it already decided to route a hit past the
shield instead of absorbing it.
Pinned in tests/Aetheria.Shared.Tests/ShieldReserveTests.cs:
RestorationProceedsWhileTheItemIsInactive (F4),
CanTakeHitNeverMutatesRegardlessOfHowManyTimesItIsCalled and
BreakIsIdempotentAcrossRepeatedCalls (F5). Updated every existing test that
relied on CanTakeHit's old mutating side effect to call Break() explicitly,
matching the new caller pattern.
Cannot compile-verify Assets/Scripts/Gameplay/Weapons/*.cs here (UnityEngine,
Unity batchmode unavailable in this environment) -- reviewed by hand for
brace/control-flow correctness; Self or a Unity batchmode pass should confirm.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
ShieldReserveTests.cs covers what Cut 4's InputCapacitorTests.cs cannot: a hit within
the reserve is absorbed and spends charge; a hit beyond it breaks the shield; the
breaking hit is not partially absorbed; a broken shield absorbs nothing (gated on
Broken itself, not merely on the reserve reading empty); a break empties the reserve
regardless of pre-hit charge; a broken shield restores on RestoreDuration and not
RefillDuration; a partial bus grant stretches the refill proportionally.
mutation_tests_shield_reserve.py mutates each rule's own line and confirms the named
test goes red for exactly that reason, plus a no-op control. All 8 (7 rules + control)
verified against the pinned CultLib worktree.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>