fix(family): a decision read as precedent says its reason once - to_brief for precedents and idea history; the decision log keeps the full row (#5131)
CI & Build / Python lint (push) Successful in 2s
CI & Build / Plugin hooks (push) Successful in 14s
CI & Build / TypeScript typecheck (push) Successful in 53s
CI & Build / integration (push) Successful in 1m13s
CI & Build / Python tests (push) Successful in 1m54s
CI & Build / Build & push image (push) Successful in 40s
CI & Build / Python lint (push) Successful in 2s
CI & Build / Plugin hooks (push) Successful in 14s
CI & Build / TypeScript typecheck (push) Successful in 53s
CI & Build / integration (push) Successful in 1m13s
CI & Build / Python tests (push) Successful in 1m54s
CI & Build / Build & push image (push) Successful in 40s
Each decision stored its reason three times (reason, before.reason, after.reason) and a promotion carried the whole criteria reasoning in evidence. Precedents (assess, promote, get_family_adoption, get_family_idea) and get_family_idea's history now serve FamilyDecision.to_brief(): reason once, before/after as status, canon_version and platforms, evidence as the cited list. list_family_decisions and the decision echoed back by a write keep to_dict. The precedent count was already bounded at five. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -67,3 +67,47 @@ def test_a_canon_ideas_scope_lives_on_the_idea_and_nowhere_else():
|
||||
|
||||
assert "topic_id" in family.FamilyIdea.__table__.c
|
||||
assert not {c.name for c in RulebookTopic.__table__.c} & {"platform_id", "platform_ids"}
|
||||
|
||||
|
||||
# --- a decision read as precedent (#5131) ------------------------------------------
|
||||
|
||||
def _assessment():
|
||||
reason = "the APK is built in CI and signed with the one release key"
|
||||
return family.FamilyDecision(
|
||||
id=7, idea_id=3, project_id=5, action="assess", reason=reason,
|
||||
before={"status": "unassessed", "reason": "", "canon_version": None},
|
||||
after={"status": "adopted", "reason": reason, "canon_version": 2},
|
||||
evidence={"evidence": ["ci.yml::android-release"], "source": "shapes"},
|
||||
precedent_ids=[4, 6], decided_via="agent", user_id=1,
|
||||
)
|
||||
|
||||
|
||||
def test_a_brief_carries_the_reason_once():
|
||||
brief = _assessment().to_brief()
|
||||
assert brief["reason"].startswith("the APK is built")
|
||||
assert brief["before"] == {"status": "unassessed", "canon_version": None}
|
||||
assert brief["after"] == {"status": "adopted", "canon_version": 2}
|
||||
# Nothing in it says the reason a second time.
|
||||
assert repr(brief).count("the APK is built") == 1
|
||||
|
||||
|
||||
def test_a_brief_keeps_the_cited_evidence_and_drops_the_rest():
|
||||
promotion = family.FamilyDecision(
|
||||
id=8, idea_id=3, project_id=None, action="promote", reason="proven twice",
|
||||
before=None,
|
||||
after={"status": "canon", "applies_when": "an app that ships its own APK",
|
||||
"canon_version": 1, "platforms": ["android-app"]},
|
||||
evidence={"criteria": {"proven": "a long paragraph"}, "evidence": ["#12"],
|
||||
"ledger_rows_opened": 3},
|
||||
)
|
||||
brief = promotion.to_brief()
|
||||
assert brief["evidence"] == ["#12"]
|
||||
assert brief["before"] is None
|
||||
assert brief["after"] == {"status": "canon", "canon_version": 1,
|
||||
"platforms": ["android-app"]}
|
||||
|
||||
|
||||
def test_the_full_row_is_still_the_audit_shape():
|
||||
full = _assessment().to_dict()
|
||||
assert full["after"]["reason"] == full["reason"]
|
||||
assert full["evidence"]["source"] == "shapes" and full["precedent_ids"] == [4, 6]
|
||||
|
||||
Reference in New Issue
Block a user