{"record":{"id":"3b5a31e183b040ab","repo":"affaan-m/ECC","slug":"label-probe-duration-is-not-bound-to-source-duration","errorCode":null,"errorMessage":"{label} probe duration is not bound to source duration","messagePattern":"(.+?) probe duration is not bound to source duration","errorType":"validation","errorClass":"ContractError","httpStatus":null,"severity":"error","filePath":"skills/taste-application/scripts/tasteforge/contract.py","lineNumber":56,"sourceCode":"    if isinstance(value, bool):\n        raise ContractError(f\"{label} contains a boolean numeric value\")\n    if isinstance(value, (int, float)):\n        if not math.isfinite(value):\n            raise ContractError(f\"{label} contains a non-finite numeric value\")\n    elif isinstance(value, dict):\n        for nested in value.values():\n            _validate_numeric_evidence(nested, label=label)\n    elif isinstance(value, list):\n        for nested in value:\n            _validate_numeric_evidence(nested, label=label)\n\n\ndef _validate_probe_evidence(probe: Any, source_duration: float, *, label: str) -> None:\n    if not isinstance(probe, dict):\n        raise ContractError(f\"{label} lacks probe evidence\")\n    _validate_numeric_evidence(probe, label=label)\n    if probe.get(\"duration\") != source_duration:\n        raise ContractError(f\"{label} probe duration is not bound to source duration\")\n    for field in (\"sample_times\", \"scene_changes\"):\n        values = probe.get(field, [])\n        if not isinstance(values, list):\n            raise ContractError(f\"{label} has invalid {field}\")\n        for value in values:\n            _validate_media_time(value, source_duration, label=f\"{label} {field}\")\n    samples = probe.get(\"style_samples\", [])\n    if not isinstance(samples, list) or any(not isinstance(sample, dict) for sample in samples):\n        raise ContractError(f\"{label} has invalid style evidence\")\n    for sample in samples:\n        _validate_media_time(sample.get(\"time\"), source_duration, label=f\"{label} style evidence\")\n\n\ndef _sha256(path: Path) -> str:\n    if not hasattr(os, \"O_NOFOLLOW\"):\n        raise ContractError(\"secure receipt validation requires O_NOFOLLOW\")\n    descriptor = os.open(path, os.O_RDONLY | os.O_NOFOLLOW)\n    digest = hashlib.sha256()","sourceCodeStart":38,"sourceCodeEnd":74,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/skills/taste-application/scripts/tasteforge/contract.py#L38-L74","documentation":"_validate_probe_evidence binds the probe's self-declared duration to the source duration passed in from the receipt. If probe['duration'] differs (by exact != comparison) from the receipt's source duration, the evidence is not bound to the artifact's media and is rejected. This prevents reusing probe evidence from a different file.","triggerScenarios":"validate_artifact_receipt where probe.duration and source_duration were generated from different media files, durations rounded differently in one place (12.5 vs 12.500001), or one field stored as int and the other float with unequal values.","commonSituations":"Copying a probe from a sibling receipt, re-encoding media without re-probing (duration shifted), float formatting differences between generator and validator, manual edits updating only one of the two duration fields.","solutions":["Re-run the probe against the exact media file so durations match exactly.","Update both the receipt source duration and probe duration together from the same measurement.","Normalize float precision at generation time (round both to a fixed number of decimals).","Verify you did not paste probe evidence from a different artifact's receipt."],"exampleFix":"// before\n\"source_duration\": 12.5, \"probe\": {\"duration\": 12.7, ...}\n// after\n\"source_duration\": 12.5, \"probe\": {\"duration\": 12.5, ...}","handlingStrategy":"validation","validationCode":"def probe_bound(receipt) -> bool:\n    src = receipt.get('source_duration')\n    probe = receipt.get('probe')\n    return isinstance(probe, dict) and probe.get('duration') == src","typeGuard":"def durations_match(receipt) -> bool:\n    return (isinstance(receipt, dict)\n            and isinstance(receipt.get('probe'), dict)\n            and receipt['probe'].get('duration') == receipt.get('source_duration'))","tryCatchPattern":"try:\n    validate_artifact_receipt(receipt)\nexcept ContractError as e:\n    if 'probe duration is not bound' in str(e):\n        receipt = regenerate_receipt(receipt['artifact'])  # re-probe same file\n    else:\n        raise","preventionTips":["Always generate source_duration and probe.duration from the same measurement","Re-probe media after any re-encode or trim","Round both duration fields identically at generation time","Never copy probe blocks between different artifacts' receipts"],"tags":["python","validation","provenance","media"],"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"}