"""musehub#227 — "I3" must not name two different, non-reconciled mechanisms. Background: musehub/graph/push_validator.py's I3 (per-edge signature authorization, actually enforced at push time — hard error) and musehub/graph/quorum.py's I3 (recursive weighted-vote quorum tallying, never called by anything outside its own module/tests — see musehub#225) both claimed the "I3" label with genuinely different meanings. Resolution: push_validator.py's definition is the real, enforced I3 (it's wired into wire_push); quorum.py's mechanism is renamed away from "I3" entirely, without deleting it (deletion is musehub#225's call, not this ticket's). musehub/services/musehub_governance.py::check_quorum (proposal-review approval counting) was never actually confused with either — it shares the English word "quorum" but no number/label — confirmed by audit, no change needed there, so no test for it below. """ from __future__ import annotations import re def _claims_label(doc: str, label: str) -> bool: """Return True if *doc* uses *label* as an invariant-naming claim — i.e. a line starting with the label immediately followed by a separator (matching this codebase's own convention, e.g. "I3 Authorization — hard error" or "I3 Quorum soundness —") — as opposed to merely mentioning the label in explanatory prose (e.g. "the actual push-time invariant labeled \"I3\" is ...", which is fine and expected in a docstring that explains why a collision was resolved). """ pattern = re.compile(rf"^{re.escape(label)}\b.*[—:]", re.MULTILINE) return bool(pattern.search(doc)) def test_push_validator_module_docstring_claims_i3_authorization() -> None: """push_validator.py is the one enforced mechanism — it keeps the I3 label.""" from musehub.graph import push_validator doc = push_validator.__doc__ or "" assert _claims_label(doc, "I3") assert "Authorization" in doc def test_quorum_module_no_longer_claims_i3() -> None: """quorum.py's recursive vote-tallying mechanism must not claim to be I3 — that label belongs to push_validator.py's (different, enforced) mechanism. musehub#225 decides whether this code is kept or deleted; this test only asserts it no longer misuses the "I3" name while it exists. Mentioning "I3" in explanatory prose (e.g. "the actual I3 is defined elsewhere") is fine — claiming it as this module's own label is not. """ from musehub.graph import quorum doc = quorum.__doc__ or "" assert not _claims_label(doc, "I3"), ( f"quorum.py's module docstring still claims 'I3' as its own label " f"— that label is reserved for push_validator.py's enforced " f"authorization mechanism (musehub#227). Got: {doc!r}" ) def test_quorum_and_push_validator_docstrings_do_not_both_claim_i3() -> None: """Belt-and-suspenders: whatever these two modules claim, they must not both claim the same invariant label for different mechanisms.""" from musehub.graph import push_validator, quorum push_claims_i3 = _claims_label(push_validator.__doc__ or "", "I3") quorum_claims_i3 = _claims_label(quorum.__doc__ or "", "I3") assert not (push_claims_i3 and quorum_claims_i3), ( "Both push_validator.py and quorum.py claim 'I3' as their own " "label — exactly the naming collision musehub#227 reports." )