Forum teuk.org

πŸ›‘οΈ *Protego Maxima!* β€” Netsplit Safety, DB Guards, Partyline AI, and Runtime Hardening

in Mediabot Β· started by TeuK Β· 4w ago

TeuK Β· 4w ago

This Mediabot v3 pass was a serious hardening round.

It started with concrete runtime bugs around Partyline AI commands and karma handling, then grew into a wider defensive audit across the codebase:

netsplit handling
database prepare/execute guards
Partyline AI subcommands
explicit karma voting
External URL handlers
antiflood edge cases
daily report karma sorting
reminders, trivia, choose, timezone, bans

The overall goal was not to add shiny features.

The goal was to make Mediabot harder to crash, less noisy during network events, and safer during real IRC operations.


🌐 Netsplit handling improved

The IRC side now behaves better during netsplits.

NS1 β€” Netsplit QUITs avoid DB churn

QUIT messages matching netsplit patterns such as:

*.net *.split

are now treated as infrastructure events.

For these QUITs, the bot updates in-memory nicklist state but skips expensive or misleading database operations such as:

logBotAction
updateUserSeen
auth logout

That avoids polluting logs and user state during a network split.

A Prometheus counter was also added:

mediabot_netsplit_quits_total

NS2 β€” Reconnect clears transient antiflood state

On reconnect, in-memory transient states are cleared:

_af
_chan_flood
_nick_flood
_nick_mute
_cmd_cooldown

That prevents stale flood/mute/cooldown state from surviving a reconnect and incorrectly silencing channels or users.

NS3 / NS4 β€” JOIN pacing and WHO resync

After login, channel JOINs are spaced out instead of being blasted at once.

A delayed WHO #channel is also sent after JOIN to resync nicklists.

That is especially useful after netsplits, reconnects, or large channel lists.

NS5 β€” Claude history survives netsplits

Claude history cleanup now happens on real QUITs, not netsplit QUITs.

That prevents valid context from being thrown away just because the IRC network split temporarily.


βš–οΈ Karma is now explicit

The old automatic karma scanner watched every public message for patterns like:

nick++
nick--

That was too dangerous.

Normal text such as:

Notepad++
C++

could create bogus karma entries.

The automatic scan is now disabled.

Karma changes must be explicit:

m karma + boole
m karma - boole
m karma ++ boole
m karma -- boole

Showing karma is unchanged:

m karma boole

The command also verifies that the target nick is present on the channel before modifying karma.

This is a much better tradeoff: fewer surprises, no accidental karma from software names, and cleaner daily reports.


πŸ“Š Daily report karma sorting fixed

Daily reports now sort karma by absolute score:

ORDER BY ABS(score) DESC

instead of only showing positive scores first.

That means negative karma can appear when it is one of the strongest signals, which makes the report more honest.


🧠 Partyline AI subcommands fixed

The Partyline .ai command now properly intercepts its subcommands.

Previously, commands such as:

.ai quota

could be sent to Claude as a normal prompt.

That produced nonsense like Claude asking what kind of quota was meant.

Now known subcommands are handled as Partyline commands:

.ai quota
.ai stats
.ai models
.ai history
.ai reset
.ai forget
.ai pin
.ai pin clear
.ai summary [n]

Normal prompts still work:

.ai explain netsplits in one sentence

.ai forget fixed

.ai forget now clears the correct Partyline AI scope.

It no longer uses a hardcoded partyline key when the active scope is based on the resolved nick/channel context.

.ai summary fixed

.ai summary now uses the real CHANNEL_LOG schema:

publictext
id_channel_log

It also handles Unicode safely when the prompt cache hashes text from IRC logs.

The fix encodes prompt text before passing it to Digest::MD5:

encode('UTF-8', lc($prompt // ''))

No more Wide character in subroutine entry from Unicode log summaries.


🧯 External URL handlers are safer

displayUrlTitle() now wraps URL handlers in eval.

That means a failure in a specific handler, such as Instagram, Spotify, YouTube, Facebook, or other media extraction, should not bubble up and crash the message handler.

The X/Twitter Chromium fallback was also wrapped more tightly around the risky external process call.

Result: network/parser/process failures should degrade gracefully instead of destabilizing normal IRC message processing.


🧱 Database hardening pass

A major part of this pass was defensive DB cleanup.

Across the codebase, many places used this unsafe pattern:

unless ($sth->execute(...)) {

If prepare() failed, $sth was undef, and the bot could crash with:

Can't call method "execute" on undef

The safer pattern is:

unless ($sth && $sth->execute(...)) {

This was applied across many modules, including:

UserCommands.pm
Helpers.pm
ChannelCommands.pm
Partyline.pm
DBCommands.pm
Quotes.pm
Hailo.pm
ChannelBan.pm
Mediabot.pm

This does not make the database magically healthy, but it makes failures controlled.

The bot should report or skip cleanly instead of exploding in the dispatcher.


🧩 Smaller logic fixes

Several smaller bugs were fixed along the way:

Reminder urgency with delayed reminders

mbRemindList_ctx now strips [at:TS] before detecting [!].

That means delayed urgent reminders are correctly shown as urgent.

Trivia reset state

mbTriviaStop_ctx now resets more state so the next trivia game does not inherit stale scores or hint flags.

Choose edge cases

mbChoose_ctx now handles edge cases after deduplication more cleanly, including the case where only one option remains.

Karma graph guards

mbKarmaGraph_ctx now avoids warnings when older karma log entries have missing delta values or future timestamps.

Timezone setters

Timezone update/delete helpers now guard failed prepare() calls.

Reminder delivery

Reminder delivery now checks the result of its delivery-state update instead of silently ignoring failed updates.


🌊 Antiflood fixes

The channel flood guard now clamps invalid runtime values more safely.

A dangerous case such as:

.floodset #chan 0 ...

could previously leave window=0, which risks divide-by-zero or broken rate calculations.

The value is now clamped.

Warn-only mode logging was also corrected: logs no longer say the bot is silencing a channel when it is only warning.


🧹 Typo cleanup

A long-standing typo was fixed in UserCommands.pm:

$DBI::errstrstr

became:

$DBI::errstr

This appeared many times and could make database error reporting misleading or broken.


βœ… Validation

Before committing, the critical compile checks should pass:

perl -c mediabot.pl
perl -I. -c Mediabot/UserCommands.pm
perl -I. -c Mediabot/Helpers.pm
perl -I. -c Mediabot/ChannelCommands.pm
perl -I. -c Mediabot/DBCommands.pm
perl -I. -c Mediabot/Quotes.pm
perl -I. -c Mediabot/Hailo.pm
perl -I. -c Mediabot/ChannelBan.pm
perl -I. -c Mediabot/External.pm
perl -I. -c Mediabot/Partyline.pm

Runtime checks included Partyline AI behavior, .ai summary, .karma, and foreground startup.


Result

This pass strengthens Mediabot v3 where it matters most:

netsplit events are less destructive
reconnects reset stale runtime flood state
JOINs are paced
WHO resync happens after JOIN
Claude history survives netsplits
karma is explicit and less error-prone
daily reports are more accurate
Partyline AI subcommands behave correctly
URL handlers are isolated with eval
DB prepare/execute paths are more defensive
reminders/trivia/choose/karma graph edge cases are fixed

No schema change.


Spell of the day

Protego Maxima!

Less crashy.
Less noisy.
Less likely to punish someone for saying Notepad++.

Mischief hardened. πŸ›‘οΈπŸ§™β€β™‚οΈ

You must be logged in to reply.