{"record":{"id":"63a1ba45ea975a4a","repo":"affaan-m/ECC","slug":"missing-modality-manifests-sorted-missing","errorCode":null,"errorMessage":"missing modality manifests: {sorted(missing)}","messagePattern":"missing modality manifests: (.+?)","errorType":"validation","errorClass":"ContractError","httpStatus":null,"severity":"error","filePath":"skills/taste-application/scripts/tasteforge/contract.py","lineNumber":287,"sourceCode":"            if not isinstance(digest, str) or len(digest) != 64:\n                raise ContractError(f\"rule {rule.get('rule_id')} lacks immutable reference evidence\")\n            times = item.get(\"times\")\n            if not isinstance(times, list) or not times:\n                raise ContractError(f\"rule {rule.get('rule_id')} lacks time evidence\")\n            source_duration = item.get(\"source_duration\")\n            for time in times:\n                _validate_media_time(\n                    time, source_duration, label=f\"rule {rule.get('rule_id')} time evidence\"\n                )\n\n\ndef validate_manifests(manifests_dir: str | Path) -> None:\n    \"\"\"Require image, video, and 3D-asset dry-run request manifests.\"\"\"\n    manifests_dir = Path(manifests_dir)\n    found = {path.stem for path in manifests_dir.glob(\"*.json\")} if manifests_dir.is_dir() else set()\n    missing = _REQUIRED_MODALITIES - found\n    if missing:\n        raise ContractError(f\"missing modality manifests: {sorted(missing)}\")\n    for modality in _REQUIRED_MODALITIES:\n        payload = json.loads((manifests_dir / f\"{modality}.json\").read_text(encoding=\"utf-8\"))\n        if payload.get(\"modality\") != modality or not payload.get(\"requests\"):\n            raise ContractError(f\"invalid or empty {modality} manifest\")\n        if (payload.get(\"dry_run\") is not True or payload.get(\"submit\") is not False\n                or type(payload.get(\"provider_calls\")) is not int\n                or payload.get(\"provider_calls\") != 0\n                or payload.get(\"provider_execution\") is not False):\n            raise ContractError(f\"{modality} manifest crosses the dry-run boundary\")\n        for request in payload[\"requests\"]:\n            if (request.get(\"dry_run\") is not True\n                    or request.get(\"submit\") is not False\n                    or type(request.get(\"provider_calls\")) is not int\n                    or request.get(\"provider_calls\") != 0\n                    or request.get(\"provider_execution\") is not False\n                    or request.get(\"provider_call_mode\") != \"disabled\"):\n                raise ContractError(f\"{modality} request crosses the dry-run boundary\")\n","sourceCodeStart":269,"sourceCodeEnd":305,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/skills/taste-application/scripts/tasteforge/contract.py#L269-L305","documentation":"validate_manifests requires a JSON manifest for every required modality (image, video, 3D asset) in the manifests directory. If one or more <modality>.json files are absent, this ContractError lists the missing stems so the bundle cannot pass without complete dry-run manifests.","triggerScenarios":"Running validate_manifests('path/to/manifests') or validate_bundle() where the directory is missing entirely, is not a directory, or lacks one of image.json / video.json / 3d_asset.json (per _REQUIRED_MODALITIES).","commonSituations":"Forgetting to run the manifest-generation step before validation; manifests written to the wrong directory; a modality generator skipped due to an earlier failure; typo in a manifest filename (e.g. 'three_d.json'); empty manifests dir because generation was dry-run-skipped.","solutions":["Generate the missing <modality>.json manifest(s) into the manifests directory before validating.","Check the manifests_dir path passed to validate_manifests/validate_bundle points at the directory that actually contains the files.","Rename typo'd manifests to exactly match the required modality names (image.json, video.json, 3d_asset.json).","Rerun the full bundle build so all modality manifest generators execute, then validate."],"exampleFix":"// before\n# manifests dir contains only image.json, video.json\n// after\n# add manifests/3d_asset.json with {\"modality\": \"3d_asset\", \"requests\": [...], \"dry_run\": true, ...}","handlingStrategy":"validation","validationCode":"from pathlib import Path\nREQUIRED = {\"image\", \"video\", \"3d_asset\"}\ndef manifests_ready(d):\n    p = Path(d)\n    found = {f.stem for f in p.glob(\"*.json\")} if p.is_dir() else set()\n    missing = REQUIRED - found\n    if missing:\n        raise FileNotFoundError(f\"missing manifests: {sorted(missing)}\")","typeGuard":null,"tryCatchPattern":"try:\n    validate_manifests(manifests_dir)\nexcept ContractError as e:\n    if \"missing modality manifests\" in str(e):\n        generate_all_manifests(manifests_dir)  # rerun generation step\n        validate_manifests(manifests_dir)\n    else:\n        raise","preventionTips":["Run the manifest generation step as a hard prerequisite of the bundle build.","Use exact modality filenames (image.json, video.json, 3d_asset.json) — no renames or typos.","Check the manifests directory exists and is populated in CI before validation."],"tags":["manifest","missing-file","validation","dry-run"],"backgroundTag":"file-not-found","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"}