Skip to content

[bug] Discord gateway hot-reload can crash router when config payload omits activeModeTiers #13

Description

@lyrishark

Discord gateway partial config hot-reload can crash router timer

Summary

Saving Discord settings from the UI can hot-reload the Discord message router
with a partial gateway config that omits activeModeTiers. A background router
timer later reads activeModeTiers.rateWindowMinutes, throws a TypeError, and
can take down the daemon. The Discord Hub can then remain disconnected even
though Gateway is enabled in settings.

Observed locally

  • Settings showed gatewayEnabled: true.

  • /api/discord/status returned gatewayEnabled: true and connected: false.

  • Daemon stderr showed:

    TypeError: Cannot read properties of undefined (reading 'rateWindowMinutes')
        at MessageRouter.pruneStaleTimestamps (.../src/discord/router.ts:643:45)
    
  • The Hub disconnected-state copy said Not connected. Enable Gateway in Settings to connect. even when Gateway was already enabled.

Root Cause

updateDiscordGatewayConfig() built a merged config for persistence, but passed
the original partial browser payload into MessageRouter.updateConfig(). The UI
save payload does not include activeModeTiers, so the running router could lose
the nested defaults while still being typed as DiscordGatewayConfig.

Local Patch

  • Added normalizeDiscordGatewayConfig() to fill all gateway defaults,
    including nested activeModeTiers.
  • Used the normalizer when loading saved gateway config.
  • Used the normalized config for server persistence and router/gateway
    hot-reload.
  • Added a defensive normalization step inside MessageRouter constructor and
    updateConfig().
  • Updated the Discord Hub disconnected message to distinguish:
    • Gateway disabled.
    • Gateway enabled but no bot token.
    • Gateway enabled but Discord still disconnected.
  • Added discord_gateway_config_test.ts covering normalizer defaults and the
    partial hot-reload path.

Verification

  • deno fmt --check passed for touched files.
  • deno test -A --no-check packages/psycheros/tests/discord_gateway_config_test.ts
    passed (2 passed).
  • Plain deno test -A ... is still blocked by a pre-existing Windows timer type
    error in src/scheduler/scheduler.ts.
  • Mirrored patch into the installed source under
    C:\Users\rache\AppData\Roaming\Psycheros\source.
  • Restarted the installed daemon and verified port 3000 responds.
  • Live hot-reload verification:
    • Posted a gateway config payload with activeModeTiers removed.
    • Server responded { "success": true }.
    • Re-read config and confirmed activeModeTiers.rateWindowMinutes was restored
      to 60.
  • Rendered /fragments/discord in the in-app browser and confirmed the new
    disconnected message appears while the old "Enable Gateway" copy does not.

Notes

The local saved bot token looked too short for a normal Discord bot token, so the
gateway may remain disconnected until a valid token is saved. That appears
separate from the router crash.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions