Forum teuk.org

🕰️🪶 Mediabot v3: Four More Mysteries Solved — Timers, Hailo and the Ghosts of Authentication (MB369–MB372)

in Mediabot · started by TeuK · 1h ago

TeuK · 1h ago

The latest Mediabot v3 pass followed four defects through some of the quieter corridors of the castle: timer commands written directly to IRC, a Hailo percentage that changed meaning between the command and the runtime, and authentication sessions that could remain behind after the user had vanished.

Claude completed MB369 and MB370. The following review added MB371 and MB372 after tracing the complete runtime paths.

The rule remained unchanged:

Keep the bot familiar, make its behaviour truthful, and do not change the database schema.


⏳🪤 MB369 — Timer commands can no longer smuggle a second IRC spell

Mediabot’s timers store raw IRC commands in the TIMERS table and write them to the socket when they fire.

The historical paths used direct writes:

$self->{irc}->write("$command\r\n");

A stored command containing CR, LF or NUL could split the payload and inject an extra IRC command at every tick.

MB369 introduced:

_timer_irc_write($command, $timer_name)

The helper now verifies the connection, rejects undefined or multiline commands, logs the refusal, and sends only a clean single-line IRC command.

Normal timers remain unchanged.

The enchanted clock may strike every minute, but it now casts only one spell per tick.


🎚️🗣️ MB370 — HailoChatter finally reads the room

The old decision used:

rand(100) >= ratio

With a stored ratio of 97, the bot replied only around 3% of the time.

MB370 corrected the runtime decision:

rand(100) < effective_percentage

It also added adaptive behaviour based on recent channel activity.

A fixed probability per message is unsuitable for every channel:

  • on a quiet channel, the bot may barely speak;
  • on a busy channel, a high percentage may become a flood.

The new engine keeps a bounded in-memory activity window per channel. At or below the reference traffic, it honours the configured percentage. Above that reference, it reduces the effective chance proportionally, with a configurable minimum factor.

The sample configuration now documents:

HAILO_CHATTER_RATE_WINDOW=60
HAILO_CHATTER_REFERENCE_MSGS=10
HAILO_CHATTER_MIN_FACTOR_PCT=10

No schema change is required.

Hailo is no longer a portrait speaking with the same intensity in an empty corridor and in the Great Hall at dinner.


🪞🎛️ MB371 — The percentage keeps its shape through the command mirror

The MB370 runtime was correct, but the command layer still used the historical inversion:

100 - $ratio

That produced this contradiction:

requested by operator : 97%
stored by command      : 3
used by runtime        : 3%

The display path inverted the stored value too.

MB371 removed both conversions.

The number now has one meaning everywhere:

percentage entered
= percentage stored
= percentage displayed
= base percentage used by adaptive Hailo

Examples:

0   → 0%
3   → 3%
50  → 50%
97  → 97%
100 → 100%

The adaptive reduction from MB370 still applies when traffic increases. MB371 simply ensures the administrator’s value reaches that engine unchanged.

The MB361 and MB370 tests were also corrected so they no longer document or tolerate the old inversion.

For channels configured manually with the former command behaviour, the percentage should be read and saved again:

m hailo_chatter #channel
m hailo_chatter #channel 97
m hailo_chatter #channel

The Mirror of Erised is useful for desires. It is a terrible place to store configuration semantics.


👻🪪 MB372 — Authentication sessions no longer linger like unfinished ghosts

The next audit left Hailo and moved into Auth.

Several methods called by LoginCommands did not exist in Mediabot::Auth:

is_logged_in_id()
set_logged_in()
set_session_user()

The calls were wrapped in eval, so the bot continued running while synchronisation silently failed.

The wrong identity was used as the session key

A user may connect under one IRC nick while authenticating against a differently named database account:

live IRC nick : Te[u]K
database user : teuk

The old login path stored the session under the database nickname.

QUIT, PART and KICK later attempted to remove it using the live IRC nick.

The session could remain in memory after the IRC user had disappeared.

The SQL authentication flag also survived

Auth::logout() removed memory entries but did not reset:

USER.auth = 0

A later message matching the same hostmask could therefore reconstruct an authenticated state from an old persistent flag.

That was not a normal logout. It was a ghost wearing yesterday’s badge.

MB372 repairs the full lifecycle

The Auth object now exposes the APIs expected by the login code.

Sessions are indexed by the live IRC nick while preserving:

database user id
database nickname
live IRC nick
hostmask
login timestamp

When a session disappears:

  • the exact runtime session is removed;
  • related caches are invalidated;
  • the Auth metric is updated;
  • the code checks for another session using the same account;
  • USER.auth returns to 0 only after the final session disappears.

Legitimate concurrent use remains supported.

Example:

FirstNick  → account 77
SecondNick → account 77

When FirstNick leaves, SecondNick remains authenticated.

Only when SecondNick leaves does the persistent flag return to zero.

Reused nicks and failed session creation

If an IRC nick is reused for another account, the old account state is cleaned before the replacement is stored.

Explicit login is also transactional: if SQL authentication succeeds but the runtime session cannot be created, the SQL flag is rolled back.

The stale-session cleanup routine now applies the same last-session rule.

The Fat Lady no longer merely closes the portrait. She also removes the vanished visitor from the guest list.


🧪🧿 Validation chambers

Claude’s rounds arrived with complete green suites:

MB369 new test              : 15/15
MB369 full suite            : 7824/7824

MB370 new test              : 24/24
MB370 updated MB361 test    : 21/21
MB370 full suite            : 7850/7850

The following rounds added:

MB371 new test              : 24/24
Hailo selected regression   : 112/112
MB361–MB371 regression      : 305/305

MB372 new test              : 46/46
Auth/login/logout regression: 291/291
MB361–MB372 regression      : 351/351

The MB371 and MB372 installers were tested on two clean copies and in already-applied states.

These suites overlap and should not be added into one artificial total.


🧱 Database impact

None.

0 new tables
0 altered columns
0 migrations
0 schema changes

MB372 corrects the lifecycle of the existing USER.auth column without altering its structure.


🗺️ What changed across MB369–MB372

This four-round pass gives Mediabot:

  • timer commands that cannot inject extra IRC lines;
  • Hailo using the actual configured percentage;
  • adaptive chatter that restrains itself when a channel becomes busy;
  • a command path that stores and displays the same percentage used at runtime;
  • Auth sessions indexed by the real IRC nick;
  • correct concurrent sessions for one account;
  • persistent logout after the final session disappears;
  • aligned Auth caches and metrics;
  • transactional login when runtime session creation fails;
  • stale-session cleanup that also clears the database flag.

🪶 Closing the Department of Mysteries file

These rounds show why a mature application must be tested as a complete path rather than as isolated functions.

The timer code looked harmless until the stored command reached the raw socket.

The Hailo runtime looked correct until the command layer transformed the number before saving it.

Auth appeared to log users out until memory keys, IRC nicks and the persistent SQL flag were followed through QUIT, PART, KICK and cleanup.

Each room looked reasonable on its own. The doors between them no longer matched.

Mediabot v3 now keeps those doors aligned.

The clocks cast one spell.

The chatter percentage keeps its shape.

And when the last authenticated user leaves, the ghost leaves too.

Teuk

You must be logged in to reply.