The three PRs patched the same snapshot and HUD lines (Grok's review: do not merge three diffs), so this is one design built from their code and tests; IceCodeNew is the commit author (#303, #378), Convey123 co-author (#383). - b.snap gains three optional, display-only lists beside the unchanged 9-field tuples (snapshot.js ammoView / wolfView / negView, called from battle/events.js snapshot(); a living, deployed, visible ally, only when it has one): ammo [[id, rounds left, magazine]] (whole rounds; the magazine is the activation's real total that unitTuple's SP fraction runs on, extras and refills included), wolves [[id, 狼影 left, talent maximum]] (mem.shadows of the new mem.wolfCapacity, set by tokens.js wolfPack and the managed vigil kit), neg [[id, fill]] (unit.negFill(), a function op-hsgma2.js sets: the pool is read when the snapshot is taken, no per-tick sync). UnitInfo.ammoSkill (an ally whose skill is an ammo magazine) is known from the first appearance: fx events run before the frame's sample, so the aura cannot wait for the first ammo row. - render/interp.js keeps the lists per snapshot (malformed rows / unknown ids dropped) and sample() hands them out from the older snapshot like flags (they step with the skill flag); render/units.js draws them: the ammo magazine replaces the SP bar (a cell per round, thin cuts, exact fill, no cuts under 2 px a cell), a row of diamonds under the bars for the wolves (the element gauge row moves below), the red bar over the drained HP bar for the pool. An ammo skill draws no standing aura (rings.js _aura; the activation burst stays). - PR #378's wolf-head avatars are NOT taken: the count is data (the talent text 至多3只, mem.shadows), the HUD art of the official counter is in no game data we have, so the pips are plain diamonds [ASSUMED look]. The PRs' own tests are folded in and extended (test/sim/hud-readouts.test.js, test/render/hud-readouts.test.js, op_hsgma2.test.js). - Docs: network.md, SIM.md §9, client.md, PLAYING.md, types/core.js. - Golden: unchanged (283 scenarios; the canon hashes units / down / elem only, no sim state moved). - Tests: 4 + 14 new + 1 in op_hsgma2 (12), all fail on the parent; 344 related tests pass; lint 0 errors, typecheck, check:imports, docs tests. Co-authored-by: Convey123 <Convey123@users.noreply.github.com>
Typecheck
npm run typecheck runs tsc --noEmit --checkJs -p jsconfig.json.
The first slice is the closed set that already typechecks:
shared/exceptshared/protocol.jsandshared/bandBonds.js(their JSDoc does not match the code yet; see below)server/sim/rng.js,server/sim/dir.js,server/sim/constants.js(the last importsGEOfrom shared)types/— JSDoc forUnit,DamageInfo, the snapshot tuples, and the protocol message envelope
strict is off. tsc does not read jsconfig.json on its own; the script passes -p.
Widen it
Add one file or one folder to jsconfig.json include, then run npm run typecheck. Fix JSDoc that disagrees with the code in that folder. Leave strict off until the folder reports nothing. Do not add @ts-nocheck.
Suggested order once the sim split settles: server/sim/grid.js, server/sim/body.js, server/sim/buffs.js, then server/sim/damage.js against the typedefs in types/core.js. The sim does not import types/. The typedefs are a reference, not a runtime dependency.
types/core.js follows docs/DESIGN.md §5.2, §5.4, §8 and docs/SIM.md §4, §9. Where those two disagree on DamageInfo.type, the typedef uses the union makeDamageInfo actually builds ('elemental' as well as 'element').
Not in the first slice
shared/protocol.js — the catalogue JSDoc is ahead of a few object literals ($optional sits on a Record of checkers; unitStatsEntry does not list side or silenced, and the code reads side). Fix the comments, then remove it from exclude.
shared/bandBonds.js — the data-shape JSDoc rejects an empty fallback object and a tuple callback. Same treatment.