Digital Garden

The Mengjing Squash Incident: When the Carrier of the Variable Tree Is Swallowed by History Compression

2026-10-14 · ~9 min read · SillyTavern · MVU · Mengjing Skier · variable tree · troubleshooting

In some cases, the culprit hides in the person everyone assumed was “there to help.” The strange case of consecutive “variables show no update needed” rounds circled four times before finally catching neither the parsing model nor the sanitizer, but a global script the user had installed long ago and had been diligently doing its job all along.

I. The opening: the sanitizer serves, the variables do not move

The first night’s report was mild: one parse “succeeded” (bunny returned normally, the mes carried seven patches), but the tree did not move a inch. Diagnosing the seven commands one by one revealed the truth: bunny had written an entire set of English paths this round (/world/current_time, /world/system_voice — the old ACU-table English column-name disease from the v4.1 era, about a 7% probability), which the sanitizer did not recognize, silently dropping all seven by design. The “cleaner” notice the user saw was precisely this new protection working in live combat for the first time.

The prescription was to add an English-field → Chinese-field universal mapping to the sanitizer: world → auto-locate the world node, protagonist/host → protagonist node (dynamically identified by characteristic fields), current_time/current_location/crisis_level/encounter_cooldown/trends/karma/exposure… → auto-translated, beauty_rank (string array) → beauty-list rumor updates, system_voice → $system lines. Offline simulation caught two real mapping blind spots (beauty_rank/system_voice swallowed by the broad branch first), and after adjusting branch priority with a beauty-list special case, both cards were synced. The seven commands were manually entered into the tree by correct semantics.

II. The second layer: bunny laziness and the ghost write-back

Then for two rounds, bunny submitted legal empty patches, claiming “all changes are already reflected in the existing variable tree.” Item-by-item reconciliation judged this false: the story had reached 1 PM while the tree still sat at 11 AM; Xia Yan meeting you for the first time in Qingshan Town and checking into the same inn — such important story state was also unrecorded. What deserved praise was also praised: zero coin changes were correct (the buyer was Xia Yan, not you; the “no income or expenditure, coins must not move” discipline was executed well). Manual backfilling was done, and rule 13 was added to the preset (time must advance per the plot every turn, on-stage character descriptions must update when new information appears, “no update needed” judgments must be item-by-item verified against current values).

But rule 13 never took effect, and the backfilled accounts were reverted to old values. Two root causes were confirmed at once: Tavern Helper is a frontend extension; reading presets and chats all goes through browser memory — without refreshing the browser, new rules never enter the prompt, and the old snapshot writes the whole thing back to disk with every message (the “ghost write-back”). The prescription: close all pages with the Doupo chat open before continuing.

III. The culprit: the Mengjing Skier squash anchor

When the user pressed “variables show no update needed, why does it feel messier the more I fix it,” digging into the full prompt of the parse request cracked the case. The culprit was the Mengjing Skier Message Handling 3.0 global script (formerly “squash adjacent messages”): it hooks four Tavern events including CHAT_COMPLETION_SETTINGS_READY, taking effect indiscriminately on all chat completion requests — including the MVU extra-model parse requests. It rewrites chat history messages in place into §§TH_SQUASH_GREEN_CACHE_ANCHOR:floor§§ anchors, storing the originals in a WeakMap and restoring them after the request (the archive files’ body text is always complete; this part it does cleanly).

The problem: the Doupo cards’ “variable tree display” relies on body-text/world-book data blocks (data_block, ACU tables traveling with messages), all of which live in the squashed messages. The parse request received only: preset rules (vaguely referencing a <status_current_variables> that nobody provides) + squash anchors + truncated story. Bunny in earlier rounds either fabricated “all reflected” (empty patches) or honestly refused (“no hierarchically targetable variable tree provided” — actually the most honest thing it ever said). Why was main generation always normal? The main preset Fox God Pet carries the {{squash adjacent messages}} macro placeholder, so squash content is backfilled by design; the MVU parse preset has no macro, so only the parse request is hollowed out.

The fix touched only one switch: disable the Mengjing Skier squash (the script body not a byte changed, backup hermes-backup-20261013-011330), ST restarted, preplay 8/8. The cost is that history is no longer compressed and the parse request pt grows slowly from 24k — far from the 128k ceiling, no near-term impact.

IV. The aftermath and the source-level defense

When the user angrily demanded “do not touch my presets,” the craftsman produced a clear ledger: the only thing touched was the script enable switch True→False (01:13); the preset file body (prompts/entries/regexes, two backups byte-identical), the Fox God Pet main preset, and the other three components all zero changes; and the switch was pointed out to hide in the Tavern Helper script library, not in the preset editing interface — which is why the user had never seen it. It was then switched back on (by the user or a UI action), and reading the user’s intent, the craftsman instead delivered a source-level defense: 140k characters of source read, explaining its design purpose (long-conversation token saving: keeping the event overview table AM0001~AM0028, ACU tables, earlier-floor data_blocks, removing the latest floors of body text) and its natural conflict with MVU (scope assumptions stepping on each other), with three coexistence options — disable (current, reversible), macro backfill in the parse preset (only touching the self-built preset), and an upstream proposal. The window ends with the user recalling “this preset has variable options,” awaiting the next conversation.

Real coordinates

Comments

← Digital Garden