Forum teuk.org

🪄 Mediabot v3 — Every Common Room Keeps Its Language, and Every Memory Finds the Right Library

in Mediabot · started by TeuK · 4w ago

TeuK · 4w ago

Development chronicle — mb572 to mb579 · 3.4dev

The castle has completed one of its most careful rounds of work yet.

This chapter began with a bilingual Seer and an improved operator board. It ended with a deeper redesign of Mediabot’s historical memory: live data and archived records can now work together without forcing MariaDB to materialize enormous combined tables, without silently hiding failures, and without searching an archive that cannot contain the requested information.

No database schema was changed during these rounds.


🔮 mb572 — One horoscope, two languages

Mediabot’s horoscope now follows the language of each channel.

A French Common Room receives the historical French reading. English-speaking rooms receive a complete English version covering signs, elements, moods, social climate, projects, advice, warnings, colours and lucky details.

The important part is invisible but deliberate: every French pool has an English twin of exactly the same size.

The same nickname and date therefore produce the same deterministic draw in both languages. The prophecy does not change when it crosses the corridor — only the words on the parchment do.


🏰 mb573 — The Entrance Hall becomes an operator board

The partyline .status command now reveals three useful runtime states:

FloodQ:   7 deferred (#miaw:2 UNARMED, #quebec:5)
AchvQ:    3 pending check(s)
Archive:  worker running (pid 4242)

FloodQ

Shows deferred IRC output by channel.

The UNARMED marker exposes a queue containing messages without an active drain timer, allowing an operator to spot trouble before users report that the bot has stopped displaying everything.

AchvQ

Shows achievement checks waiting for asynchronous processing.

Archive

Shows whether the daily archive is disabled, waiting for its first run, currently running, or completed with an exit code and duration.

The panel reads memory only. A diagnostic command must never become the stall it is meant to diagnose.


📚 mb574 — Career counters discover the annex

Historical counters originally read only the live CHANNEL_LOG table.

Once old records moved to the archive, career views could lose years of history. Message totals, first appearances, ranks, streaks and leaderboard positions could become incomplete.

The first archive-aware pass restored that missing historical vision for:

  • stats;
  • top;
  • streak;
  • leaderboard.

This round also exposed an important design question: how should millions of live and archived rows be queried without bringing the old performance problem back?


📖 mb575 — Historical readers follow the counters

The archive-aware view was extended to commands that read message content:

  • wordcount;
  • last;
  • compat.

Old last messages could be found again, vocabulary samples could include long-absent users, and career word statistics no longer stopped at the live retention horizon.

Recent commands such as mood and recap deliberately remained live-only. Their job is to describe the present, not the entire history of the castle.


⚙️ mb576 — The giant UNION ALL leaves the Great Hall

The initial implementation combined both tables through a derived query:

SELECT * FROM CHANNEL_LOG
UNION ALL
SELECT * FROM archive.CHANNEL_LOG_ARCHIVE

It was compact, but it could be expensive.

For commands using ORDER BY ... LIMIT, MariaDB could still materialize far more rows than the command actually needed. A request for one last message could make the server inspect a very large historical set before returning a single line.

The replacement follows a safer model:

  1. query each table independently;
  2. keep each table’s indexes and limits effective;
  3. merge the small results in Perl.

This model now covers the broader career surface, including statistics, rankings, last messages, compatibility, history comparisons, profiles, dashboards, chronologies and milestones.

A nickname split between live and archive records is merged before ranking. Three hundred archived messages plus eight hundred live messages now correctly become one career total of eleven hundred.


🗝️ mb577 — The librarian opens only the useful shelves

Not every archive contains every kind of record.

Mediabot now selects sources by purpose:

  • content for messages and actions;
  • presence for joins, parts, quits and related events;
  • all when a command genuinely needs both.

This matters on Undernet, where presence records may be archived while message content remains entirely live. Content commands no longer search millions of archived presence events that cannot answer the question.

The gather contract was also strengthened:

  • a successful query returning zero rows is a valid result;
  • failure of the live table is a hard command failure;
  • failure of the archive preserves the live result when it remains trustworthy;
  • nickname keys are normalized before merging;
  • date filters use index-friendly ranges;
  • wordcount all streams text instead of loading an unlimited corpus into memory;
  • counters labelled as messages explicitly count public and action, not joins and quits.

🧭 mb578 — “First seen” means first seen again

Filtering message counters introduced a subtle semantic regression.

when and the first seen field of stats promise the first appearance of a nickname, not merely the first time that nickname spoke.

The corrected design uses separate gathers:

  • first appearance: all relevant historical events;
  • message count and last message: public and action only.

A user who joined years ago but never spoke can therefore still have a genuine first-seen date and a message total of zero.

The live-source contract was also applied consistently across every archive-aware gather. A live database failure can no longer masquerade as “no history”, “no public activity” or an invented rank.


🛡️ mb579 — Partial history can no longer pretend to be complete

The final inspection covered a rare but important failure mode.

An archive fetch can fail after some rows have already reached the Perl callback. At that point, the command’s counters have absorbed only part of the archive. The result is neither purely live nor complete.

Mediabot now marks that state as tainted and refuses to display it.

The rule is precise:

  • archive failure before any archived row: retain the valid live result;
  • archive failure after one or more archived rows: fail closed and reject the incomplete answer.

The final pass also ensures that stats displays a first-seen date for a nickname that has appeared but has not yet spoken, rather than incorrectly calling that nickname absent from the database.


🚀 Why this matters on Undernet

The archive remains on the same MariaDB server, so millions of historical rows still consume real CPU, disk and buffer-pool resources.

These rounds do not pretend otherwise.

Instead, Mediabot now avoids unnecessary work:

  • content commands ignore a presence-only archive;
  • presence commands can still recover old joins and quits;
  • table-local LIMIT and index scans remain effective;
  • huge derived unions are gone;
  • unlimited word analysis is streamed;
  • malformed or partial results are not shown as successful;
  • expensive global rankings remain candidates for a future cache or asynchronous worker.

The result is not “history for free”. It is history queried deliberately, honestly and with much better control.


đź§Ş Validation

The complete local test suite passed after the final mb579 safeguards.

The validation covered:

  • bilingual deterministic horoscopes;
  • queue and archive runtime status;
  • archive source scopes;
  • live and archive failure semantics;
  • empty result sets;
  • mixed-case nickname merging;
  • historical counters and readers;
  • true first-appearance semantics;
  • streaming word counts;
  • partial archive fetch failures;
  • repository whitespace checks.

✨ Final parchment

The Seer now speaks the language of every Common Room.

The Entrance Hall shows what the workers are doing.

The librarians know which shelves to open, the census clerks combine both libraries without losing anyone’s past, and a torn archive scroll is never presented as a complete history.

Mediabot remembers more than before — and, just as importantly, it now knows when a memory can be trusted.

You must be logged in to reply.