{"record":{"id":"5401728e741cc8f1","repo":"affaan-m/ECC","slug":"unsupported-asset-receipt-schema","errorCode":null,"errorMessage":"Unsupported asset receipt schema","messagePattern":"Unsupported asset receipt schema","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"skills/taste-application/scripts/tasteforge/assets.py","lineNumber":223,"sourceCode":"        receipt['bundle_receipt'] = binding\n    if 'genre_spec' in config:\n        receipt['genre_spec'] = _fingerprint(_path(config['genre_spec'], base))\n    # All inputs already exist, so the output-exists gate also prevents collisions.\n    try:\n        with output.open('x', encoding='utf-8') as stream:\n            json.dump(receipt, stream, indent=2, sort_keys=True)\n            stream.write('\\n')\n    except OSError as exc:\n        raise ValueError(f'Cannot create exclusive receipt: {output}') from exc\n    return receipt\n\n\ndef validate_assets(receipt_path: str | Path) -> dict[str, Any]:\n    \"\"\"Re-hash every bound file and validate receipt semantics; no remote calls.\"\"\"\n    path = _path(receipt_path, Path.cwd())\n    receipt = _load(path)\n    if receipt.get('schema') != SCHEMA:\n        raise ValueError('Unsupported asset receipt schema')\n    if type(receipt.get('provider_calls')) is not int or receipt['provider_calls'] != 0:\n        raise ValueError('Local ingestion must have zero provider calls')\n    if receipt.get('provider_execution') is not False:\n        raise ValueError('Local ingestion cannot claim provider execution')\n    _, requests = (_bundle(receipt['bundle_receipt'], path.parent, True)\n                   if 'bundle_receipt' in receipt else (None, {}))\n    for asset in _assets(receipt.get('assets')):\n        _taste(asset, requests, True)\n        _verify_binding(asset, path.parent, asset['modality'])\n        provenance = _provenance(asset, path.parent, True)\n        if provenance is not None and provenance != asset['provider_provenance']:\n            raise ValueError('Invalid supplied provenance declaration')\n    inputs = receipt.get('input_artifacts')\n    if not isinstance(inputs, list):\n        raise ValueError('input_artifacts must be a list')\n    for artifact in inputs:\n        _verify_binding(artifact, path.parent)\n    if 'genre_spec' in receipt:","sourceCodeStart":205,"sourceCodeEnd":241,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/skills/taste-application/scripts/tasteforge/assets.py#L205-L241","documentation":"validate_assets checks that the receipt's 'schema' field equals the supported schema constant 'tasteforge.assets.v1'. Any other or missing schema value is rejected, since validation semantics (required fields, hashing rules) are version-specific. This guards against validating foreign or newer-format receipts.","triggerScenarios":"Calling validate_assets on a JSON file that is not a tasteforge asset receipt (missing 'schema'); a receipt produced by a different tool or a newer/older tasteforge schema version; hand-built receipts with a wrong schema string; passing a bundle receipt.json (different schema) to validate_assets.","commonSituations":"Pointing validate_assets at the bundle's receipt.json instead of the asset receipt; upgrading tasteforge so old receipts have a previous schema id; copying an arbitrary JSON file as receipt.","solutions":["Pass the asset receipt produced by ingest_assets (schema 'tasteforge.assets.v1'), not a bundle receipt or arbitrary JSON.","Check receipt['schema'] before calling validate_assets.","If receipts are from an older tasteforge schema, re-ingest with the current version to produce a v1 receipt; there is no migration path in this code.","Fix typos if the schema string was hand-crafted."],"exampleFix":"# before\nvalidate_assets('bundle/receipt.json')  # bundle schema, not assets schema\n# after\nvalidate_assets('out/assets-receipt.json')  # produced by ingest_assets","handlingStrategy":"type-guard","validationCode":"import json\nreceipt = json.loads(open(p).read())\nassert receipt.get('schema') == 'tasteforge.assets.v1', 'not a tasteforge asset receipt'","typeGuard":"def is_asset_receipt(obj) -> bool:\n    return isinstance(obj, dict) and obj.get('schema') == 'tasteforge.assets.v1'","tryCatchPattern":null,"preventionTips":["Only validate receipts produced by ingest_assets.","Distinguish bundle receipts from asset receipts in your pipeline layout.","Track schema versions when upgrading the tool and re-ingest old receipts."],"tags":["validation","schema","versioning","receipt"],"backgroundTag":"schema-validation-failed","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"}