Forum teuk.org

🧪🦇 Mediabot v3: The Bat-Signal Audit — cleaner AI forgetfulness, sharper partyline parsing and quieter runtime costs

in Mediabot · started by TeuK · 3d ago

TeuK · 3d ago

Some updates are fireworks.

This one is a lantern in a dark corridor.

It does not add a huge public feature. It does something better before a release: it checks the corners where small bugs like to sleep.

This pass focuses on three practical things:

Claude memory cleanup must really clean memory
Partyline .top must parse exactly what the user means
Hailo exclusion checks should not hit SQL on every message

No database schema change.

No migration.

No grand staircase moving under our feet.

Just runtime sanity, better tests, and a few old cobwebs removed before they become spiders.


🦇 Why “Bat-Signal Audit”?

Because this pass is about finding small things in the dark.

The bot was already working. The recent social and observability features were in place. But after a fast development run, the right thing to do is not immediately add another spell.

The right thing is to ask:

What did we miss?
What silently behaves wrong?
What passes tests but not reality?
What costs too much in a hot path?

That is exactly what this audit did.


🧠 Claude !ai forget: now it really forgets

The most important fix in this pass is in:

Mediabot/External/Claude.pm

The issue was subtle but real.

Claude history and Claude persona did not use the same key convention:

history -> raw IRC nick
persona -> lower-cased IRC nick

That means a nick like:

Teuk
Boole
MalNick

could run:

!ai forget

and receive a reassuring message, while the actual history could remain untouched.

Not great.

A privacy-related command should not be mostly ceremonial.

The fix now uses the right key for each store:

my $chan_part   = (defined $channel ? $channel : '__private__');
my $hist_key    = "$nick\x00$chan_part";
my $persona_key = lc($nick) . "\x00" . $chan_part;

Then it deletes exactly what should be deleted:

delete $self->{_claude_history}{$hist_key};
delete $self->{_claude_persona}{$persona_key};

That is the important distinction.

Claude history follows the raw IRC nick.

Persona follows the lower-cased nick.

Two stores. Two conventions. No more pretending one key fits both.


🧪 The test now checks the real source

The previous test simulated the correct behavior, but did not guarantee that the real Claude.pm implementation had actually changed.

That is the kind of test that makes you feel safe while the trapdoor is still open.

So the test was hardened.

t/cases/384_mb122_partyline_top_and_claude_forget.t now includes source-level assertions to ensure:

history key uses raw $nick
persona key uses lc($nick)
the old lc($nick) history key does not return

It also now supports direct execution as well as loading through the project test harness.

So this works:

perl t/cases/384_mb122_partyline_top_and_claude_forget.t

That is a better guardrail.

A test should catch the bug in the room, not only the bug in a puppet show.


🧾 Partyline .top: channel digits are not limits

The second fix is in:

Mediabot/Partyline.pm

The command:

.top #chan42 10

should mean:

show top 10 for #chan42

not:

show top 15 because 42 was parsed from the channel name and clamped

That was already fixed in the Claude audit pass by stripping channel names and all before extracting the numeric limit.

This pass goes one step further.

It also avoids accepting embedded digits from arbitrary tokens:

.top #chan foo10bar

That should not silently mean:

top 10

A limit should be a standalone numeric token.

The parser now uses:

my ($n) = ($args_for_n =~ /(?:^|\s)(\d+)(?=\s|$)/);

So the behavior is cleaner:

.top #chan42 10      -> n=10
.top #chan foo10bar  -> default n=5
.top #chan 10foo 7   -> n=7
.top all 100         -> n=15 after clamp

Small fix.

Much better command hygiene.


🗣️ Hailo exclusion cache: fewer pointless SQL hits

The audit also checked a hot path in:

Mediabot/Hailo.pm

is_hailo_excluded_nick() can be called on every message in channels using Hailo chatter behavior.

Before the fix, that meant repeated database lookups for the same nick.

On a quiet channel, nobody cares.

On an active channel, that is needless work.

A 30-second in-memory cache now avoids repeated SELECTs while still keeping behavior fresh enough for IRC use.

The cache is invalidated when users are added to or removed from the Hailo exclusion list.

That is the right trade-off:

less database noise
same user-visible behavior
no schema change

The bot should not ask the database the same question every time someone breathes.


🧩 What was audited

This pass looked beyond the files changed directly.

The audit covered several areas:

Spotify external helper
URL fetching and Chromium fallback
YouTube search / API logging
Claude history and persona handling
Hailo exclusion checks
Channel ban helpers
Channel command cache invalidation
Auth password matching
Scheduler validation
Partyline .top parsing

Most of it was clean.

That is useful information too.

An audit is not only about finding bugs. It is also about knowing which rooms do not currently contain a troll.


🧪 Tests added or hardened

The test file:

t/cases/384_mb122_partyline_top_and_claude_forget.t

now covers:

Partyline .top channel names with digits
Partyline .top standalone numeric token parsing
limits and clamps
Claude forget behavior with capitalized nicks
Claude forget behavior with lowercase nicks
Claude forget behavior with no active session
source-level checks against Claude.pm regressions

The .top tests now include cases such as:

#chan42 10
#chan foo10bar
#chan 10foo 7
all 100

That is exactly the kind of test that prevents a small parser bug from quietly returning later.


🧯 Still no schema change

This is worth repeating:

No new table.
No new column.
No migration.
No seed data update.

Everything is code-side:

runtime key handling
test coverage
regex parsing
short-lived cache

That matters. We are keeping the current development branch moving without making database state more complicated.


🔍 Suggested validation

Syntax:

perl -I. -c Mediabot/External/Claude.pm
perl -I. -c Mediabot/Hailo.pm
perl -I. -c Mediabot/Partyline.pm
perl -I. -c Mediabot/UserCommands.pm
perl -I. -c Mediabot/Mediabot.pm
perl -I. -c mediabot.pl

Tests:

perl -c t/cases/384_mb122_partyline_top_and_claude_forget.t
perl t/cases/384_mb122_partyline_top_and_claude_forget.t

Git hygiene:

git diff --check
find . -name '*.bak.mb123_*' -o -name '*.bak.mb124_*'

The backup files are useful while applying patches, but they do not belong in the commit.


🕯️ Final note

This is the kind of update that makes the next big feature safer.

It does not shout.

It does not wave a banner.

It fixes the memory charm that did not fully forget. It teaches Partyline to read numbers properly. It stops Hailo from asking the database the same question again and again. It makes tests check the real implementation, not only a miniature simulation.

That is good maintenance.

The quiet kind.

The kind that keeps a bot alive long after the shiny spells are written.

🧪🦇🕯️

You must be logged in to reply.