{"record":{"id":"9d09e1002beea58b","repo":"affaan-m/ECC","slug":"missing-artifact-binding","errorCode":null,"errorMessage":"Missing artifact binding","messagePattern":"Missing artifact binding","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"skills/taste-application/scripts/tasteforge/assets.py","lineNumber":129,"sourceCode":"        return None\n    if not isinstance(source, dict):\n        raise ValueError('external_result requires provider provenance and local evidence')\n    provider = _text(source.get('provider'), 'provider')\n    identifiers = {key: _text(source[key], key) for key in ('request_id', 'workflow_id')\n                   if key in source}\n    if not identifiers:\n        raise ValueError('Provider provenance requires request_id or workflow_id')\n    if verify:\n        evidence = _verify_binding(source.get('evidence'), base)\n    else:\n        evidence = _fingerprint(_path(source.get('evidence_path'), base))\n    return dict(provider=provider, **identifiers, evidence=evidence,\n                verification='supplied_local_evidence_only')\n\n\ndef _verify_binding(value: Any, base: Path, modality: str | None = None) -> dict[str, Any]:\n    if not isinstance(value, dict):\n        raise ValueError('Missing artifact binding')\n    actual = _fingerprint(_path(value.get('path'), base), modality)\n    if type(value.get('bytes')) is not int or any(value.get(k) != v for k, v in actual.items()):\n        raise ValueError(f'Artifact changed or binding invalid: {actual[\"path\"]}')\n    return actual\n\n\n_TASTE_FIELDS = ('genre_number', 'genre_slug', 'style_fingerprint', 'reference_sha256')\n\n\ndef _bundle(value: Any, base: Path, verify: bool) -> tuple[dict[str, Any], dict[tuple[str, str], Any]]:\n    from .contract import validate_bundle\n\n    if verify:\n        binding = _verify_binding(value, base)\n        root = Path(binding['path']).parent\n    else:\n        root = _path(value, base)\n        binding = _fingerprint(root / 'receipt.json')","sourceCodeStart":111,"sourceCodeEnd":147,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/skills/taste-application/scripts/tasteforge/assets.py#L111-L147","documentation":"Every provider_provenance must include an artifact binding: a dict with a 'path' plus expected fingerprint fields (bytes, etc.). The library throws this in _verify_binding when the binding value is missing or not a dict, because there is nothing to fingerprint-verify against.","triggerScenarios":"provider_provenance lacking the 'evidence' key while verify=true; evidence set to null/string; validate_assets checking an asset whose binding was dropped during manifest editing.","commonSituations":"Hand-written manifests forgetting the evidence block; tooling serializing evidence as a stringified path; deleting evidence entries to 'clean up' manifests.","solutions":["Add an 'evidence' dict under provider_provenance containing 'path' and the recorded fingerprint fields (bytes, hash values)","Regenerate the binding by re-fingerprinting the artifact with the library's fingerprint helper instead of hand-writing it","If evidence cannot be supplied, mark the provenance verification as supplied_local_evidence_only by using evidence_path instead of verify mode"],"exampleFix":"// before\n\"provider_provenance\": {\"provider\": \"acme\", \"request_id\": \"r1\"}\n// after\n\"provider_provenance\": {\"provider\": \"acme\", \"request_id\": \"r1\",\n  \"evidence\": {\"path\": \"artifacts/a1.png\", \"bytes\": 1024, \"sha256\": \"...\"}}","handlingStrategy":"validation","validationCode":"for a in assets:\n    p = a.get(\"provider_provenance\") or {}\n    ev = p.get(\"evidence\")\n    if a.get(\"origin\") == \"external_result\" and not (isinstance(ev, dict) and ev.get(\"path\")):\n        raise ValueError(f\"asset {a['id']}: missing artifact binding (evidence dict with path)\")","typeGuard":"def has_binding(p: dict | None) -> bool:\n    return isinstance(p, dict) and isinstance(p.get(\"evidence\"), dict) and bool(p[\"evidence\"].get(\"path\"))","tryCatchPattern":"try:\n    ingest_assets(assets)\nexcept ValueError as e:\n    if str(e) == \"Missing artifact binding\":\n        regenerate_bindings(assets); retry()\n    else:\n        raise","preventionTips":["Generate bindings with the library's fingerprint helper instead of hand-writing them","Keep evidence blocks adjacent to provenance in your manifest templates","Schema-validate that external_result assets always include an evidence object"],"tags":["provenance","binding","validation"],"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"}