{"record":{"id":"c5bccbbf333c12d7","repo":"affaan-m/ECC","slug":"artifact-relative-has-invalid-reference-time-provenance","errorCode":null,"errorMessage":"artifact {relative} has invalid reference/time provenance","messagePattern":"artifact (.+?) has invalid reference/time provenance","errorType":"validation","errorClass":"ContractError","httpStatus":null,"severity":"error","filePath":"skills/taste-application/scripts/tasteforge/contract.py","lineNumber":420,"sourceCode":"        if entry.get(\"bytes\") != path.stat().st_size:\n            raise ContractError(f\"artifact {relative} byte size does not match receipt\")\n        if entry.get(\"sha256\") != _sha256(path):\n            raise ContractError(f\"artifact {relative} SHA-256 does not match receipt\")\n        provenance = entry.get(\"provenance\")\n        if not isinstance(provenance, list) or not provenance:\n            raise ContractError(f\"artifact {relative} lacks exact reference/time provenance\")\n        for source in provenance:\n            if not isinstance(source.get(\"reference_path\"), str) or not source[\"reference_path\"]:\n                raise ContractError(f\"artifact {relative} has invalid reference path\")\n            digest = source.get(\"reference_sha256\")\n            if not isinstance(digest, str) or len(digest) != 64:\n                raise ContractError(f\"artifact {relative} has invalid reference SHA-256\")\n            if (source[\"reference_path\"], digest) not in known_sources:\n                raise ContractError(f\"artifact {relative} cites an unknown provenance source\")\n            times = source.get(\"reference_times\")\n            basis = source.get(\"time_basis\")\n            if not isinstance(times, list) or basis not in {\"media_seconds\", \"whole_file\"}:\n                raise ContractError(f\"artifact {relative} has invalid reference/time provenance\")\n            if basis == \"media_seconds\" and not times:\n                raise ContractError(f\"artifact {relative} lacks media reference times\")\n            if basis == \"whole_file\" and times:\n                raise ContractError(f\"artifact {relative} whole-file provenance must not invent times\")\n            if basis == \"media_seconds\":\n                expected_duration = source_durations.get((source[\"reference_path\"], digest))\n                if expected_duration is None or source.get(\"source_duration\") != expected_duration:\n                    raise ContractError(f\"artifact {relative} has an unbound source duration\")\n                for time in times:\n                    _validate_media_time(\n                        time, expected_duration,\n                        label=f\"artifact {relative} media reference time\",\n                    )\n\n    digest_payload = dict(receipt)\n    claimed_digest = digest_payload.pop(\"receipt_sha256\", None)\n    actual_digest = hashlib.sha256(\n        json.dumps(digest_payload, sort_keys=True, separators=(\",\", \":\")).encode(\"utf-8\")","sourceCodeStart":402,"sourceCodeEnd":438,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/skills/taste-application/scripts/tasteforge/contract.py#L402-L438","documentation":"Each provenance source must declare a 'time_basis' of exactly 'media_seconds' or 'whole_file', and 'reference_times' must be a list. This error is raised when times is not a list or the basis is missing/outside the allowed set. The validator uses this to know how the artifact's use of the reference is temporally bound.","triggerScenarios":"A provenance source with time_basis values like 'seconds', 'full', 'media', or null; reference_times set to null, a dict, or a string; omitting one of the two fields entirely.","commonSituations":"Hand-written receipts inventing their own basis names, schema migrations changing field names, generators emitting null for times when they meant [], and typos such as 'media_second'.","solutions":["Set time_basis to exactly 'media_seconds' (time-ranged usage) or 'whole_file' (full reference usage)","Change reference_times to a list (possibly empty for whole_file)","Regenerate the receipt via tasteforge to emit canonical field values","Check for typos — the accepted set is exactly {'media_seconds','whole_file'}"],"exampleFix":"# before\n{'reference_path': 'refs/a.mp4', 'time_basis': 'full', 'reference_times': None}\n# after\n{'reference_path': 'refs/a.mp4', 'time_basis': 'whole_file', 'reference_times': []}","handlingStrategy":"validation","validationCode":"VALID_BASES = {'media_seconds', 'whole_file'}\nfor src in entry['provenance']:\n    assert isinstance(src.get('reference_times'), list), 'reference_times must be a list'\n    assert src.get('time_basis') in VALID_BASES, f'bad time_basis: {src.get(\"time_basis\")!r}'","typeGuard":"def valid_time_provenance(src: dict) -> bool:\n    return (isinstance(src.get('reference_times'), list)\n            and src.get('time_basis') in {'media_seconds', 'whole_file'})","tryCatchPattern":"try:\n    validate_artifact_receipt(out_dir)\nexcept ContractError as e:\n    if 'invalid reference/time provenance' in str(e):\n        normalize_time_fields(receipt)\n    else:\n        raise","preventionTips":["Use only the two documented basis strings verbatim","Model provenance with a dataclass/TypedDict so invalid values cannot be constructed","Replace None with [] for reference_times at generation time","Diff receipts against a schema after migrations"],"tags":["provenance","validation","time-basis"],"backgroundTag":"invalid-enum-value","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"}