A crash, a corrupted character, and a lurking split edge case — all disarmed. Then five new spells: a Partyline persona inspector, persistent karma history, and five test cases locking it all down.
“Expelliarmus Maxima II! The crash yields. The em dash surrenders. The operators take their seats.” 🏰⚡
_seconds_to_human() Was Missing (Crash on !karmahist)Severity: CRITICAL — mbKarmaHist_ctx called _seconds_to_human()
to format the “ago” timestamp on each karma entry. The function was never
defined — every !karmahist call crashed immediately with
Undefined subroutine &Mediabot::UserCommands::_seconds_to_human.
Fix: added the function to UserCommands.pm:
# B19/fix: was missing, caused crash in mbKarmaHist_ctx
sub _seconds_to_human {
my ($secs) = @_;
$secs = int($secs // 0);
return '0s' unless $secs > 0;
my $d = int($secs / 86400); ...
return "${d}d ${h}h" if $d;
return "${h}h ${m}m" if $h;
return "${m}m ${s}s" if $m;
return "${s}s";
}
Output examples: 3d 2h, 14m 7s, 42s.
botNotice (Non-ASCII)External.pm:3238 contained a Unicode em dash (—, U+2014) inside a
single-quoted string passed to botNotice:
# Before — Unicode em dash, may corrupt on non-UTF-8 IRC links
'Persona cleared — using default system prompt.'
# After — ASCII only
'Persona cleared -- using default system prompt.' # B17/fix: ASCII only
split /\x00/, $key Without Limit_cmd_quota split rate-limit keys on \x00 without a count limit.
A key with an unexpected second \x00 would silently produce three
fields, corrupting the channel name display.
# Before
my ($nick_k, $chan_k) = split /\x00/, $key;
# After — B20/fix
my ($nick_k, $chan_k) = split /\x00/, $key, 2;
Four occurrences fixed across _cmd_quota.
.persona [nick]Operators can now inspect and manage Claude personas directly from the Partyline.
Without argument — list all active personas:
.persona
Active Claude personas:
teuk #boulets Tu es un pirate des Caraïbes...
Boole #teuk You are a Unix wizard who speaks...
With nick — show persona for that nick:
.persona teuk
Persona(s) for teuk:
[#boulets] Tu es un pirate des Caraïbes. Réponds en argot nautique.
With clear — remove persona:
.persona teuk clear
Persona cleared for teuk (1 entry).
All split /\x00/ calls use limit 2. Listed in .help.
!karmahist DB Persistence (Graceful)processKarma now writes each karma change to KARMA_LOG in addition
to the in-memory ring buffer. mbKarmaHist_ctx reads from DB first,
falling back to memory if the table doesn’t exist yet.
SQL schema to activate:
CREATE TABLE KARMA_LOG (
id INT AUTO_INCREMENT PRIMARY KEY,
id_channel INT NOT NULL,
nick VARCHAR(64) NOT NULL,
delta TINYINT NOT NULL,
from_nick VARCHAR(64) NOT NULL,
score INT NOT NULL,
ts DATETIME DEFAULT NOW(),
INDEX (id_channel, ts)
) ENGINE=InnoDB;
Without the table, the bot continues working exactly as before — the
eval {} wrapper silently absorbs the error.
| # | File | What |
|---|---|---|
| 237 | 237_partyline_quota_cmd.t |
_cmd_quota: reads _claude_ratelimit, safe split, 60s window, empty case, help entry |
| 238 | 238_scheduler_daily_report.t |
daily_channel_report: 86400s interval, top speakers, top karma, ensure_connected, ->finish, autostart |
| 239 | 239_usercommands_wave4_subs.t |
_seconds_to_human (B19), mbFlip_ctx, mbMorse_ctx, mbRoll_ctx, mbStreak_ctx, mbWhen_ctx — all with logBot |
| 240 | 240_partyline_persona_cmd.t |
_cmd_persona: reads _claude_persona, safe split, empty case, clear, dispatch, help |
| 241 | 241_usercommands_karmahist_db.t |
processKarma I8 insert + eval, mbKarmaHist_ctx DB-first + fallback |
Total test suite: 228 cases.
| File | Changes |
|---|---|
UserCommands.pm |
B19 _seconds_to_human; I8 KARMA_LOG insert in processKarma, DB read in mbKarmaHist_ctx |
External.pm |
B17 em dash → ASCII |
Partyline.pm |
B20 split limit; I7 _cmd_persona sub + dispatch + help |
t/cases/237…241 |
5 new test cases |
You must be logged in to reply.