affaan-m/ECC · error · ContractError
rule lacks reference evidence
Error message
rule {rule.get('rule_id')} lacks reference evidence What it means
Each provenance rule must cite at least one piece of reference evidence. When a rule's 'evidence' key is missing, not a list, or an empty list, this ContractError is raised so every derived rule is traceable to its source media.
Solutions
- Add a non-empty 'evidence' list to each rule object in the provenance payload.
- Check the rule-generation code path that creates rule dicts and ensure it appends evidence items before validation.
- Regenerate provenance with the official Tasteforge producer instead of hand-editing rule entries.
- Log the rule_id reported in the error to locate the exact offending rule in the payload.
Example fix
// before
rule = {"rule_id": "r1"}
// after
rule = {"rule_id": "r1", "evidence": [{"reference_sha256": "<64-hex>", "times": [0.0], "source_duration": 10.0}]} Defensive patterns
Strategy: validation
Validate before calling
missing = [r.get('rule_id') for r in payload.get('rules', [])
if not isinstance(r.get('evidence'), list) or not r['evidence']]
if missing:
raise ValueError(f"rules lacking evidence: {missing}") Type guard
def rule_has_evidence(rule: dict) -> bool:
ev = rule.get("evidence")
return isinstance(ev, list) and len(ev) > 0 and all(isinstance(i, dict) for i in ev) Try / catch
try:
validate_provenance(payload)
except ContractError as e:
if "lacks reference evidence" in str(e):
rule_id = str(e).split()[-1] if e.args else "unknown"
payload = attach_evidence(payload, rule_id)
else:
raise Prevention
- Build rule objects with a helper that always attaches at least one evidence item.
- Lint provenance JSON for required keys (rule_id, evidence) before bundling.
- Avoid copying rule templates without their evidence field.
When it happens
Trigger: validate_provenance encounters a rule dict like {'rule_id': 'r1'} with no 'evidence' key, {'rule_id': 'r1', 'evidence': None}, or {'rule_id': 'r1', 'evidence': []}.
Common situations: Producers that build rule objects but never attach evidence entries; a rule template copied without its evidence field; evidence stripped by a downstream transform that drops keys; rules authored manually in a hand-edited provenance file.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- a generated candidate cannot claim original-source identity
- anchor evidence source duration is not bound to its receipt…
- artifact cites an unknown provenance source
- artifact has an unbound source duration
- artifact has invalid reference path
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/1c0ab65ee0d6a360.
Report an issue: GitHub.
Appendix: source
Thrown at skills/taste-application/scripts/tasteforge/contract.py:266
digest = anchor.get("source_ref_sha256")
expected_duration = reference_durations.get(digest) if isinstance(digest, str) else None
if expected_duration is None or anchor.get("source_duration") != expected_duration:
raise ContractError("anchor evidence source duration is not bound to its receipt reference")
for event in events:
placement = event.get("placement")
if not isinstance(placement, dict) or not {"safe_area", "max_coverage", "occlusion_policy"}.issubset(placement):
raise ContractError(f"effect {event.get('effect')} lacks placement constraints")
def validate_provenance(payload: dict[str, Any]) -> None:
"""Require every declared rule to cite immutable, timestamped evidence."""
rules = payload.get("rules")
if not isinstance(rules, list) or not rules:
raise ContractError("provenance must contain derived rules")
for rule in rules:
evidence = rule.get("evidence")
if not isinstance(evidence, list) or not evidence:
raise ContractError(f"rule {rule.get('rule_id')} lacks reference evidence")
for item in evidence:
digest = item.get("reference_sha256")
if not isinstance(digest, str) or len(digest) != 64:
raise ContractError(f"rule {rule.get('rule_id')} lacks immutable reference evidence")
times = item.get("times")
if not isinstance(times, list) or not times:
raise ContractError(f"rule {rule.get('rule_id')} lacks time evidence")
source_duration = item.get("source_duration")
for time in times:
_validate_media_time(
time, source_duration, label=f"rule {rule.get('rule_id')} time evidence"
)
def validate_manifests(manifests_dir: str | Path) -> None:
"""Require image, video, and 3D-asset dry-run request manifests."""
manifests_dir = Path(manifests_dir)
found = {path.stem for path in manifests_dir.glob("*.json")} if manifests_dir.is_dir() else set()View on GitHub (pinned to 8321021c54)