affaan-m/ECC · error · ValueError

approval evidence must bind exact source, candidate and…

Error message

approval evidence must bind exact source, candidate and placement

What it means

_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.

Solutions

  1. Regenerate the approval file so its fields are computed from the current candidate, source, compiled input, and ranges
  2. 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'
  3. Re-run the approval step after any change to the compiled input or edit context so the digests refresh
  4. If ranges changed, capture a new approval for the new placement instead of hand-editing the old evidence

Example fix

// before (stale approval)
{"status": "approved", "candidate_sha256": "aaa..."}
// after (fully bound)
{"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]}
Defensive patterns

Strategy: validation

Validate before calling

import json
def approval_is_current(evidence, expected):
    if not isinstance(evidence, dict):
        return False
    return all(json.dumps(evidence.get(k), sort_keys=True) == json.dumps(v, sort_keys=True)
               for k, v in expected.items())

Type guard

def is_bound_approval(e):
    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"))

Try / catch

try:
    bundle = build_application_bundle(cfg, ci)
except ValueError as e:
    if "approval evidence must bind" in str(e):
        recapture_approvals(cfg)  # regenerate approval files from current inputs
    else:
        raise

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.

Related errors


AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16). Data as JSON: /api/errors/299d445026dc6607. Report an issue: GitHub.

Appendix: source

Thrown at skills/taste-application/scripts/tasteforge/integration.py:334

            raise ValueError("insert requires an approved, resolved candidate")
        target = _range(item["timeline_range"], config["baseline"]["timeline_range"])
        source = _range(item["candidate_range"], [0, candidate["media_frames"]])
        if any(_overlap(target, p["range"]) for p in config["protected_intervals"]):
            raise ValueError("insert overlaps protected original stack")
        if any(_overlap(target, span) for span in occupied):
            raise ValueError("insert proposals overlap")
        if (item["retime"] != "none" or target[1] - target[0] != source[1] - source[0]
                or _rate(candidate["fps"]) != _rate(config["baseline"]["fps"])):
            raise ValueError("candidate fps/duration/retime ambiguity")
        evidence = _artifact(item["approval_file"], parse_json=True)
        expected = {"status": "approved", "candidate_sha256": candidate["media"]["sha256"],
                    "source_sha256": config["source"]["media"]["sha256"],
                    "compiled_input_sha256": input_hash,
                    "edit_context_sha256": edit_hash,
                    "candidate_range": source, "timeline_range": target}
        if not isinstance(evidence, dict) or any(
                _canonical(evidence.get(key)) != _canonical(value) for key, value in expected.items()):
            raise ValueError("approval evidence must bind exact source, candidate and placement")
        occupied.append(target)


def build_application_bundle(config: dict, compiled_input: dict | None, *, local_only: bool = False) -> dict:
    """Validate resident evidence and return a new deterministic, offline bundle."""
    if type(local_only) is not bool:
        raise ValueError("local_only must be an exact boolean")
    _object(config, _REQUIRED, _OPTIONAL)
    if len(_canonical(config)) > _MAX_JSON:
        raise ValueError("application config exceeds local size limit")
    if local_only:
        if compiled_input is not None:
            raise ValueError("local-only preservation cannot accept provider input")
    else:
        _object(compiled_input, {"source_video", "compiled_prompt"})
        url = urlsplit(_text(compiled_input["source_video"]))
        if url.scheme != "https" or not url.hostname or url.username or url.password:
            raise ValueError("source reference must be HTTPS without embedded credentials")

View on GitHub (pinned to 8321021c54)