- /tg-admin result post-all [slot:] — posts/updates every TG result for a
slot (default 20:00) in one pass, not one at a time
- Officers can add a late-arriving player to a poll (locked or not) so
they can submit a score instead of hitting "You weren't in this TG":
/tg poll add-attendee (single, autocomplete) and /tg-admin poll
add-attendees (modal, comma/newline-separated, for adding several at
once — Discord modals can't hold select menus, only text inputs)
- fix: /tg-admin result post, leaderboard post, and leaderboard
post-highlights had no permission check at all — any guild member could
invoke them
- fix: --register never exited after registering slash commands, so it
kept running as a full second bot instance forever. Every docker exec
--register run stacked another live process on top of the container's
real one, each independently connected to Discord — root cause of /tg
poll start posting multiple polls and vote/submit state acting confused
(confirmed 3 live processes via docker top, cleaned up)
- fix: bot startup poll-restore logic had the same stale-button-
resurrection bug already fixed in /tg poll reload, in a sibling code
path that got missed — now respects scoreSubmitOpen/buttonsRemoved
there too instead of re-deriving from locked/confirmed
- rename: officer -> moderator throughout (Config.roles, hasOfficerRole,
all "officer only" text, /tg-config roles set/add/remove/reset-*
commands). Config.load() auto-migrates a legacy roles.officer key on
read so existing deployed config.json files don't silently reset.
Slash command names changed — re-register after deploying.
- data/updates v0.10.3 changelog for the above
- Result.post() now returns { ok, reason } instead of void — it used to
silently no-op (unconfigured channel, or zero rows built) while
/tg-admin result post always reported success regardless
- Fixed a crash when a TGScore's class is missing and the character it
names is gone from CharacterRegistry (orphaned history) — Emoji.class()
and Emoji.nation() now degrade to a placeholder instead of throwing
- Fixed tg-history files being written with only a scores array, missing
date/confirmed/nationKD — Score.submit's loadHistory now fills in the
full TGResult shape on every read; scripts/migrate-history-shape.py
backfills existing files (50 fixed in dev, run on prod too — this
script is gitignored like the other migration scripts, copy manually)
- ATK/DEF/Heal shorthand parser: accepts comma as a decimal separator
(3,4M == 3.4M), and rejects implausibly large values (150.0M, or an
already-full number with a redundant M) via a configurable ceiling
(Config.tg.maxStatValue, default 50,000,000, /tg-config tg
set-max-stat-value) instead of silently producing multi-billion junk
- data/updates v0.10.1 (result posting fixes) and v0.10.2 (parser
refinements) — sequenced after the already-deployed v0.10 rather than
backfilling v0.9.x, since posting order in #updates is what matters
- new announcement (002) explaining the shorthand input change to players
- doc updates: REFERENCE.md and MERGE_CHECKLIST.md cover all of the above
- ATK/DEF/Heal now accept K/M shorthand (500K, 1.4M, case-insensitive) via
a shared parser (@helpers/stat-value), used identically by the Submit
Score modal, /tg score set, and /tg-admin score-inject
- /tg-admin score-modal — officers can open the Submit Score modal on
behalf of any player; the modal's customId now carries the target
userKey so submission always resolves to the intended player rather
than whoever's Discord client is submitting it
- fix: /tg call now actually reveals the Submit Score button (was
recording the call but never opening submission)
- fix: /tg poll reload no longer resurrects Submit Score / Yes-No buttons
that had already been removed — poll state now tracks submission-open
and buttons-removed explicitly instead of re-deriving it from
locked/confirmed on every render
- fix: midnight cleanup now fully removes all poll buttons (not just
Submit Score) instead of leaving them disabled
- Sleep Check — players on a configured role get flagged (💤 shown on
their poll row) the moment they vote Yes; a scheduled per-slot job DMs
everyone currently flagged at a configurable time before TG (default
20 min). State changes and DM sending are intentionally decoupled —
flagging never itself sends a message. Officers can also flag/clear
manually via /tg-admin sleep-check set|clear
- data/updates/v0.9.2 and new v0.10 changelog entries for the above
- merged the two .claude reference docs into one, removed stale/fixed
items, documented the new systems and known deferred gaps
- Score.submit/score/set.ts/score-inject.ts now all share one code path
- TGScore consolidated to single canonical type (was duplicated in types.ts and score.ts)
- Fixed atk/def/heal flat-vs-nested TGStats drift across leaderboard.ts, result layouts
- Fixed playedBy semantics — now correctly identifies the actual player on borrowed characters
- Attendance.allSubmitted now correctly matches against playedBy (borrower) not just userKey (owner)
- score-inject gained atk/def/heal/date/played_by parameters for full parity with real submission
- Added migrate-stats-shape.py and fix-class-keys.py maintenance scripts
- TextAlign: column alignment for embeds using real gg sans font metrics
- EmbedHelpers: per-player grid/column layouts immune to 1024-char field limit
- Layout: domain-aware formatting wrapper (wrank, bringer, cockroach, tgCount)
- PersistentMessage: multi-slot support for independently-updatable embeds
- Leaderboard: weekly rankings + highlights embed (most kills/deaths, next Bringer)
- Result: per-TG breakdown with wRankAtSubmission snapshot for historical accuracy
- /tg call, /tg poll confirm-no, /tg-admin score-inject, result/leaderboard post commands
- Fix: CharacterRegistry wasn't hydrating ownerKey, breaking K/D bot-wide
- Fix: Leaderboard.buildEntries used current week instead of passed-in week param
- /tg-admin test-align: permanent calibration tool for embed text alignment
Includes data/emojis/anima-mastery.json for new combat stat icons.