fix(client): TagExtractor tolerates paren-less moves + scrubs misformatted move tags (live-review LF1/LF2)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-10 13:15:18 -05:00
parent 86d1352b19
commit 2b1c11b1e6
2 changed files with 45 additions and 1 deletions

View File

@@ -38,3 +38,45 @@ func test_no_tags_is_clean_passthrough():
assert_eq(r["dispositions"], [])
assert_eq(r["moves"], [])
assert_eq(r["clean_text"], "no tags here")
# LF1 — a live model emitted [MOVE: refuse] with no parens at all. The move
# must still be recognized so the legal move isn't silently dropped.
func test_move_without_parens_is_parsed():
var r := TagExtractor.extract("[MOVE: refuse]")
assert_eq(r["moves"][0]["name"], "refuse")
assert_eq(r["moves"][0]["args"], [])
# LF1 regression guard — explicit empty parens must still work as before.
func test_move_with_explicit_empty_parens_still_parsed():
var r := TagExtractor.extract("[MOVE: end_conversation()]")
assert_eq(r["moves"][0]["name"], "end_conversation")
assert_eq(r["moves"][0]["args"], [])
# LF1 regression guard — well-formed args must still parse unchanged.
func test_move_with_args_still_parsed():
var r := TagExtractor.extract("[MOVE: reveal(varrell_twins)]")
assert_eq(r["moves"][0]["name"], "reveal")
assert_eq(r["moves"][0]["args"], ["varrell_twins"])
# LF2 — a live model emitted [adjust_disposition(-5)] without the MOVE:
# prefix. It must not be parsed/applied (untrusted, malformed), but it must
# also not leak into player-visible prose as literal tag text.
func test_bare_lowercase_move_shape_is_scrubbed_not_parsed():
var r := TagExtractor.extract("He glares. [adjust_disposition(-5)] Fine.")
assert_false(r["clean_text"].contains("[adjust_disposition(-5)]"))
assert_eq(r["moves"], [])
assert_eq(r["dispositions"], [])
# LF2 regression guard — a well-formed MOVE tag alongside a bare lowercase
# shape in the same prose must still be parsed and stripped correctly.
func test_wellformed_move_still_parsed_alongside_bare_lowercase_shape():
var r := TagExtractor.extract("[MOVE: reveal(x)] He glares. [adjust_disposition(-5)] Fine.")
assert_eq(r["moves"][0]["name"], "reveal")
assert_eq(r["moves"][0]["args"], ["x"])
assert_false(r["clean_text"].contains("[MOVE:"))
assert_false(r["clean_text"].contains("[adjust_disposition(-5)]"))