Forum teuk.org

🪄 Mediabot v3: The Quiet Charms Pass — Caches, Counters, Karma and Tiny Invisible Fixes

in Mediabot · started by TeuK · 3w ago

TeuK · 3w ago

Some updates arrive like a dragon through the Great Hall.

This one did not.

This was quieter: a set of small charms placed carefully where the bot needed them most. Not flashy, not noisy, but the kind of work that makes the whole castle feel better kept.

This pass is about finesse:

  • metrics that were silently missing;
  • caches that needed proper invalidation;
  • karma and trivia counters becoming more useful;
  • wordcount becoming a little smarter;
  • Partyline status becoming more truthful;
  • fewer unnecessary SQL queries;
  • and a few hidden traps removed before they could become real bugs.

No fireworks.

Just the sort of spellwork Professor Flitwick would approve of.


🧭 What changed in this pass

This update follows the mb110 to mb115 polish line.

The main areas touched were:

Mediabot/Metrics.pm
Mediabot/Helpers.pm
Mediabot/ChannelCommands.pm
Mediabot/UserCommands.pm
Mediabot/Partyline.pm

No database schema change was needed.

That matters. This was not a migration pass. It was a refinement pass: tune what already exists, declare what was already being used, and make the runtime behavior more honest.


📊 Prometheus: silent counters are no longer silent

A very important issue was found in the metrics layer.

Some counters introduced during earlier improvements were being incremented in the code, but not declared in Mediabot::Metrics.

That meant the code could call the metric, but Metrics::add() would silently return without exposing anything.

The bot did not crash.

The dashboard simply never saw the spell.

That is worse in a way, because silent observability bugs are easy to miss.

This pass declares the missing metrics for URL titles, Claude, YouTube search, nick changes, joins, parts and trivia-related counters. It also adds the later missing counters for:

mediabot_karmahist_requests_total
mediabot_wordcount_requests_total

That means the bot now says what it is doing in a way Prometheus can actually hear.


🧮 wordcount: now counted, ranked, and less misleading

!wordcount received a careful polish.

First, it now increments:

mediabot_wordcount_requests_total

So usage of the command can be tracked.

Second, the command can now show a lightweight channel activity rank for the nick when no period filter is used.

Example:

!wordcount teuk

Can now include something like:

activity rank: #3

The wording matters.

This is intentionally called an activity rank, not a perfect distinct-word rank for every nick. A true distinct-word rank would require a much heavier tokenization pass across the whole channel history.

So the command now gives useful context without pretending to be more exact than it is.

Small honesty charm. Very important.


🧹 Removed a hidden SQL trap

During the wordcount rank work, a dead prepare() block was spotted.

It referenced an alias that did not exist:

n.n

Even if the query was not actually executed, keeping invalid SQL inside a prepare() is the kind of thing that waits patiently in a cupboard until the wrong driver, version or runtime path opens the door.

That block is gone.

The remaining query is simpler, parameterized, and honest about what it measures.

No boggart left behind the bookshelf.


🧙 Partyline .stat: reporting the real counters

Partyline .stat was reading a metric that did not exist:

mediabot_commands_total

But the real counters are split more precisely:

mediabot_commands_public_total
mediabot_commands_private_total
mediabot_commands_partyline_total

The status output now uses the real counters and reports IRC public, IRC private and Partyline command totals separately.

That is better than inventing one big number that was not actually there.

A good status command should not use divination when the ledgers are available.


⚡ Chanset cache: faster, but now properly invalidated

The getIdChannelSet() helper gained a TTL cache earlier to avoid hammering the database on every outgoing bot message.

That was a good performance improvement, because outgoing messages can check things like:

AntiFlood
NoColors
UrlTitle

very frequently.

But a cache that does not invalidate after a !chanset change can be annoying:

!chanset +UrlTitle

followed immediately by a URL should behave immediately, not two minutes later.

This pass keeps the cache, but invalidates it after changes in channelSet_ctx.

That is the right balance:

fast when idle
fresh when changed

A proper little Time-Turner, but with rules.


🔐 User level caches: fewer repeated SQL lookups

Two permission paths were improved.

checkUserLevel()

USER_LEVEL is static at runtime, but the bot was querying it repeatedly for command permission checks.

Now the level table is cached lazily in memory.

That saves repeated SQL lookups during command handling.

checkUserChannelLevel()

Channel-specific user levels are more dynamic, so this cache is shorter lived:

TTL: 60 seconds

And it is invalidated immediately when channel users are added or removed.

That avoids the classic bug:

add user
then immediately try chanset
but old cache still says no

Again: fast, but not stale when it matters.


🪙 Karma: more useful windows and clearer memory source

!karmainfo gained a period option:

!karmainfo teuk 7d
!karmainfo teuk 24h

That makes the command more useful when you care about recent mood rather than all available memory history.

It also shows the memory source more clearly, keeping it consistent with !karmahist.

The bot now better distinguishes between:

current score
recent memory/log window
direction of recent votes

Karma is still silly, obviously.

But if we are going to be silly, we may as well be precise.


🏆 Trivia: questions now have their own counter

Trivia already had counters for correct answers and timeouts.

But to calculate useful rates, you also need the denominator:

How many questions were asked?

So this pass adds:

mediabot_trivia_questions_total

That makes dashboards much more meaningful.

Now Grafana can show things like:

correct answers / questions asked
timeouts / questions asked

That turns trivia from “some fun in a channel” into something observable.

A scoreboard for the scoreboard.


🧪 Why this pass matters

This is not the sort of update where users will immediately say:

Wow, everything is different.

Good.

They should not.

The best parts of this pass are deliberately invisible:

  • fewer SQL queries per command;
  • metrics that actually appear;
  • caches that do not lie after changes;
  • status commands that report real counters;
  • wordcount that avoids misleading wording;
  • hidden invalid SQL removed before it becomes a bug.

That is the quiet maintenance work that makes long-running IRC bots survive.

Mediabot is getting less fragile.

Not because one giant spell was cast, but because a dozen small charms were placed exactly where they belonged.


🧪 Suggested checks

Before calling it done:

perl -I. -c Mediabot/Metrics.pm
perl -I. -c Mediabot/Helpers.pm
perl -I. -c Mediabot/ChannelCommands.pm
perl -I. -c Mediabot/UserCommands.pm
perl -I. -c Mediabot/Partyline.pm

git diff --check

Live checks:

m wordcount teuk
m wordcount teuk today
m karmahist teuk
m karmainfo teuk 7d
m trivia

Partyline:

.stat
.metrics

Prometheus:

mediabot_karmahist_requests_total
mediabot_wordcount_requests_total
mediabot_trivia_questions_total
mediabot_commands_public_total
mediabot_commands_private_total
mediabot_commands_partyline_total

🕯 Final note

This was the Quiet Charms pass.

No phoenix. No dragon. No dramatic duel in the Astronomy Tower.

Just well-placed spellwork:

declare the counters
invalidate the caches
name the rank honestly
trust the real metrics
remove the trap before it bites

Mediabot v3 is a little faster, a little clearer, and a little more truthful about what it is doing.

That is not spectacular magic.

That is better.

That is craft.

You must be logged in to reply.