Forum teuk.org

πŸͺƒ Mediabot v3 β€” Welcome Back: Comeback Achievements

in Mediabot Β· started by TeuK Β· 6d ago

TeuK Β· 6d ago

Commit: 49cb3dc
Version: 3.4dev-20260817_122837

MB656 adds a new family of user-facing achievements based on something Mediabot already knew: how long someone had been away.

The tricky part was not defining the milestones. It was making sure the historical absence could be observed before the normal USER_SEEN update erased that information.


πŸ† New comeback achievements

Three milestones are now available:

πŸͺƒ Welcome Back       7 days away
πŸ•°οΈ Long Time No See 30 days away
🌠 The Return        90 days away

Progress is stored using the existing generic Achievement counter:

comeback_days

No new table, no migration, no schema change.


🧠 The timing problem

USER_SEEN is updated as soon as a user joins.

That means a naΓ―ve implementation would do this:

JOIN
  ↓
update USER_SEEN
  ↓
first message
  ↓
try to determine how long the user was away

At that point, the old seen_at is gone.

MB656 therefore captures the candidate before the normal seen update:

JOIN
  β”‚
  β”œβ”€ read previous USER_SEEN
  β”œβ”€ if absence >= 7 days:
  β”‚      keep a temporary comeback candidate
  β”‚
  └─ normal updateUserSeen()

first message
  β”‚
  β”œβ”€ normal MB646 identity observation
  └─ consume the comeback candidate

This keeps the runtime order correct without changing the database model.


πŸ”’ Joining alone does not create an Achievement identity

A comeback candidate is only a short-lived in-memory fact.

The actual Achievement progression happens later, when the user sends a real message and the normal durable identity resolver has run.

That means:

JOIN only

does not create or touch an Achievement profile merely because someone appeared on the channel.

This keeps MB656 aligned with the existing identity semantics.


πŸ›‘οΈ Hostmask protection

Nicknames can be reused.

MB656 therefore refuses to transfer old USER_SEEN history when the historical hostmask is clearly incompatible with the current one.

The real read-only validation explicitly tested this:

WRONG_ACCEPT = 0

So an unrelated user who happens to take over an old nickname should not inherit someone else’s comeback achievement.


🧹 Temporary candidates are bounded

Comeback candidates exist only in memory and are deliberately constrained:

maximum candidates : 200
expiry             : 24 hours

This prevents the feature from becoming an unbounded runtime cache.


πŸ—„οΈ Real USER_SEEN validation

MB656 was tested against the real DEV database through an isolated MariaDB connection placed explicitly in read-only mode.

A genuine historical USER_SEEN entry was selected:

NICK         = teuk69
USERHOST     = kiwi@teuk.org
PREV_EVENT   = quit
PREV_SEEN    = 2026-05-05 08:07:58
DB_AWAY_SEC  = 9021539

The new candidate logic captured exactly the same duration:

CAPTURED     = 1
PENDING_SEC  = 9021539
PENDING_SEEN = 2026-05-05 08:07:58

The incompatible-host test then confirmed:

WRONG_ACCEPT = 0

Final result:

READ_ONLY_TRANSACTION=ROLLED_BACK
REAL_COMEBACK_CANDIDATE_CHECK=OK
RC=0

πŸ”Ž Read-only source guard

The candidate-capture path was also inspected structurally.

The diagnostic query used to inspect the old USER_SEEN state is a single prepared statement:

SELECT userhost,
       event_type,
       seen_at,
       TIMESTAMPDIFF(SECOND, seen_at, NOW()) AS away_seconds
FROM USER_SEEN
WHERE nick = ?
LIMIT 1

The source guard confirmed:

OK: candidate capture has exactly one SQL statement
OK: candidate SQL is SELECT-only
OK: Perl delete() only affects the transient in-memory candidate map
MB656_READ_ONLY_SOURCE_GUARD=OK

No hidden DB write was introduced into candidate detection.


πŸ§ͺ Focused regression

The focused comeback + Achievement regression passed:

PASSED : 496/496

Coverage included:

USER_SEEN persistence
wildcard escaping
Achievement message filtering
Achievement persistence
channel identity behaviour
seen enrichment
deferred checks
async Achievement worker
progress persistence
threshold handling
progress display
MB646 durable DB identity
MB654 identity diagnostics
MB655 activity streak achievements
MB656 comeback achievements
module structure sanity

πŸ§ͺ Full-suite validation

The complete Mediabot suite passed:

PASSED : 13485/13485
RC=0

Runtime:

869s

So MB656 adds the new behaviour without introducing a regression elsewhere.


🧱 Operational scope

MB656 deliberately introduces:

no database schema change
no migration
no configuration change
no service change
no systemd change

It reuses:

USER_SEEN
existing Achievement persistence
MB646 durable identity resolution
existing generic progress counters

✨ Commit

49cb3dc
πŸͺƒ Welcome Returning Users With Comeback Achievements

Version:

3.4dev-20260817_122837

Committed scope:

CHANGELOG.md
VERSION
Mediabot/Achievements.pm
mediabot.pl
t/cases/795_mb612_achievement_progress_view.t
t/cases/838_mb656_comeback_achievements.t

Mediabot already remembered that someone had disappeared.

MB656 finally notices when they come home.

You must be logged in to reply.