reject character/world updates that are <70% of original size

Adds _validate_update_size() safeguard that skips writing if the
LLM returns a fragment instead of the full file — warns on stderr.
This commit is contained in:
Dejvino 2026-06-25 19:31:58 +02:00
parent 4c968f8096
commit 8c06fd1be7

View File

@ -636,8 +636,6 @@ class GameEngine:
if finalize_call: if finalize_call:
args = finalize_call.get("args", {}) args = finalize_call.get("args", {})
errs = [] errs = []
if not args.get("dm_status"):
errs.append("dm_status is required")
if not args.get("book_log"): if not args.get("book_log"):
errs.append("book_log is required") errs.append("book_log is required")
if not args.get("user_prompt"): if not args.get("user_prompt"):
@ -767,13 +765,36 @@ class GameEngine:
# ── State Persistence ─────────────────────────────────────────────── # ── State Persistence ───────────────────────────────────────────────
def _validate_update_size(self, name: str, new_content: str, path: Path) -> bool:
"""Reject updates that are more than 30% shorter than the existing file
likely the LLM pasted a fragment instead of the full state."""
if not path.exists():
return True
old = path.read_text().strip()
if not old:
return True
ratio = len(new_content) / len(old)
if ratio < 0.7:
import sys
print(
f"WARNING: {name} update rejected ({ratio:.0%} of original size "
f"= {len(new_content)} vs {len(old)} chars) — likely a partial paste.",
file=sys.stderr,
)
return False
return True
def apply_state(self, result: TurnResult) -> None: def apply_state(self, result: TurnResult) -> None:
"""Write state changes from a TurnResult to disk.""" """Write state changes from a TurnResult to disk."""
if result.character_updates: if result.character_updates and self._validate_update_size(
"character", result.character_updates, CHAR_PATH
):
CHAR_PATH.write_text(result.character_updates.strip() + "\n") CHAR_PATH.write_text(result.character_updates.strip() + "\n")
if result.world_updates: if result.world_updates and self._validate_update_size(
"world", result.world_updates, WORLD_PATH
):
WORLD_PATH.write_text(result.world_updates.strip() + "\n") WORLD_PATH.write_text(result.world_updates.strip() + "\n")
if result.ambience: if result.ambience: