Validate every chain-step merge output; reconcile insertions globally; atomic writes - #33
Merged
Merged
Conversation
…; atomic writes Three fixes from using the live install as a regression testing ground: - Chain-step output validation: DiffPlex's ThreeWayDiffer bug has a SILENT variant (no exception, no conflict block, content lost or duplicated) that only ever had the exception/conflict paths guarded - "clean" whole-file outputs shipped unchecked, and chains multiplied exposure. Observed live: mid-chain steps of a real 12-mod r4Player.ws chain silently duplicated three functions, and an actor.ws step duplicated ManageMonstersRegenTimer. Every clean output (and every function-level rescue output) now passes structural sanity plus per-scoped-unit no-duplication/no-loss invariants against its three inputs; a violation routes the step to the function-level rescue (which re-merges from the ORIGINAL inputs), then to skip - the corrupt text is never written, not even as a sidecar. - Global cross-slot insertion reconciliation: re-merge chains start from the previous full merge, so the accumulated side already contains what later mods insert - at different positions than the mods' own copies, which per-slot reconciliation never pairs up (emitting BOTH, the observed duplication) and whose whitespace-only formatting differences the old byte-identical rule declined on. Same-name insertions across sides now reconcile globally: identical or whitespace-equal keeps the accumulated side's copy (span emission cuts consumed units out while preserving position/separators); genuinely different content still declines. - Atomic merged-file writes (WriteUtf16Atomic: temp + same-volume rename): merged output lands inside the live game's Mods tree, and a game launch during a 40-file re-merge compiled truncated scripts into "'X' is not a member of Y" errors that looked exactly like a bad merge. 8 new tests (153 total). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GXAuGMLB44T5Zv5o5ZzKah
Owner
Author
Mirrored end-to-end validation results (post-redeploy)Full real-pipeline run (MCP
73 total: 153 unit tests + this end-to-end run, all green. 🤖 Generated with Claude Code |
This was referenced Aug 11, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Round 2 of engine hardening, driven by using the real 199-mod install as a regression testing ground (read-only + mirrored runs). Three root causes found and fixed:
1. Silent chain-step corruption was ungated
DiffPlex's ThreeWayDiffer bug has a silent variant — no exception, no conflict block, but content lost or duplicated (documented in CLAUDE.md with measured rates). Only the exception/conflict paths were guarded; "clean" whole-file outputs shipped unchecked, and multi-step chains multiplied exposure. Observed live: steps of the real r4Player.ws chain silently duplicated
SetSlowActive/GetVoiceSetLastPlayed/SetVoiceSetLastPlayed, and an actor.ws step duplicatedManageMonstersRegenTimer— corruption that shipped in every previous successful run. Now every clean whole-file output and every function-level rescue output is validated: structural sanity gate + per-scoped-unit no-duplication (a name can't occur more often than in any input) and no-loss (a name in both inputs, or inserted by either, must survive) invariants. A violation routes the step to the function-level rescue (which re-merges from the original inputs, sidestepping the corrupt output), then to skip — corrupt text is never written anywhere, sidecar included.2. Insertion reconciliation was per-slot only
Re-merge chains start from the previous full merge, so the accumulated side already contains what later chain mods insert — at different slots than the mods' own copies. Per-slot reconciliation never pairs those up (both get emitted → the observed duplication), and byte-identical-only matching declined on whitespace-only formatting drift.
ReconcileInsertionsGloballynow pairs same-scoped-name insertions across all slots and both sides: identical or whitespace-equal (the engine's existing NBSP-safe collapse standard) keeps the accumulated side's copy — span emission cuts consumed units out of verbatim spans while preserving position and separators — and genuinely different content still declines as a real new-functionality collision.3. Merged-file writes were non-atomic
Merged output lands inside the live game's Mods tree; launching the game during a 40-file re-merge compiled truncated scripts into
'X' is not a member of Yerrors that perfectly impersonated a bad merge (a full evening of forensics proved every symbol present-and-correctly-scoped in the on-disk output).WriteUtf16Atomic(same-directory temp +File.Moveoverwrite) closes that window for both merge and rescue outputs.Validation
🤖 Generated with Claude Code
https://claude.ai/code/session_01GXAuGMLB44T5Zv5o5ZzKah