minecraft-server/docs/MIGRATION-PLAN-CHATCHAT.md
s8n 41ae6f90ef feat(chat): stage ChatChat migration bundle (jar + configs + swap scripts)
Replaces CarbonChat 3.0.0-beta.36 — viewer-context bug on <luckperms_prefix>.
ChatChat (HelpChat fork) renders per-recipient with sender-context PAPI +
built-in Kyorifier (& -> MM). Built from upstream main HEAD via podman/temurin 21.

Staged only — operator runs scripts/swap.sh during a quiet window. Rollback
plan + smoke checklist in docs/MIGRATION-PLAN-CHATCHAT.md. JAR gitignored;
rebuild via staging/chatchat/build/build.sh.
2026-05-07 22:23:11 +01:00

9.2 KiB
Raw Permalink Blame History

Migration Plan — CarbonChat → ChatChat

Date drafted: 2026-05-07 Operator sign-off: s8n green-lit pre-research, awaiting final go on swap window Live target: racked.ru / Paper 1.21.11 / nullstone container minecraft-mc Built artifact: staging/chatchat/build/ChatChat-1.0.0-SNAPSHOT-racked-1.jar (2.2 MB) Pre-research: docs/CHAT-PLUGIN-CHATCHAT-RESEARCH.md, _github/auth-limbo/docs/RESEARCH-LIMBO-PLUGIN-SURVEY.md


0. Why we're doing this

CarbonChat 3.0.0-beta.36 has a viewer-context render bug: the MM tag <luckperms_prefix> resolves against the viewing player, not the sending player. Every player sees every other player wearing their own LP rank prefix. The PAPI-form workaround %luckperms_prefix% returns legacy & codes that Carbon doesn't pass through its MiniMessage pipeline, so the format renders broken or stripped.

ChatChat (HelpChat fork of DeluxeChat) renders per-recipient via MessageProcessor.process(), calls PlaceholderAPI.setPlaceholders(sender, …) explicitly, and ships a built-in Kyorifier that converts & legacy codes to MiniMessage before the parser runs. Both bugs gone.


1. Pre-flight checklist

  • JAR built: staging/chatchat/build/ChatChat-1.0.0-SNAPSHOT-racked-1.jar exists. If missing, run staging/chatchat/build/build.sh (uses podman + temurin 21).
  • Configs staged: staging/chatchat/configs/{channels,formats,settings,extensions}.yml reviewed by operator.
  • LP migration script reviewed: staging/chatchat/scripts/lp-migration.sh — verify perm grants match operator intent (esp. chatchat.tag.color/hover/item for default group).
  • Rollback ready: staging/chatchat/scripts/{rollback,lp-rollback}.sh present and executable.
  • Backup taken outside this swap: standard nightly nullstone snapshot ran in last 24h (reference BACKUP-STRATEGY.md).
  • No DiscordSRV in flight: Carbon config has DSRV integration enabled but DSRV plugin is NOT loaded — no live bridge to break. ChatChat config extensions.yml > addons.discordsrv.channels_bridging: false matches.
  • Quiet window: swap during low-player time (≤2 players). Currently 2 online (s8n + YOU500 on default rank).

2. Swap window — step-by-step

The full sequence is automated by staging/chatchat/scripts/swap.sh. Steps:

  1. Broadcast 60s warning via RCON (say [racked.ru] chat plugin swap in 60s …).
  2. save-all to flush worlds.
  3. Backup Carbon JAR + /data/plugins/CarbonChat/ directory into /data/backups/chat-swap-YYYY-MM-DD-HHMMSS/ (in-container, on the named docker volume).
  4. docker compose stop mc — server goes offline. Hot-swap is NOT used because Paper's plugin lifecycle for chat-event-listening plugins is unreliable post-1.20; full restart is the safe path.
  5. Remove carbonchat-paper-3.0.0-beta.36.jar and rename /data/plugins/CarbonChatCarbonChat.disabled-<ts> (kept for forensics).
  6. Drop ChatChat-1.0.0-SNAPSHOT-racked-1.jar into /data/plugins/.
  7. Drop translated configs into /data/plugins/ChatChat/{channels,formats,settings,extensions}.yml.
  8. docker compose start mc — server boots, ChatChat reads configs, generates users.json/messages.yml/placeholders.yml defaults.
  9. Run lp-migration.sh — drops carbon.channel.* and grants chatchat.channel.{see,use}.global, plus chatchat.pm, chatchat.ignore*, chatchat.mention.personal*, and safe MM tag grants.
  10. Smoke test (manual; see §3).

Estimated downtime:

  • Best case (clean stop → swap → start, no boot-time hang): 4560 seconds.
  • Worst case (config syntax error forces second restart, or world I/O slow): 35 minutes.

3. Smoke verification checklist

Run as soon as the server accepts connections:

  • rcon-cli list returns the player list (server alive).
  • s8n logs in. Sends hello in chat. Operator's own client shows [⛧] s8n — hello (their own prefix). Confirms self-render works.
  • YOU500 logs in (or remains logged in via cross-session). Sends a chat line. Operator sees YOU500 — <message> (no prefix because Adventurer prefix is set to value=false in his LP nodes — that's the existing rank state, not a regression). Confirms per-recipient render works WITHOUT inheriting s8n's owner prefix. This is the bug we're fixing.
  • Operator runs /msg YOU500 ping → both sides see correct sender/recipient names (private-messages format).
  • Operator runs /r pong from YOU500's session via test client (or socially: ask YOU500 to confirm /msg s8n works).
  • /ignore <test-name> succeeds and /ignorelist shows the entry.
  • LP perm check: lp group default permission check chatchat.channel.use.global returns true.
  • No MiniMessage parse errors in the latest server log (docker logs minecraft-mc 2>&1 | tail -200 | grep -iE "minimessage|parse|error").
  • Console log shows readable plain-text chat lines (no MM-tag noise).

4. Rollback procedure

Triggered by any smoke-test failure (especially: chat doesn't render at all, players can't speak, or the prefix bug reappears). Run staging/chatchat/scripts/rollback.sh:

  1. Locate latest chat-swap-<ts> backup dir on the data volume.
  2. docker compose stop mc.
  3. Remove ChatChat JAR + dir.
  4. Restore Carbon JAR + CarbonChat/ from backup.
  5. Run lp-rollback.sh to restore carbon.channel.* perms and drop chatchat.*.
  6. docker compose start mc.
  7. Re-run lp-rollback.sh (online this time, ensures clean state).

Rollback downtime: same envelope as forward swap (4590s).

The viewer-context bug is back, but that's the status quo we tolerate today — it's not a regression, it's a known-tolerated condition we attempted to fix. Defer the fix and re-research the failure mode.


5. Risk register (top 3)

# Risk Likelihood Impact Mitigation
1 ChatChat fork has no formal release; HelpChat repo is sleepy (last commit Apr 2025). The built JAR is essentially HEAD-of-main pinned by us. Could have latent 1.21.11 incompatibility nobody's found yet. Medium High (chat broken) Test smoke checklist immediately. Rollback plan is mature. Pinned commit preserved in /tmp/chatchat-build/.git; we can re-build at any commit.
2 Config translation gaps — ChatChat splits format into parts: (channel/prefix/name/divider/message), Carbon used a single MM string. Edge cases like LP suffixes, unicode names, Essentials-nick formatting may render off. Medium Medium (cosmetic, not functional) Smoke checklist includes operator + player visual check. Format tweaks are config-only, no rebuild needed; reload via RCON reload confirm post-swap.
3 Paper 1.21.11 + plugin compiled against Spigot 1.21.4 API drops a NoSuchMethodError on a removed Bukkit API call (rare but happens — Adventure platform API is the usual culprit). Low High (server crash on first chat event) If chat triggers crash: stop server, run rollback.sh. Carbon's deprecated AsyncPlayerChatEvent works on 1.21.11 today, so identical-event ChatChat should too.

Lower-tier risks tracked but not actioned:

  • DiscordSRV bridge regression — N/A, plugin not loaded.
  • MiniPlaceholders LP-Expansion drop — N/A, we switched to PAPI form which Kyorifier handles.
  • Item-tag rename <itemlink><item> — no players use it today.
  • User data carry-over — Carbon nicknames live in nickname-settings.use-carbon-nicknames=true; they'll be lost on Carbon disable. EssentialsX nicknames are unaffected (different store), and EssentialsX is what %player_displayname% reads from in our new config, so visible nicknames survive.

6. Post-swap follow-ups

  • Update docs/PLUGINS.md to swap CarbonChat → ChatChat in the plugin table.
  • Update docs/PERMISSIONS.md with the new chatchat.* perm node tree.
  • Add ChatChat to the racked.ru THANKS.md (HelpChat fork + AGPL/MIT credit).
  • After 7 days of stable operation, delete /data/plugins/CarbonChat.disabled-<ts> and the chat-swap backup dir.
  • File issue at HelpChat/ChatChat for any 1.21.11 quirks observed (give back to upstream).

7. Files in this migration

staging/chatchat/
├── build/
│   ├── build.sh                                  # podman + temurin 21 reproducible build
│   └── ChatChat-1.0.0-SNAPSHOT-racked-1.jar      # GITIGNORED — rebuild from build.sh
├── configs/
│   ├── channels.yml                              # global channel, single rank-tier format
│   ├── extensions.yml                            # towny/dsrv/grief disabled, ess vanish on
│   ├── formats.yml                               # console-format + default fallback
│   └── settings.yml                              # PMs, mentions, item-format
└── scripts/
    ├── build.sh                                  # (in build/)
    ├── lp-migration.sh                           # carbon.* → chatchat.* perm grants
    ├── lp-rollback.sh                            # reverse of lp-migration.sh
    ├── rollback.sh                               # full revert: stop, restore Carbon, perm-rollback, start
    └── swap.sh                                   # full swap orchestrator with confirm gates