• v1.12.0 fc0f22ce04

    v1.12.0 — boot preflight
    All checks were successful
    CI / build-and-test (push) Successful in 1m54s
    CI / docker-build (push) Successful in 23s
    Stable

    joeyr released this 2026-08-03 07:24:01 -05:00 | 1 commits to main since this release

    The last of three releases on the log output, and the one that changes what the
    logs are for. The first two made a line readable; this one makes the bot say at
    boot whether it can actually do its job.

    The problem with apiKeyConfigured: true

    The startup banner reported that every credential was a non-empty string. That
    is not the same as working, and every dependency this bot has was therefore
    discovered broken at the moment of use:

    • A dead RIOT_API_KEY turns the LoL plugin's API clients into no-op stubs that
      return "no game" forever — indistinguishable from a healthy monitor whose
      players simply are not playing.
    • A bad BRAVE_SEARCH_API_KEY surfaces the first time an admin runs
      web_search, which may be days later.
    • A d2emu outage surfaces as a terror-zone rotation nobody was told about.

    In each case the container is up, healthy, and reporting nothing wrong, because
    it has not yet tried anything.

    The block

    2026-08-03 07:17:38 INF preflight/db      > ok       server=PostgreSQL 16.3
    2026-08-03 07:17:38 INF preflight/discord > ok       bot=aufhocker id=1429626051755118693
    2026-08-03 07:17:38 INF preflight/claude  > ok       model=claude-sonnet-5
    2026-08-03 07:17:38 ERR preflight/riot    > FAILED   reason=platform-data returned HTTP 403
    2026-08-03 07:17:38 INF preflight/ddragon > ok       patch=16.15.1
    2026-08-03 07:17:38 INF preflight/brave   > skipped  reason=admin tools are disabled
    2026-08-03 07:17:38 INF preflight/d2emu   > ok       current=5
    2026-08-03 07:17:38 ERR preflight/summary > preflight found problems; starting anyway  failed=riot
    

    Seven checks, one request each, run concurrently under a 10s cap — so the block
    costs one timeout rather than seven. Each gets its own caller, which is what
    makes it read as a checklist rather than seven unrelated boot messages.

    Design

    • Loud, never fatal. Nothing here can stop the bot. A dead Brave key must
      not cost the chat command that has nothing to do with it, and a boot that
      exited would have Swarm restart it in a loop — churning away the very lines
      that say what is wrong. The checks report; the operator decides.
    • Probes, not retries. One shot, hard timeout. A dependency that is merely
      slow at boot is not worth delaying the boot over, and the answer a retry would
      eventually get is the answer the first real use will get for itself.
    • skipped means switched off, not unconfigured. ENABLE_ADMIN_TOOLS=false
      is the only input that produces one. A missing credential on a dependency that
      is supposed to be running reports failed — otherwise a
      BRAVE_SEARCH_API_KEY dropped from the secret set would look identical to one
      deliberately left out, and the block would train you to ignore it.
    • The Claude check is a model lookup, not a message: no tokens, and it also
      catches a CLAUDE_MODEL that does not exist. Config.validate() only warns
      when the value matches a known-retired prefix, so a misspelled model — or one
      retired after that list was written — currently surfaces as a 404 on the first
      question someone asks the bot.
    • Riot uses platform-data because it is the only key-authenticated Riot
      endpoint taking no parameters; every call the monitor actually makes needs a
      puuid, a tier or a match ID, none of which exist at boot. What is being
      checked is the key.
    • No credential is logged, in any form — not even a prefix. A prefix is
      still enough to pair with a leak elsewhere, and which key is configured has
      never been the question. There is a test asserting no configured secret
      appears anywhere in the reported outcomes.

    Also

    • DatabaseConnection.serverVersion()SELECT version() trimmed to
      PostgreSQL 16.3. The same round trip as SELECT 1, and it is the difference
      between "the database answered" and "the database I meant answered".
    • Fixed a flaky ContextManager property test that failed on roughly one seed
      in ten. The generators draw user and bot message content from one pool, so
      they could collide, and "bot content never appears in the context" then failed
      because a user had said the same thing.

    Minor rather than patch for the new boot output. No schema, command, or
    config-input changes, and nothing to do on the stack. This completes the
    Portainer work across 1.10.0 → 1.12.0: all five keys the dashboard renders are
    in use, and the boot block now proves the dependencies behind them.

    Downloads