Forum teuk.org

πŸ† Mediabot v3 β€” The Road to the Trophy Becomes Visible

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

TeuK Β· 2w ago

Development chronicle β€” mb609 to mb613 Β· Multilingual AI recap, persistent achievement progress, tunable rarity and truthful async state

This development arc improves two parts of Mediabot that look unrelated at first: AI recaps and achievements.

They actually share the same design goal: what the user sees should accurately reflect the state Mediabot is really using.

AI recap now follows the same language rules as ai summary. Achievement progress now survives restarts, uses configurable thresholds, shows the next goals directly on IRC, and correctly returns progress calculated inside async workers back to the parent process.

No database schema change was required.


🌍 mb609 β€” One language rule for both AI summaries

recap ai now follows the same language policy introduced for ai summary.

Examples:

recap 2h ai
recap 2h ai fr
recap ai lang=en

The important part is not merely that both commands support English, French and Spanish.

They now use the same implementation.

The shared Claude API exposes helpers for:

language token extraction
channel/default language resolution
model language names
localized service messages

Conceptually:

explicit lang=en|fr|es
          β”‚
          β–Ό
channel language
          β”‚
          β–Ό
main language / English fallback

ai summary and recap ai therefore cannot quietly develop two different interpretations of the same channel.

The recap prompt also stopped asking the model to guess β€œthe same language as the conversation”. On a bilingual IRC channel that was inherently ambiguous. Mediabot now tells the model exactly which language to use.


🧠 mb610 β€” Achievement progress survives restarts

Unlocks were already persistent.

The counters leading to them were not.

Several values lived only in memory:

horoscope consultations
compat checks
mood reads
duel wins

More seriously, trivia and quotegame progression used the score of the current game session.

That made goals such as a large number of correct trivia answers effectively reset between games.

mb610 adds a persistent progress ledger alongside the existing achievement data:

{
  "version": "2",
  "profiles": {},
  "progress": {
    "trivia_correct": {},
    "duel_wins": {},
    "msg_count": {}
  }
}

Progress is scoped by normalized nickname and channel:

Teuk on #Chan
teuk on #chan
        ↓
same progress identity

Legacy flat achievement files remain readable and are upgraded transparently on the next save.

The registry is bounded as well: oversized progress maps prune the weakest entries while protecting the counter that has just been updated.


βš”οΈ mb611 β€” Rare achievements require a rarer journey

Achievement thresholds used to be scattered inside checking code.

They now live in the achievement catalogue itself.

That gives Mediabot one source of truth for:

definition
display
validation
unlock condition

Thresholds can also be overridden in configuration:

[achievements]
TRIVIA_CHAMPION=200
LEGEND=120000

Invalid, missing, zero or negative overrides fall back to the catalogue default.

The harder tiers were rebalanced, for example:

Achievement Old New default
Trivia Champion 100 300
Quote Master 50 150
Duel Master 50 150
Karma Legend 100 250
Polyglot 5,000 7,500
Polyphony 5 channels 8
Legend 100,000 150,000

Entry-level achievements remain welcoming.

And an achievement already unlocked is never revoked merely because its threshold becomes harder later.


πŸ“Š mb612 β€” The journey becomes visible

Persistent counters are much more useful when users can see them.

The normal achievement view now includes the nearest goals:

πŸ† teuk β€” 2 / 24 achievements:
  πŸ’¬ Chatterbox  |  πŸ‘‹ First Steps
  Next: πŸ“š Wordsmith 980/1k (98%)
        | βš”οΈ Duel Warrior 9/10 (90%)
        | 🌟 Karma Star 41/50 (82%)

A new detailed view exposes the ladder:

!achievements progress

Example:

πŸ“Š teuk on #quebec β€” 2/24 unlocked, 18 in progress:

[===========.] πŸ“š Wordsmith       980/1k   (98%)
[==========..] βš”οΈ Duel Warrior     9/10    (90%)
[=========...] 🌟 Karma Star       41/50    (82%)
[=====.......] πŸ† Trivia Champion 137/300  (45%)
[=====.......] πŸ“’ Megaphone       4.2k/10k (42%)

Goals which are already numerically complete but have not yet been registered as unlocked are not presented as β€œnext objectives”.

Achievements for which Mediabot has no honest measurable progress β€” such as some timing or streak conditions β€” stay explicitly non-measurable instead of receiving invented percentages.

The partyline .status view also exposes achievement registry state:

Achv: N profile(s), M progress counter(s)

and reports unsaved changes when applicable.


πŸ›‘οΈ mb613 β€” Progress calculated in a worker must return home

The final audit found an important runtime distinction.

Heavy achievement checks run inside a forked worker.

A direct call like:

set_progress(...)

inside the child only modifies the child process’s copy-on-write memory.

Without an explicit return path:

PARENT
   β”‚
   └── fork ──► CHILD
                β”‚
                β”œβ”€β”€ calculates msg_count
                β”œβ”€β”€ set_progress(...)
                β”‚
                └── exits

             progress disappears

The corrected path is:

PARENT
   β”‚
   └── fork ──► CHILD
                β”‚
                β”œβ”€β”€ calculates msg_count
                β”œβ”€β”€ calculates channels_active
                β”‚
                └── returns bounded result
                          β”‚
                          β–Ό
                       PARENT
                          β”‚
                          β”œβ”€β”€ set_progress(msg_count)
                          β”œβ”€β”€ set_progress(channels_active)
                          └── normal persistence

This makes mb612’s promise true in the actual asynchronous runtime, not just in direct unit calls.


βš™οΈ Configured thresholds now cross the fork too

The worker deliberately receives a minimal bot object with an isolated database handle.

That isolation is good, but it also meant configuration-backed achievement thresholds were unavailable there.

mb613 snapshots the effective thresholds before the fork.

So:

[achievements]
LEGEND=200000
POLYPHONY=12

is respected both by the parent and by the async worker.

The result is one consistent achievement contract regardless of which process performs the expensive calculation.


🧹 Final consistency fixes

The final pass also closes several smaller truthfulness gaps:

  • the already calculated Polyphony channel count now feeds channels_active;
  • catalogue descriptions match the mb611 default thresholds;
  • the stale duplicate 790_mb608_ai_summary_language.t is actually removed;
  • the canonical mb608 language test remains under its new number;
  • a dedicated mb613 regression test locks the parent/worker contract.

No extra database query was introduced merely to draw progress bars: values already calculated by the existing checks are reused.


πŸ§ͺ Validation strategy

This round deliberately did not repeat the entire twelve-thousand-assertion suite after the final audit fix.

The Claude development passes had already exercised the broader suite, including:

mb609 β†’ 12145/12145
mb610 + mb611 β†’ 12190/12190
mb612 β†’ 12222/12222

The final review concentrated on the affected language, persistence, threshold, presentation and async-worker tests, including the new mb613 guard.

This keeps the final pre-commit loop focused while still testing the exact boundaries changed by the audit.


✨ What users gain

For AI features:

one channel
one resolved language
one implementation

For achievements:

activity
   ↓
persistent progress
   ↓
configurable target
   ↓
visible next goal
   ↓
unlock

And that progression now remains true across:

game sessions
bot restarts
forked workers
configuration overrides

🏰 Final parchment

The castle no longer keeps only a cabinet of trophies.

It keeps the road that leads to them.

The scoreboard survives when the candles go out, the rare cups demand a worthy journey, and the notice board shows exactly how far remains.

Even when a distant clerk counts the records in another room, the result now comes back to the Great Hall before it is written into the ledger.

And the portraits that summarize the evening finally speak with one shared voice.

You must be logged in to reply.