Skip to content

fix(reload): instantiate reloaded command classes and drop removed triggers - #205

Merged
Rushaway merged 3 commits into
masterfrom
fix/189-reload-stale-classes
Oct 14, 2026
Merged

Rushaway merged 3 commits into
masterfrom
fix/189-reload-stale-classes

Conversation

@Rushaway

Copy link
Copy Markdown
Member

Stale command classes after !reload

Why: CommandHandler imported BaseCommand, Say and VoiceTrigger by name. Reload() re-executes torchlight.Commands, but Setup() then walked __subclasses__() on the old class objects, which those names kept alive. Every !reload re-instantiated the pre-reload classes, so code changes in Commands.py were never picked up.

Fix: Setup() resolves the classes through the module object (Commands.BaseCommand.__subclasses__(), Commands.VoiceTrigger..., Commands.Say...). Discovery semantics are unchanged (direct subclasses of BaseCommand plus subclasses of VoiceTrigger and Say, sorted by order desc). BaseCommand is now a typing-only import, so nothing at module level pins the first generation of classes. After a reload the old classes and old command instances are garbage-collectable.

Removed voice triggers survived !reload

Why: TriggerManager.Load() wrote into the existing self.voice_triggers and never cleared it, so triggers removed from triggers.json stayed active. sound_path was only read in __init__.

Fix: Load() builds triggers_dict, voice_triggers and the sound path into locals and swaps them in at the end. Removed triggers disappear, a malformed triggers.json (ConfigError) leaves the previous triggers intact, and Sounds.Path is re-read on every load.

Advertiser config not refreshed / config loaded twice

Why: OnReload refreshed anti_spam.config but not advertiser.config. It also re-read config.json, which Torchlight.Reload() had just done.

Fix: OnReload also refreshes audio_manager.advertiser.config and no longer calls config.load(). Torchlight.Reload() stays the only place config.json is re-read on reload, so a malformed config.json still raises ConfigError to the !reload caller before any OnReload state is swapped.

Persistent caches still live outside Commands.py (GeoIP.py is untouched).

Test plan

I ran a throwaway script (not committed) against a temp copy of config/, with the real Config, Torchlight, AudioManager, AccessManager, TriggerManager, SourcemodConfig and CommandHandler. It ran the full Torchlight.Reload() → OnReload path on origin/master and on this branch:

Check master this PR
type(cmd) is Commands.<Name> for every command after reload False True
Same set of 24 commands loaded after reload True True
config.load() calls per reload 2 1
Trigger removed from triggers.json gone from voice_triggers and VoiceTrigger.triggers False True
Sounds.Path change picked up False True
advertiser.config refreshed False True
Old class (weakref) collected after gc.collect() False True
Old command instances collected True True
Malformed triggers.json → ConfigError, previous triggers kept True True
Malformed config.json → ConfigError propagates from Torchlight.Reload() True True

No VERSION bump (batch policy, see #177).

Closes #189
Part of #177

🤖 Generated with Claude Code

…iggers

CommandHandler imported BaseCommand/VoiceTrigger/Say by name, so after
reload(Commands) Setup() still walked the pre-reload class objects and
re-instantiated old code. Resolve the classes through the Commands
module at Setup() time and keep BaseCommand as a typing-only import so
nothing pins the old classes.

TriggerManager.Load() now builds voice_triggers into a fresh dict and
swaps it in at the end, so triggers removed from triggers.json disappear
and a failed load keeps the previous triggers. Sounds.Path is re-read on
every load.

OnReload no longer re-reads config.json (Torchlight.Reload already did,
and still raises ConfigError before any callback runs) and now also
refreshes the advertiser config.

Closes #189

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Rushaway
Rushaway merged commit 5690552 into master Oct 14, 2026
2 checks passed
@Rushaway
Rushaway deleted the fix/189-reload-stale-classes branch October 14, 2026 11:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

!reload re-instantiates the pre-reload command classes and never drops removed voice triggers

1 participant