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.
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.
!ai forget: now it really forgetsThe 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 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.
.top: channel digits are not limitsThe 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.
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.
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.
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.
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.
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.
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.