{"record":{"id":"299d445026dc6607","repo":"affaan-m/ECC","slug":"approval-evidence-must-bind-exact-source-candidate-and","errorCode":null,"errorMessage":"approval evidence must bind exact source, candidate and placement","messagePattern":"approval evidence must bind exact source, candidate and placement","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"skills/taste-application/scripts/tasteforge/integration.py","lineNumber":334,"sourceCode":"            raise ValueError(\"insert requires an approved, resolved candidate\")\n        target = _range(item[\"timeline_range\"], config[\"baseline\"][\"timeline_range\"])\n        source = _range(item[\"candidate_range\"], [0, candidate[\"media_frames\"]])\n        if any(_overlap(target, p[\"range\"]) for p in config[\"protected_intervals\"]):\n            raise ValueError(\"insert overlaps protected original stack\")\n        if any(_overlap(target, span) for span in occupied):\n            raise ValueError(\"insert proposals overlap\")\n        if (item[\"retime\"] != \"none\" or target[1] - target[0] != source[1] - source[0]\n                or _rate(candidate[\"fps\"]) != _rate(config[\"baseline\"][\"fps\"])):\n            raise ValueError(\"candidate fps/duration/retime ambiguity\")\n        evidence = _artifact(item[\"approval_file\"], parse_json=True)\n        expected = {\"status\": \"approved\", \"candidate_sha256\": candidate[\"media\"][\"sha256\"],\n                    \"source_sha256\": config[\"source\"][\"media\"][\"sha256\"],\n                    \"compiled_input_sha256\": input_hash,\n                    \"edit_context_sha256\": edit_hash,\n                    \"candidate_range\": source, \"timeline_range\": target}\n        if not isinstance(evidence, dict) or any(\n                _canonical(evidence.get(key)) != _canonical(value) for key, value in expected.items()):\n            raise ValueError(\"approval evidence must bind exact source, candidate and placement\")\n        occupied.append(target)\n\n\ndef build_application_bundle(config: dict, compiled_input: dict | None, *, local_only: bool = False) -> dict:\n    \"\"\"Validate resident evidence and return a new deterministic, offline bundle.\"\"\"\n    if type(local_only) is not bool:\n        raise ValueError(\"local_only must be an exact boolean\")\n    _object(config, _REQUIRED, _OPTIONAL)\n    if len(_canonical(config)) > _MAX_JSON:\n        raise ValueError(\"application config exceeds local size limit\")\n    if local_only:\n        if compiled_input is not None:\n            raise ValueError(\"local-only preservation cannot accept provider input\")\n    else:\n        _object(compiled_input, {\"source_video\", \"compiled_prompt\"})\n        url = urlsplit(_text(compiled_input[\"source_video\"]))\n        if url.scheme != \"https\" or not url.hostname or url.username or url.password:\n            raise ValueError(\"source reference must be HTTPS without embedded credentials\")","sourceCodeStart":316,"sourceCodeEnd":352,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/skills/taste-application/scripts/tasteforge/integration.py#L316-L352","documentation":"_inserts validates that the approval file evidence for each insert cryptographically binds the exact candidate media, the exact source media, the compiled input digest, the edit-context digest, and the exact source and timeline ranges. Any missing, extra, or non-matching field in the approval JSON means the approval cannot be proven to refer to this exact placement, so bundling is refused.","triggerScenarios":"build_application_bundle reads item['approval_file'] via _artifact(parse_json=True) and compares it canonically against the expected dict {status:approved, candidate_sha256, source_sha256, compiled_input_sha256, edit_context_sha256, candidate_range, timeline_range}; any key whose canonical JSON differs, or a non-dict evidence file, triggers the error.","commonSituations":"Editing the timeline after approval was captured (ranges no longer match); rebuilding the compiled input so input_hash changed; reusing an approval file from a different candidate; hand-written approval JSON missing a required key or with floats formatted differently.","solutions":["Regenerate the approval file so its fields are computed from the current candidate, source, compiled input, and ranges","Ensure the approval file contains every expected key with status 'approved','candidate_sha256','source_sha256','compiled_input_sha256','edit_context_sha256','candidate_range','timeline_range'","Re-run the approval step after any change to the compiled input or edit context so the digests refresh","If ranges changed, capture a new approval for the new placement instead of hand-editing the old evidence"],"exampleFix":"// before (stale approval)\n{\"status\": \"approved\", \"candidate_sha256\": \"aaa...\"}\n// after (fully bound)\n{\"status\": \"approved\", \"candidate_sha256\": \"<candidate sha>\", \"source_sha256\": \"<source sha>\", \"compiled_input_sha256\": \"<input hash>\", \"edit_context_sha256\": \"<edit hash>\", \"candidate_range\": [0, 48], \"timeline_range\": [120, 168]}","handlingStrategy":"validation","validationCode":"import json\ndef approval_is_current(evidence, expected):\n    if not isinstance(evidence, dict):\n        return False\n    return all(json.dumps(evidence.get(k), sort_keys=True) == json.dumps(v, sort_keys=True)\n               for k, v in expected.items())","typeGuard":"def is_bound_approval(e):\n    return isinstance(e, dict) and all(k in e for k in (\"status\",\"candidate_sha256\",\"source_sha256\",\"compiled_input_sha256\",\"edit_context_sha256\",\"candidate_range\",\"timeline_range\"))","tryCatchPattern":"try:\n    bundle = build_application_bundle(cfg, ci)\nexcept ValueError as e:\n    if \"approval evidence must bind\" in str(e):\n        recapture_approvals(cfg)  # regenerate approval files from current inputs\n    else:\n        raise","preventionTips":["Always recapture approval evidence after any edit to compiled input or timeline","Never hand-edit approval JSON files","Include all seven binding fields when generating approvals","Store approvals per-candidate-id to avoid cross-candidate reuse"],"tags":["validation","approval","integrity","hash-binding"],"backgroundTag":"checksum-mismatch","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"}