{"record":{"id":"a665271f1bcec4b3","repo":"affaan-m/ECC","slug":"external-result-requires-provider-provenance-and-local","errorCode":null,"errorMessage":"external_result requires provider provenance and local evidence","messagePattern":"external_result requires provider provenance and local evidence","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"skills/taste-application/scripts/tasteforge/assets.py","lineNumber":113,"sourceCode":"        asset_id = _text(asset.get('id'), 'asset id')\n        if asset_id in ids:\n            raise ValueError(f'Duplicate asset id: {asset_id}')\n        ids.add(asset_id)\n        if asset.get('modality') not in tuple(MODALITIES):\n            raise ValueError('modality must be image, video or 3d_asset')\n        if asset.get('origin') not in tuple(ORIGINS):\n            raise ValueError('Invalid asset origin')\n    return value\n\n\ndef _provenance(asset: dict[str, Any], base: Path, verify: bool) -> dict[str, Any] | None:\n    source = asset.get('provider_provenance')\n    if asset['origin'] != 'external_result':\n        if source is not None:\n            raise ValueError('Provider provenance requires external_result origin')\n        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()):","sourceCodeStart":95,"sourceCodeEnd":131,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/skills/taste-application/scripts/tasteforge/assets.py#L95-L131","documentation":"An asset with origin 'external_result' MUST carry a dict-shaped 'provider_provenance'. The library throws this when provider_provenance is missing or not a dict, because external-origin assets are untrusted without documented provider evidence.","triggerScenarios":"An asset with origin set to 'external_result' but no 'provider_provenance' key, or provider_provenance set to a string/list/None instead of a dict, passed to ingest_assets or validate_assets.","commonSituations":"Manually adding external assets without filling in provenance; a tool emitting provenance as a JSON string rather than an object; truncating provenance during serialization.","solutions":["Add a provider_provenance dict with at least a 'provider' string plus request_id or workflow_id","If the value is a JSON string, parse it into an object before ingestion","Change origin to an internal value if the asset was not actually produced externally (then remove the provenance requirement path)"],"exampleFix":"// before\n{\"id\": \"a1\", \"origin\": \"external_result\", \"modality\": \"image\"}\n// after\n{\"id\": \"a1\", \"origin\": \"external_result\", \"modality\": \"image\",\n \"provider_provenance\": {\"provider\": \"acme\", \"request_id\": \"req-123\", \"evidence_path\": \"artifacts/a1.png\"}}","handlingStrategy":"validation","validationCode":"for a in assets:\n    if a.get(\"origin\") == \"external_result\" and not isinstance(a.get(\"provider_provenance\"), dict):\n        raise ValueError(f\"asset {a['id']}: external_result needs a provider_provenance object\")","typeGuard":"def has_provenance_dict(a: dict) -> bool:\n    p = a.get(\"provider_provenance\")\n    return a.get(\"origin\") != \"external_result\" or isinstance(p, dict)","tryCatchPattern":"try:\n    ingest_assets(assets)\nexcept ValueError as e:\n    if \"external_result requires provider provenance\" in str(e):\n        raise ManifestError(\"fill provider_provenance for all external_result assets\") from e\n    raise","preventionTips":["Never set origin='external_result' by hand without also filling provenance","Serialize provenance as an object, never a JSON string","Validate manifests with a schema requiring provenance for external_result"],"tags":["validation","provenance","external-origin"],"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"}