Forum teuk.org

🐺🪶 Mediabot v3: The Wolfhound Audit — safer exits, sharper maps and restored old spells

in Mediabot · started by TeuK · 3w ago

TeuK · 3w ago

Some Mediabot updates arrive with new toys.

This one is different.

This is the kind of pass that does not try to impress the room immediately. It sharpens the knife, oils the hinges, checks the hidden staircases, and makes sure the old spell still points to the right wand.

It fixes real bugs:

a schema parser confused by comments
fresh achievements that could be lost during shutdown
duel streaks that could never properly trigger Underdog
a historical !top command shadowed by a newer alias

No database schema change. No migration drama. Just cleaner behavior, safer tooling, and fewer cursed corners.

Welcome to the Wolfhound Audit pass.


🐺 Why “Wolfhound”?

Because this update is not flashy.

It is loyal.

It guards the doorway.

It notices the weird sound in the wall before the wall starts moving.

Mediabot has recently gained social features, achievements, games, leaderboards, timelines and richer channel awareness. That is great. But once the castle gets larger, you need better patrols.

This pass is one of those patrols.


🧭 Drift checker: the map gets less gullible

The schema drift checker had already been improved to stop producing cursed SQL like:

ALTER TABLE `KARMA_LOG` ADD COLUMN `COMMENT` 'Vote timestamp';

That bug came from parsing SQL too naively.

This pass goes further.

The parser now handles another subtle case:

`id` INT, -- comment with, commas, inside
`name` VARCHAR(64)

And also:

`id` INT, # MySQL-style comment with, commas, inside
`name` VARCHAR(64)

That matters because comments can contain commas, and a parser that splits blindly on commas will eventually invent nonsense.

The drift checker now understands more of the real SQL shape:

multi-line column definitions
COMMENT attributes
ENUM(...) values
quoted strings
backticked identifiers
inline -- comments
inline # comments
top-level commas only

The map is still a tool, not a full SQL engine. But it is much harder to trick now.


📜 Reference data drift: chansets are not optional decoration

The checker also learned to pay attention to CHANSET_LIST.

That table is not ordinary user data.

It defines runtime features:

AchievementAnnounce
Games
UrlTitle
Youtube
Claude
RandomQuote

So when the schema says a chanset exists but the live DB does not have the row, that is a real drift.

The checker can now detect missing reference rows and generate safe idempotent SQL such as:

INSERT INTO `CHANSET_LIST` (`id_chanset_list`, `chanset`)
SELECT 16, 'Games'
WHERE NOT EXISTS (
  SELECT 1 FROM `CHANSET_LIST` WHERE `chanset` = 'Games'
);

That is exactly the kind of output we want:

reviewable
safe to rerun
non-destructive
clear

And if the whole CHANSET_LIST table is missing, the checker no longer screams about every missing seed row. It reports the missing table and stops there.

Less noise. Better signal.


🏆 Achievements: no more lost trophies on shutdown

Achievements are persisted to JSON.

That is clean and avoids a schema change.

But there was a subtle shutdown risk.

Achievements are saved with a debounce so the bot does not write too often. That is usually fine.

But if an achievement unlock happened near shutdown, the latest unlock could exist only in memory and not yet on disk.

This pass adds a forced flush during clean_and_exit():

$self->{achievements}->save(1);

It happens before DB disconnection and is protected by eval, so shutdown remains safe.

Small fix. Big peace of mind.

Nobody wants to earn a rare badge and have it vanish like a badly handled Portkey.


⚔️ Duel streaks: Underdog can finally happen

The duel system had a logic bug in streak tracking.

The idea was simple:

lose several duels in a row
then win
unlock Underdog

But the old streak logic did not properly reset winners and losers when the direction changed.

A player with a winning streak who lost would not become -1 loss streak cleanly.

That broke the logic behind the Underdog achievement.

The new logic is clearer:

winner:
  if previous result was win, increment positive streak
  otherwise reset to +1

loser:
  if previous result was loss, decrement negative streak
  otherwise reset to -1

The underdog check is evaluated before overwriting the previous streak.

That means the expected scenario now works:

A loses 5 times
A wins next duel
A qualifies as underdog

That is fair. And more importantly, it is finally trackable.


🧙 !top: the old spell is restored

A subtle regression was found before commit.

The new leaderboard feature had added top as an alias.

But Mediabot already had a historical !top command.

In a Perl hash, duplicate keys do not coexist politely.

The last one wins.

So the newer alias could shadow the old command.

That is not acceptable.

This pass preserves the old behavior:

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

That is the right compromise.

New magic should not steal an old wand.


🧪 Parser tests: the cursed parchment is now locked in a cabinet

A new test file was added:

t/cases/382_check_schema_drift_parser.t

It covers the important parser cases:

multi-line COMMENT attributes
inline -- comments with commas
inline # comments with commas
-- inside strings
# inside strings
ENUM values
nested parentheses
reserved keyword guards
table constraints

That is valuable because this bug class is sneaky.

Without tests, it comes back.

With tests, the next person who breaks it gets caught by the gargoyle at the door.


🧯 No schema change

This is worth repeating:

No database schema change.
No destructive migration.
No DROP.
No table rewrite.

This pass improves code and tooling only.

The existing database stays where it is.

That is exactly the kind of update you want after a larger feature series.


🧪 Suggested validation

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

git diff --check

Runtime checks:

!top
!leaderboard
!lb
!chronos
!achievements
!duel SomeNick

Expected behavior:

!top keeps the old behavior
!leaderboard and !lb use the new leaderboard
!chronos still works
duel streaks update correctly
achievements are still saved

Drift checker check:

tools/check_schema_drift.pl --conf=mediabot.conf --generate-migration

Expected improvement:

no fake ADD COLUMN COMMENT
inline comments do not corrupt parsing
missing CHANSET_LIST rows are detected
missing CHANSET_LIST table does not produce noisy seed spam

🕯️ Final note

This update is quiet, but important.

It does not add a spectacular command.

It makes existing things safer.

It protects old behavior. It preserves earned achievements. It makes duels fairer. It teaches the drift checker not to hallucinate SQL. It adds tests around the exact place where the parchment used to be cursed.

That is good engineering.

Not the fireworks kind.

The kind that lets the fireworks happen later without burning down the tower.

🐺🪶🧭

You must be logged in to reply.