• v5.3.6 770c72a5b5

    v5.3.6
    All checks were successful
    CI / build-and-test (push) Successful in 2m12s
    CI / docker-build (push) Successful in 24s
    Stable

    joeyr released this 2026-10-10 12:48:38 -05:00 | 2 commits to main since this release

    The last 22 findings from the whole-repo review, each minor or rare. LoL
    results survive a restart and a watchlist change, registering checks the
    region and Riot ID first, failed buttons say so, a broken mappings file no
    longer wipes names, and the logs keep their details and never show the
    database password. A setting that did nothing, D2EMU_POLL_INTERVAL_MS, is
    gone.

    Fixed

    • A LoL result still pending when the bot restarted was never posted.
      Riot can take a few minutes to publish a finished match, and the bot keeps
      checking for it in the background. A restart in that window, such as a
      deploy, stopped the checks and nothing started them again, so the post said
      "results unavailable" for good. After a restart the bot now picks up any
      result from the last half hour that never arrived.
    • A restart could drop a LoL game's result over one failed Riot call. On
      startup the bot checks whether each game it was following is still on. One
      timeout or busy answer from Riot at that moment wrote the game off, so if it
      had ended, its result never appeared. The game is now checked again on the
      next poll, as it already was outside a restart.
    • Removing a player from the watchlist mid-game could cost that game its
      result.
      A game is followed through the first watched player found in it.
      If that player was removed while it was on, nobody noticed it end, and it
      was written off hours later with no result. Another watched player in the
      game now takes it over, and the result shown is theirs.
    • A LoL game that came back from a false end could lose its ranks and
      result after the notification channel changed.
      Riot sometimes briefly
      reports a live game as over, and when it reappears the bot edits its
      original post back. If monitor-channel had moved notifications meanwhile,
      the bot then looked for that post in the new channel, so the ranks and the
      result never arrived. It now follows the post in the channel it is in.
    • The cleanup of stuck LoL games always reported none. Its count was
      always 0, so its log line never appeared, and the games it closed had no
      end time. It now reports how many it closed and records when.
    • A LoL player registered under a region they don't play on was accepted,
      and their games were never posted.
      Riot finds an account whatever region
      is typed, so the wrong region was stored and their games were looked for on
      the wrong server. Register and monitor-add now ask Riot where the player
      plays and register them there, and say so when it differs from what was
      typed. If Riot can't be asked, the typed region is used as before.
    • A mistyped LoL region or a name without its #TAG got "try again
      later".
      Neither was checked until Riot was asked, so input that could
      never work failed as if Riot were down, and was logged as an error.
      Register, unregister, monitor-add and monitor-remove now reply at once with
      the valid regions or the Name#TAG format.
    • A connection to Riot that dropped mid-answer was logged as a bug in the
      bot.
      A cut-off response surfaced as a bare TypeError rather than a
      network error. It is now reported, and handled, like any other network
      failure.
    • Every query-chat answer said "(with context: last 1 hours)". The
      default one-hour window was named on every answer, private and public,
      though nobody chose it, and a follow-up reads what was said since the last
      question rather than an hour anyway. The header now names a window only when
      the asker typed one, and says "1 hour", not "1 hours".
    • /aufhocker espnff help said the fantasy server wasn't connected when it
      was.
      When the server was up but none of its tools were open to the person
      asking, help said "not connected" while espnff mcp said connected. Help
      now says the same as espnff mcp, and no longer retries a server that is
      already up.
    • A web page with one bad character code couldn't be read. A numeric
      character code past the last valid one, such as �, failed the
      whole fetch, so Claude answered without the page. The code is now left as
      written and the rest of the page comes through.
    • When chat history was too long to send in full, part of a multi-line
      message could lose its author.
      If the cut fell inside a message several
      lines long, its last lines were kept without the name and time, so Claude
      read them as nobody's, or as the next person's. A message is now either
      kept whole or left out.
    • Buttons and menus that hit an error showed only "This interaction
      failed".
      The bot logged the error but never answered the click. The
      clicker now gets a private error message, and the message the button sits
      on is left alone.
    • The role sign-up board couldn't be posted with one role for both games,
      and the bot blamed a permission.
      Each button needs its own role, so
      Discord refused the board, and the bot told the admin to check its Send
      Messages permission. The command now asks for a different role per game up
      front, and a post that fails for any other reason no longer blames
      permissions unless Discord said so.
    • Reloading name mappings from a broken file erased every real name. If
      user-mappings.json had a typo or was missing, /aufadmin reload-mappings
      dropped every mapping, reported success, and the bot fell back to Discord
      usernames everywhere. A file that can't be read now leaves the current names
      in place, and the command says the reload failed.
    • The startup log could show part of the database password. A password
      holding an @ followed by /, ? or # (or digits followed by # or
      ?), pasted into DATABASE_URL unencoded, confused the address parser, and
      pieces of it were logged as the database host, port or name on every boot.
      When the address can't be read with certainty, the line now says
      (unparseable) and shows nothing from it.
    • The startup checks said only "fetch failed" when a service couldn't be
      reached.
      The real reason (address not found, connection refused, a bad
      certificate) was dropped, so DNS, firewall and TLS problems all looked the
      same. The check now names it. Any token or password is removed from the
      line first, including one the error text quoted back, which could already
      happen before.
    • A crash caused by an unusual error could skip the clean shutdown or log
      no reason.
      When code threw something that wasn't a normal error, the crash
      handler either crashed itself, exiting without closing the database or
      Discord, or logged a line with no reason in it. It now logs what was thrown
      and always shuts down properly, and normal errors keep their type and cause.
    • A log line whose text contained a % sign could lose its details,
      including the error.
      The logging library treats %s, %o, %% and the
      like as fill-in markers, and a message with one dropped everything logged
      with it; a user typing 50%off was enough. The details are now always kept,
      and the text is left exactly as written.
    • A number setting written as 10_000, 1e4 or 30s was quietly cut
      short.
      Only the leading digits were read, so CLAUDE_MAX_TOKENS=10_000
      ran as 10 tokens and RATE_LIMIT_INTERVAL_MS=30s as 30 milliseconds, and
      the startup check passed both. Number settings must now be plain digits, and
      anything else stops the bot at startup with an error naming the setting.
      Every shipped config file and the Swarm stack already use plain digits.
    • The connection that runs migrations ignored
      DATABASE_SSL_REJECT_UNAUTHORIZED.
      With DATABASE_SSL=true, the bot's own
      connection verified the database server's certificate, but the one that
      applies schema changes at startup accepted any. Both now use the same SSL
      settings. The live stack runs with DATABASE_SSL=false, so it is unaffected.
    • CI's dependency audit passes again. handlebars 4.7.9 had newly
      published critical advisories. It is dev-only, reached through
      ts-jest, so it was never in the production image, and 4.7.10, within the
      range ts-jest asks for, fixes it.

    Changed

    • D2EMU_POLL_INTERVAL_MS is removed. It looked like it set how often the
      D2 tracker polls, but nothing read it: Terror Zones are checked on the
      5-minute marks and DClone every 10–30 seconds. A stack that still sets it
      gets a startup warning saying it is ignored, so remove it from the stack.
    Downloads