Theme plugin migration — sprint backlog
Continuation guide for adopting the !theme / !paint IRC frame system across plugins. Architecture: architecture.md. IRC style rules: lib/CONVENTIONS.md.
Status: Theme migration S0–S12 done. Phase 2 (S13–S21) done — real PaintSamples, irc_ping_ms, colon alignment, progress polish, ThemeFrame wrapping.
Architecture
Plugin formats IRC text (default IrcFormat colours)
↓
ThemeOutput.apply (reads PaintStore overrides for channel + plugin)
↓
FloodSafe.reply_pieces (with_progress: :auto → MessageProgress gutter)
↓
BotOutputQueueGate defer → channel
Admin flow: !theme use <name> → ThemePaint.apply! writes overrides from ThemeCatalog paint_rules into PaintStore.
Key libs:
| Lib | Role |
|---|---|
| lib/theme_output.rb | Runtime PaintApply wrapper |
| lib/flood_safe_theme.rb | themed_flood_safe_reply mixin |
| lib/message_progress.rb | Line % gutter (uniform aqua on dark blue; theme progress_percent) |
| lib/reply_layout.rb | 4-char gutter width; colon alignment helper |
| lib/reply_delivery.rb | Thread-local queue/lag context for progress |
| lib/theme_paint_rules.rb | Auto-discover paint rules + progress_gutter_rules |
| lib/paint_samples.rb | Sample registry (!paint preview) |
| lib/theme_catalog.rb | Built-in themes + merged paint_rules |
Definition of done (per plugin)
-
[ ] Stable layout — coloured tag, heading, footer at fixed plain-text positions; body plain
-
[ ] PaintSamples —
register("<plugin>")inlib/paint_samples/register_*.rb -
[ ] ThemeCatalog — rules merged via
paint_rules_for_palette(auto from samples, or explicit like blackjack) -
[ ] Runtime —
include FloodSafeTheme+themed_flood_safe_reply(orThemeOutput.applyforsafe_reply); multi-line replies use defaultwith_progress: :auto -
[ ] Tests — sample registered;
bundle exec ruby -Itest test/lib/theme_catalog_test.rbpasses -
[ ] Manual —
!theme use fserverecolours live output;!theme analyseclean
Sprint calendar
| Sprint | Focus | Plugins | Status |
|---|---|---|---|
| S0 | Foundation | ThemeOutput, blackjack runtime, docs |
done |
| S1 | CONVENTIONS references | bom, cocktail, silence, news, cursorusage |
done |
| S2 | SearchReport cluster |
auslib, qldlibrary, qldmuseum, staticice, car, cachy, pacman, aur |
done |
| S3 | Events / media | whatson, theatres, wiki, dictionary, rss, meidas, fart |
done |
| S4 | Rich domain cards | yt, auspost, sports, ehc, eh, radar, fishing, charts |
done |
| S5 | Games A | poker, solitaire, battleships, boggle, trivia, roulette, pool |
done |
| S6 | Games B + misc | snakes, bingo, wheel, btop, clock, flip_time, aip, ala |
done |
| S7 | QLD / transit / geo | qld, sunbus, geo, globe, holidays, quake |
done |
| S8 | Gov / open data | govau, abs, aec, fuel, tm, rba |
done |
| S9 | Admin / social | autoop, rabbot_user, chan, reminder, bank, stats, codestats, archey, asterisk |
done |
| S10 | Heavy plugins | ai, rabbot_meta, bot, directchat, mircruby, recipe, draw, urban |
done |
| S11 | Tail + cleanup | remaining styled plugins, docs | done |
| S12 | Progress gutter | MessageProgress HUD, FloodSafe :auto, ReplyLayout, theme progress rules |
done |
Phase 2 (S13+):
| Sprint | Focus | Status |
|---|---|---|
| S13 | Blockers + doc sync | done |
| S14 | Real samples S4 | done |
| S15 | Real samples S5–S6 + trivia | done |
| S16 | Real samples S7–S8 | done |
| S17 | Real samples S9–S10 | done |
| S18 | Real samples S11 + song | done |
| S19 | Colon alignment | done |
| S20 | Progress polish (optional) | done |
| S21 | ThemeFrame (optional) |
done |
Velocity assumption: 2-week sprints; adjust after S0.
Plugin inventory
Columns: samples = PaintSamples registered; runtime = FloodSafeTheme wired; rules = in ThemeCatalog via paint_rules_for_palette.
| Plugin | Sprint | samples | runtime | rules | Output lib |
|---|---|---|---|---|---|
| blackjack | S0 | yes | yes | explicit | plugins/blackjack.rb |
| bom | S1 | yes | yes | auto | lib/bom_forecast_report.rb |
| cocktail | S1 | yes | yes | auto | plugins/cocktail.rb |
| silence | S1 | yes | yes | auto | plugins/silence.rb |
| news | S1 | yes | yes | auto | plugins/news.rb |
| cursorusage | S1 | yes | yes | auto | plugins/cursorusage.rb |
| auslib | S2 | yes | yes | auto | lib/auslib_report.rb |
| qldlibrary | S2 | yes | yes | auto | lib/qldlibrary_report.rb |
| qldmuseum | S2 | yes | yes | auto | lib/qldmuseum_report.rb |
| staticice | S2 | yes | yes | auto | lib/staticice_report.rb |
| car | S2 | yes | yes | auto | lib/car_report.rb |
| cachy | S2 | yes | yes | auto | lib/cachy_report.rb |
| pacman | S2 | yes | yes | auto | lib/pacman_report.rb |
| aur | S2 | yes | yes | auto | lib/aur_report.rb |
| whatson | S3 | yes | yes | auto | lib/whatson_report.rb |
| theatres | S3 | yes | yes | auto | lib/theatres_report.rb |
| wiki | S3 | yes | yes | auto | lib/wiki_report.rb |
| dictionary | S3 | yes | yes | auto | lib/dictionary_report.rb |
| rss | S3 | yes | yes | auto | lib/rss_report.rb |
| meidas | S3 | yes | yes | auto | lib/meidas_report.rb |
| fart | S3 | yes | yes | auto | lib/fart_report.rb |
| yt | S4 | yes | yes | auto | lib/yt_report.rb |
| auspost | S4 | yes | yes | auto | lib/auspost_report.rb |
| sports | S4 | yes | yes | auto | lib/sports_report.rb |
| ehc | S4 | yes | yes | auto | lib/ehc_report.rb |
| eh | S4 | yes | yes | auto | lib/eh_report.rb |
| radar | S4 | yes | yes | auto | lib/radar_report.rb |
| fishing | S4 | yes | yes | auto | lib/fishing_report.rb |
| charts | S4 | yes | yes | auto | lib/charts_report.rb |
| poker | S5 | yes | yes | auto | plugins/poker.rb |
| solitaire | S5 | yes | yes | auto | plugins/solitaire.rb |
| battleships | S5 | yes | yes | auto | plugins/battleships.rb |
| boggle | S5 | yes | yes | auto | lib/boggle_report.rb |
| trivia | S5 | yes | yes | auto | plugins/trivia.rb |
| roulette | S5 | yes | yes | auto | plugins/roulette.rb |
| pool | S5 | yes | yes | auto | plugins/pool.rb |
| snakes | S6 | yes | yes | auto | plugins/snakes.rb |
| bingo | S6 | yes | yes | auto | plugins/bingo.rb |
| wheel | S6 | yes | yes | auto | plugins/wheel.rb |
| btop | S6 | yes | yes | auto | plugins/btop.rb |
| clock | S6 | yes | yes | auto | lib/clock/report.rb |
| flip_time | S6 | yes | yes | auto | plugins/flip_time.rb |
| aip | S6 | yes | yes | auto | lib/aip_report.rb |
| ala | S6 | yes | yes | auto | lib/ala_species_report.rb |
| qld | S7 | yes | yes | auto | plugins/qld.rb |
| sunbus | S7 | yes | yes | auto | lib/sunbus/format.rb |
| geo | S7 | yes | yes | auto | plugins/geo.rb |
| globe | S7 | yes | yes | auto | plugins/globe.rb |
| holidays | S7 | yes | yes | auto | plugins/holidays.rb |
| quake | S7 | yes | yes | auto | plugins/quake.rb |
| govau | S8 | yes | yes | auto | plugins/govau.rb |
| abs | S8 | yes | yes | auto | plugins/abs.rb |
| aec | S8 | yes | yes | auto | plugins/aec.rb |
| fuel | S8 | yes | yes | auto | plugins/fuel.rb |
| tm | S8 | yes | yes | auto | plugins/tm.rb |
| rba | S8 | yes | yes | auto | plugins/rba.rb |
| autoop | S9 | yes | yes | auto | lib/autoop_report.rb |
| autovoice | S9 | yes | yes | auto | lib/autovoice/report.rb |
| rabbot_user | S9 | yes | yes | auto | plugins/rabbot_user.rb |
| chan | S9 | yes | yes | auto | lib/chan_report.rb |
| reminder | S9 | yes | yes | auto | plugins/reminder.rb |
| bank | S9 | yes | yes | auto | plugins/bank.rb |
| stats | S9 | yes | yes | auto | plugins/stats.rb |
| codestats | S9 | yes | yes | auto | plugins/codestats.rb |
| archey | S9 | yes | yes | auto | plugins/archey.rb |
| asterisk | S9 | yes | yes | auto | plugins/asterisk.rb |
| ai | S10 | yes | yes | auto | plugins/ai.rb |
| rabbot_meta | S10 | yes | yes | auto | plugins/rabbot_meta.rb |
| bot | S10 | yes | yes | auto | plugins/bot.rb |
| directchat | S10 | yes | yes | auto | plugins/directchat.rb |
| mircruby | S10 | yes | yes | auto | plugins/mircruby.rb |
| recipe | S10 | yes | yes | auto | plugins/recipe.rb |
| draw | S10 | yes | yes | auto | plugins/draw.rb |
| urban | S10 | yes | yes | auto | plugins/urban.rb |
| msg, sms, dcc, hf, logbook, man, wine, define, pubcrawl, lotto, surf, king, quote, ozb, kfc, redrooster, animal, taboo, chain, pitch, rpg | S11 | yes | yes | auto | various |
Out of scope (~40 plugins): one-line replies (joke, flip, roll, duck, google, …), internal wiring (help, veto, theme, paint), alias-only (au_aliases).
Follow-up: optional per-plugin colon alignment in remaining reports; hand-tune paint rules if !theme analyse drifts on dynamic plugins (ai, directchat).
PR template
## Theme migration: `<plugin>` - [ ] PaintSamples registration (real or stub) - [ ] `include FloodSafeTheme` + `themed_flood_safe_reply` - [ ] `bundle exec ruby -Itest test/lib/theme_catalog_test.rb` - [ ] Manual: `!theme use fserve` + `!theme analyse fserve`
Risk register
| Risk | Mitigation |
|---|---|
| Dynamic content shifts paint positions | Keep nick/bet/etc. in fixed columns; test with !paint list <plugin> |
| Stub samples mis-align rules | Real formatter samples in lib/paint_samples/register_real_s*.rb |
| Multi-line flood splits | ThemeOutput applies before chunking (FloodSafeTheme order) |
| Custom themes | ThemeGenerate uses paint_rules_for_palette |
Future (not in initial sprints)
Live ASCII doodles (ThemeFrame header/footer) on multi-line replies — gated in ThemeOutput.wrap_frame when theme metadata includes frame doodles.