What happened
referenced_by and cascade_plan walk pages, claims, and relations but never goals — even though Goal.claims / Goal.entities are first-class refs validated by storage._validate_goal_refs.
After goals landed (#427 / Goal artifact), deleting a claim (or entity) that a goal cites succeeds because the delete gate returns []. Later lifecycle.set_goal_status → update_goal → _validate_goal_refs raises ValueError: goal … references unknown claim.
Expected
referenced_by(store, "claim", id) includes goal '<gid>' when that goal cites the claim. cascade_plan / cascade approve unlinks the claim (or entity) from the goal the same way it unlinks from pages.
Repro
from vouch.storage import KBStore
from vouch import proposals, lifecycle
from vouch.models import Claim
store = KBStore.init(tmp)
src = store.put_source(b"e")
pr = proposals.propose_claim(store, text="the sky is blue", evidence=[src.id], proposed_by="a")
claim = proposals.approve(store, pr.id, approved_by="h")
gpr = proposals.propose_goal(store, title="keep sky blue", claims=[claim.id], proposed_by="a")
proposals.approve(store, gpr.id, approved_by="h")
assert proposals.referenced_by(store, "claim", claim.id) # today: []
dpr = proposals.propose_delete(store, target_kind="claim", target_id=claim.id, proposed_by="a")
proposals.approve(store, dpr.id, approved_by="h") # succeeds today
lifecycle.set_goal_status(store, goal_id=gpr.payload["id"] if False else store.list_goals()[0].id, status="done", actor="h") # ValueError
What happened
referenced_byandcascade_planwalk pages, claims, and relations but never goals — even thoughGoal.claims/Goal.entitiesare first-class refs validated bystorage._validate_goal_refs.After goals landed (#427 / Goal artifact), deleting a claim (or entity) that a goal cites succeeds because the delete gate returns
[]. Laterlifecycle.set_goal_status→update_goal→_validate_goal_refsraisesValueError: goal … references unknown claim.Expected
referenced_by(store, "claim", id)includesgoal '<gid>'when that goal cites the claim.cascade_plan/ cascade approve unlinks the claim (or entity) from the goal the same way it unlinks from pages.Repro