{"record":{"id":"9814ca69e1bb56a1","repo":"affaan-m/ECC","slug":"artifact-relative-byte-size-does-not-match-receipt","errorCode":null,"errorMessage":"artifact {relative} byte size does not match receipt","messagePattern":"artifact (.+?) byte size does not match receipt","errorType":"validation","errorClass":"ContractError","httpStatus":null,"severity":"error","filePath":"skills/taste-application/scripts/tasteforge/contract.py","lineNumber":403,"sourceCode":"\n    for entry in entries:\n        relative = entry.get(\"path\")\n        assert isinstance(relative, str)\n        path = (out_dir / relative).resolve()\n        try:\n            path.relative_to(out_dir)\n        except ValueError as error:\n            raise ContractError(f\"artifact path escapes output directory: {relative}\") from error\n        if entry.get(\"provider_execution\") is not False:\n            raise ContractError(f\"artifact {relative} permits provider execution\")\n        if not isinstance(entry.get(\"genre_numbers\"), list):\n            raise ContractError(f\"artifact {relative} lacks genre binding\")\n        modalities = entry.get(\"modalities\")\n        if (not isinstance(modalities, list)\n                or any(modality not in _REQUIRED_MODALITIES for modality in modalities)):\n            raise ContractError(f\"artifact {relative} has invalid modality binding\")\n        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:","sourceCodeStart":385,"sourceCodeEnd":421,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/skills/taste-application/scripts/tasteforge/contract.py#L385-L421","documentation":"The receipt records each artifact's byte size at generation time; validation compares the recorded 'bytes' field with the actual file size on disk (path.stat().st_size). This ContractError is raised when they differ, meaning the artifact content changed after the receipt was written.","triggerScenarios":"Calling validate_artifact_receipt()/validate_bundle() after an artifact file was edited, re-encoded, re-saved by an editor/tool, truncated during transfer, or regenerated without updating the receipt.","commonSituations":"An image re-saved by an editor or optimizer pipeline post-generation; text-mode transfer (FTP/zip) altering line endings and size; partial/corrupted copy; regenerated outputs paired with an old receipt.","solutions":["Regenerate the bundle and receipt together so recorded sizes match the files.","Restore the artifact files to their original bytes (git restore / re-download) matching the receipt.","Verify sizes with find out_dir -type f -printf '%s %p\\n' and compare against receipt 'bytes' to identify which files drifted."],"exampleFix":"# before (file edited after generation)\npython contract.py validate ./bundle  # byte size does not match receipt\n# after\ntasteforge generate ./bundle && python contract.py validate ./bundle","handlingStrategy":"try-catch","validationCode":"for e in receipt['artifacts']:\n    p = out_dir / e['path']\n    if p.is_file() and p.stat().st_size != e.get('bytes'):\n        raise SystemExit(f'size drift: {e[\"path\"]} — regenerate receipt')","typeGuard":"def size_matches(out_dir: Path, entry: dict) -> bool:\n    p = out_dir / entry.get('path', '')\n    return p.is_file() and p.stat().st_size == entry.get('bytes')","tryCatchPattern":"try:\n    validate_artifact_receipt(out_dir, entries)\nexcept ContractError as e:\n    if 'byte size does not match' in str(e):\n        regenerate_bundle(out_dir)  # artifacts drifted; rebuild receipt+outputs together\n    else:\n        raise","preventionTips":["Regenerate bundle and receipt in one atomic step after any output change.","Transfer bundles as archives in binary mode to avoid size/line-ending changes.","Exclude the output directory from editor autosave/optimizer pipelines.","Commit artifacts and receipt together in version control."],"tags":["integrity","receipt","file-size","validation"],"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"}