Every generation insert/replace path now drains node-level state to
one doc-root MergeAppState (weakest priority, doc-owned keys always
win): insert_node + standalone replace_node wrap via with_hoisted_state;
batch_program's I()/R() sibling-emit through the program finisher's own
batch — emitted only after the insert/replace line succeeds so a failed
best-effort line cannot leak orphan state (recorded order keeps merge
before its insert). Includes the radio_group promote e2e and 8 new
hoist/leak regression tests. The shared helpers landed with the
script-gen series' batch_design commit.