Forum teuk.org

🔭🦉 Mediabot v3: The Astronomy Tower Pass — observatory views, smarter games and safer maps

in Mediabot · started by TeuK · 4d ago

TeuK · 4d ago

Some updates add a command.

This one adds altitude.

Mediabot v3 has been growing fast lately: achievements, moods, duels, chronos, leaderboards, channel memory, games, metrics and drift tooling. That is exciting, but a larger castle needs more than new rooms. It needs signs on the doors, working staircases, good maps, and someone making sure the owls do not deliver the same message twice.

This pass is about that.

It makes the social layer more usable, more discoverable, more polite and better protected by tests.

No database schema change.

No destructive migration.

Just a careful climb up the Astronomy Tower to look at the whole system from above.


🔭 The idea: more magic, more manners

The goal was not simply to add more commands.

The goal was to make the recent features feel like part of Mediabot rather than a pile of shiny spells.

This update improves four big areas:

discoverability
channel diagnostics
game behavior
test coverage

In plain English:

users can find the new commands
admins can see what a channel allows
games behave more naturally
tests protect the dispatch layer and schema drift tooling

That is the difference between “the bot has features” and “the bot feels maintained”.


🧪 Dispatch integrity: protecting old spells from new ones

Before adding more behavior, the first step was to protect the command dispatch layer.

A new test was added:

t/cases/383_dispatch_integrity.t

It checks that public commands do not accidentally overwrite each other.

This matters because we already caught one subtle regression: the new leaderboard alias tried to reuse top, but !top was already a historical Mediabot command.

In a Perl hash, duplicate keys do not negotiate.

The last one wins.

So the test now protects this:

!top          -> historical top command
!leaderboard  -> new leaderboard
!lb           -> new leaderboard

It also verifies that the recent social handlers are exported and visible:

mbAchievements_ctx
mbProfil_ctx
mbRadar_ctx
mbDashboard_ctx
mbDuel_ctx
mbHoroscope_ctx
mbCompat_ctx
mbQuotegame_ctx
mbMood_ctx
mbLeaderboard_ctx
mbChronos_ctx
mbFeatures_ctx
mbObservatory_ctx

That is not glamorous.

But it is essential.

A command map should not be a Marauder’s Map with disappearing corridors.


⏳ Quotegame gets a real hourglass

!quotegame used to announce a 60-second timeout, but the timeout was lazy.

That meant:

the game said “60 seconds”
but if nobody talked after 60 seconds,
nothing happened until the next message

Functional, yes.

Elegant, no.

Now !quotegame uses a proactive IO::Async::Timer::Countdown.

Behavior is cleaner:

!quotegame starts a question
a 60-second timer starts
if nobody answers, the bot announces the answer
if someone answers correctly, the timer is cancelled
if !quotegame stop is used, the timer is cancelled
the old lazy timeout remains as a safety net

That turns the game into an actual game.

Not a game with a sleepy hourglass waiting for someone to poke it.


📚 Help topics for the new social layer

A lot of recent commands were powerful, but not easy enough to discover.

This pass improves the help system with direct topics:

!help social
!help games
!help stats
!help chansets

The social category now exposes commands such as:

achievements
profil
radar
dashboard
leaderboard
chronos
features
observatory
mood

The games category exposes:

duel
horoscope
compat
quotegame

And help chansets explains important channel flags:

+AchievementAnnounce
+Games
+UrlTitle
+Youtube
+YoutubeSearch
+RandomQuote
+Claude
+NoColors
+AntiFlood

This matters because a bot should not require archaeology to use.

Good features deserve good signposts.

Even Hogwarts had staircases. Confusing ones, yes, but still staircases.


🧭 !features: what can this channel do?

A new diagnostic command was added:

!features
!capabilities
!caps

It answers a simple but very useful question:

What is enabled on this channel?

Example concept:

🔭 Capabilities for #i/o
  🏆 achievements: on | announce: off | catalogue: 24
  🎲 games: on | commands: duel, horoscope, compat, quotegame
  🔗 links: UrlTitle=on Youtube=on YoutubeSearch=off
  💬 social memory: profil/radar/dashboard/leaderboard/chronos/mood available
  🤖 integrations: Claude=on RandomQuote=off Radio=off
  🛡 safety/output: AntiFlood=on NoColors=off Metrics=on

The output is sent as NOTICE to the requester.

That is intentional.

It gives admins and curious users useful information without spamming the channel.

A diagnostic spell should not explode in the common room.


📜 !chronos short|full: the saga can now whisper

!chronos is one of the most charming recent commands. It turns channel history into a small narrative timeline.

But sometimes you do not want the whole saga.

So chronos now supports:

!chronos short
!chronos full
!chrono short
!timeline full

The full mode keeps the existing narrative timeline.

The short mode gives a compact version:

📜 Chronos #i/o — genesis 2026-06-03 by Te[u]K | peak day 2026-06-05 (123 msgs) | karma king teuk (+42)
📍 now: last activity 2026-06-05 by MenzAgitat | use: chronos full

That gives the channel a memory without turning every request into a scroll from the Ministry.


🏅 !leaderboard learns time windows

!leaderboard can now use period filters where the underlying data has reliable timestamps.

Supported examples:

!leaderboard 24h
!leaderboard 7d
!leaderboard 30d
!leaderboard msgs 7d
!leaderboard karma 7d

The important part is honesty.

Period filters are supported only for categories with reliable timestamped sources:

msgs  -> CHANNEL_LOG.ts
karma -> KARMA_LOG.ts

The other categories remain all-time:

trivia
duels
achievs

If someone asks for something like:

!leaderboard trivia 7d

Mediabot does not fake it.

It explains that period filters are currently supported for messages and karma only.

That is the right behavior.

A scoreboard should be playful, but it should not lie.


🫀 !observatory: the channel from above

This is the feature that gives the pass its name.

New commands:

!observatory
!obs

The output is compact and public:

🔭 Observatory #i/o — alive 2d 04h | games on | achievements on (24) | announce off
🫀 last hour: 42 msg(s) / 8 nick(s) | energy lively | UrlTitle on | Claude on | AntiFlood on | metrics on

It combines:

process uptime
channel activity over the last hour
energy level
games status
achievement status
announcement status
selected chansets
metrics status

This is not a replacement for !features.

It is more like a live telescope view.

!features says what the channel can do.

!observatory says how alive it feels right now.

That is very Mediabot.

A little practical.

A little poetic.

Exactly the right balance.


📡 New metric

The observatory command also gets a Prometheus counter:

mediabot_observatory_total{channel}

Because of course the telescope should be observable.


🧬 Drift checker: reference data gets tests

The schema drift checker already learned to compare reference data such as CHANSET_LIST.

This pass adds a dedicated test:

t/cases/384_schema_drift_refdata.t

It verifies:

parsing INSERT INTO CHANSET_LIST
parsing INSERT IGNORE INTO CHANSET_LIST
detecting missing chansets such as Games
not spamming missing seed rows when CHANSET_LIST itself is absent
SQL quoting of apostrophes

The parser was also made slightly more flexible:

INSERT IGNORE INTO CHANSET_LIST (...) VALUES ...

is now accepted in addition to normal INSERT INTO.

This is not a database change.

It is future-proofing.

The map now understands another kind of ink.


🛡 No schema change

This pass deliberately avoids DB schema changes.

It uses what already exists:

CHANNEL_LOG.ts
KARMA_LOG.ts
CHANSET_LIST
CHANNEL_SET
in-memory duel stats
achievements JSON
Prometheus metrics

No table rewrite.

No migration drama.

No destructive SQL.

That restraint matters.

The recent feature work was already large enough. This pass improves the experience without moving the foundations.


🧪 Suggested checks

Syntax checks:

perl -I. -c Mediabot/Mediabot.pm
perl -I. -c Mediabot/UserCommands.pm
perl -I. -c Mediabot/Achievements.pm
perl -I. -c Mediabot/Helpers.pm
perl -I. -c Mediabot/Metrics.pm
perl -I. -c mediabot.pl

perl -c tools/check_schema_drift.pl
perl -c t/cases/382_check_schema_drift_parser.t
perl -c t/cases/383_dispatch_integrity.t
perl -c t/cases/384_schema_drift_refdata.t

git diff --check

Runtime smoke tests:

!top
!leaderboard
!leaderboard 7d
!leaderboard karma 7d
!quotegame
!quotegame stop
!help social
!help games
!help chansets
!features
!observatory
!chronos short
!chronos full

Watch logs for:

Undefined subroutine
Wide character
Incorrect string value
SQL error
Use of uninitialized value

🕯 Final note

This pass is the Astronomy Tower because it gives Mediabot perspective.

The bot can now explain more of itself. It can show what a channel allows. It can summarize the channel’s pulse. It can run a quote game with a real timer. It can show leaderboards over recent time windows. It can keep old commands safe while new ones arrive. It can test the maps it uses to compare databases.

That is what a mature bot needs.

Not just more spells.

Better instruments.

Sharper maps.

Quieter manners.

And a telescope pointed at the channel, just high enough to see the story forming.

🔭🦉✨

You must be logged in to reply.