{"record":{"id":"c4994b6849ba500f","repo":"affaan-m/ECC","slug":"effect-event-get-effect-lacks-reference-evidence","errorCode":null,"errorMessage":"effect {event.get('effect')} lacks reference evidence","messagePattern":"effect (.+?) lacks reference evidence","errorType":"validation","errorClass":"ContractError","httpStatus":null,"severity":"error","filePath":"skills/taste-application/scripts/tasteforge/contract.py","lineNumber":207,"sourceCode":"    timeline = recipe.get(\"timeline_duration\")\n    if not _is_finite_real(timeline):\n        raise ContractError(\"effect recipe must declare a finite positive timeline duration\")\n    timeline = cast(float, timeline)\n    if float(timeline) <= 0:\n        raise ContractError(\"effect recipe must declare a finite positive timeline duration\")\n    for event in events:\n        start = event.get(\"time\")\n        duration = event.get(\"duration\")\n        if (not _is_finite_real(start) or not _is_finite_real(duration)\n                or float(start) < 0 or float(duration) <= 0):\n            raise ContractError(\"effect event start and duration must be finite positive timeline values\")\n        start = cast(float, start)\n        duration = cast(float, duration)\n        if float(start) + float(duration) > float(timeline) + 1e-9:\n            raise ContractError(\"effect event end exceeds the declared timeline\")\n        evidence = event.get(\"evidence\")\n        if not isinstance(evidence, dict):\n            raise ContractError(f\"effect {event.get('effect')} lacks reference evidence\")\n        _validate_media_time(\n            evidence.get(\"time\"), evidence.get(\"source_duration\"), label=\"effect evidence time\"\n        )\n        if reference_durations is not None:\n            digest = evidence.get(\"reference_sha256\")\n            expected_duration = reference_durations.get(digest) if isinstance(digest, str) else None\n            if expected_duration is None or evidence.get(\"source_duration\") != expected_duration:\n                raise ContractError(\"effect evidence source duration is not bound to its receipt reference\")\n    times = [float(event[\"time\"]) for event in events]\n    if times != sorted(times) or len(times) != len(set(times)):\n        raise ContractError(\"effect event times must be unique and increasing\")\n    intervals = [round(b - a, 6) for a, b in zip(times, times[1:])]  # noqa: RUF007\n    if len(set(intervals)) <= 1:\n        raise ContractError(\"stochastic schedule is periodic; intervals must vary\")\n    for period in range(1, len(intervals) // 2 + 1):\n        if all(intervals[index] == intervals[index % period] for index in range(len(intervals))):\n            raise ContractError(\"stochastic schedule is periodic; repeating interval cycle\")\n    if recipe.get(\"periodic\") is not False:","sourceCodeStart":189,"sourceCodeEnd":225,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/skills/taste-application/scripts/tasteforge/contract.py#L189-L225","documentation":"Every effect event must carry reference evidence: a dict under the 'evidence' key that anchors the effect to source media. If 'evidence' is missing or is not a dict, the event's effect name is interpolated into the error to identify the offender. Evidence is required so effect outputs can be verified against the source material.","triggerScenarios":"validate_effect_recipe called where an event dict has no 'evidence' key, or evidence is None, a list, or any non-dict value.","commonSituations":"Hand-built events that skip the evidence block; a generator failing to attach evidence when reference media lookup fails; JSON schemas from older versions without evidence; typos like 'evidences' or 'ref'.","solutions":["Attach a valid evidence dict to the event: event['evidence'] = {'time': ..., 'source_duration': ..., 'reference_sha256': ...}.","Check the recipe generator/reference-lookup step for why evidence was not attached.","Fix key typos so the evidence dict lands under 'evidence'."],"exampleFix":"# before\nevent = {\"effect\": \"cv_blur\", \"time\": 1.0, \"duration\": 2.0}\n# after\nevent = {\"effect\": \"cv_blur\", \"time\": 1.0, \"duration\": 2.0,\n         \"evidence\": {\"time\": 1.0, \"source_duration\": 10.0, \"reference_sha256\": \"<hex>\"}}","handlingStrategy":"validation","validationCode":"for ev in recipe[\"events\"]:\n    if not isinstance(ev.get(\"evidence\"), dict):\n        raise ValueError(f\"event {ev.get('effect')} is missing an evidence dict\")","typeGuard":"def has_evidence(ev: dict) -> bool:\n    return isinstance(ev.get(\"evidence\"), dict)","tryCatchPattern":"try:\n    validate_effect_recipe(recipe)\nexcept ContractError as exc:\n    if \"lacks reference evidence\" in str(exc):\n        effect = extract_effect_name(str(exc))\n        recipe = {**recipe, \"events\": [attach_evidence(ev, effect) if not isinstance(ev.get(\"evidence\"), dict) else ev for ev in recipe[\"events\"]]}\n        validate_effect_recipe(recipe)\n    else:\n        raise","preventionTips":["Require evidence at event-construction time (fail fast in your builder).","Verify the reference-media lookup succeeds before emitting events.","Spell the key exactly 'evidence'; avoid aliases."],"tags":["validation","evidence","events"],"backgroundTag":"missing-required-argument","analyzedSha":"8321021c54d670126ce3b2969d5deb880b4b0c2a","analyzedAt":"2026-09-16T10:08:13.343Z","contentChangedAt":"2026-09-16T10:08:13.343Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}