fix(inplace,embed): input set back mid-flight, report inputs, ambiguous anchors

Four items owed after S5b, reported by design-dev during the anti-slop run:

- carry() measured a sent-then-changed form against its OLD DEFAULTS. An
  answer set back mid-flight to the value the page first showed read as
  untouched, and the swap put the just-saved value over it. A form sent and
  then changed is now measured against its sent snapshot (sentSet.snapOf).
- The embed's clean-batch reload saw only our own forms. A report's own
  inputs lost whatever the operator had typed into them. Unsaved text in
  any control we don't own now holds the reload, and the page says so.
- Two r2b.toml rows ("D3 a stored theme...", "D3 forced light...") matched
  twice, so they proved only by where the first match fell. Both are
  re-anchored, and scripts/mutation_check.py now refuses any anchor that
  matches more than once. A new tool control covers that.
- The r2_flow contract's C3 steps 2 and 4 now say what S5b superseded. U3
  gains the report-input rule.

Mutation rows: u3_submit_all +1, r2_submit_all +1. Four rows were
re-anchored onto the moved lines.
This commit is contained in:
vh
2026-09-28 16:52:42 -07:00
parent a22a00b82e
commit 377e652670
13 changed files with 194 additions and 32 deletions
+27
View File
@@ -1031,3 +1031,30 @@ def test_a_refusal_blocks_the_reload_even_when_nothing_reads_dirty(browser, live
page.close()
assert same, "the page reloaded over a refused POST"
assert shown, "the refusal was never said"
def test_a_clean_batch_does_not_reload_over_text_typed_into_the_report(browser, live):
"""design-dev's report, 2026-09-28: a successful batch reloaded whenever
none of OUR forms was dirty — but a report can carry inputs of its own, and
the reload took whatever the operator had typed into them. Unsaved input
anywhere on the page now holds the reload, and the page says so."""
base, data = live
b = _asks(data / "b", ("a1", "a2"))
html = ("<!doctype html><title>r</title><body>"
'<textarea id="scratch"></textarea>'
f"{SEAM}</body>")
page = _open(browser, base, "b", html, b)
page.wait_for_selector("#bk-ask-a2-submit")
page.evaluate("window.__same = 1")
page.fill("#scratch", "my own working")
_choice(page, "a1", "yes")
_choice(page, "a2", "no")
_press(page, "a1")
page.wait_for_selector("#bk-ask-a1-submit .bk-ask-status:not([hidden])", timeout=10000)
said = page.locator("#bk-ask-a1-submit .bk-ask-status").inner_text()
same = page.evaluate("window.__same === 1")
kept = page.input_value("#scratch")
page.close()
assert same and kept == "my own working", (same, kept)
assert "reload" in said.lower(), said
assert {k: v["choice"] for k, v in _answers(b).items()} == {"a1": "yes", "a2": "no"}