{"record":{"id":"7279ccda7f6833b1","repo":"affaan-m/ECC","slug":"missing-resolve-effect-recipe","errorCode":null,"errorMessage":"missing Resolve effect recipe","messagePattern":"missing Resolve effect recipe","errorType":"validation","errorClass":"ContractError","httpStatus":null,"severity":"error","filePath":"skills/taste-application/scripts/tasteforge/contract.py","lineNumber":483,"sourceCode":"            or receipt.get(\"provider_calls\") != 0):\n        raise ContractError(\"receipt crosses the dry-run boundary\")\n    validate_artifact_receipt(out_dir, receipt)\n\n    reference_durations: dict[str, float] = {}\n    for reference in receipt.get(\"references\", []):\n        digest = reference.get(\"sha256\")\n        duration = reference.get(\"source_duration\")\n        if not isinstance(digest, str) or not _is_finite_real(duration):\n            raise ContractError(\"receipt reference cannot bind recipe evidence\")\n        duration = float(duration)\n        previous = reference_durations.get(digest)\n        if previous is not None and previous != duration:\n            raise ContractError(\"receipt reference digest has conflicting source durations\")\n        reference_durations[digest] = duration\n\n    recipe_path = out_dir / \"resolve\" / \"effect_recipe.json\"\n    if not recipe_path.is_file():\n        raise ContractError(\"missing Resolve effect recipe\")\n    validate_effect_recipe(\n        json.loads(recipe_path.read_text(encoding=\"utf-8\")),\n        reference_durations=reference_durations,\n    )\n","sourceCodeStart":465,"sourceCodeEnd":488,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/skills/taste-application/scripts/tasteforge/contract.py#L465-L488","documentation":"A complete bundle must include resolve/effect_recipe.json, the Resolve effect recipe that validate_bundle validates against the receipt's reference durations. If that file is missing from the out_dir, this ContractError is raised. Without the recipe, the receipt's evidence cannot be cross-checked, so the bundle is incomplete.","triggerScenarios":"Calling validate_bundle on an out_dir without out_dir/resolve/effect_recipe.json — e.g. a pipeline step that skipped recipe emission, a partially copied bundle, or validating a directory from a pre-recipe generator version.","commonSituations":"Copying bundles without the resolve/ subdirectory, older pipeline outputs predating the recipe step, or custom generators that never write effect_recipe.json.","solutions":["Re-run the full tasteforge pipeline so resolve/effect_recipe.json is generated","Copy the complete bundle including the resolve/ subdirectory","Point validate_bundle at the correct bundle root that contains resolve/effect_recipe.json","If writing a custom generator, emit the effect recipe into out_dir/resolve/ before validation"],"exampleFix":"# before\nvalidate_bundle(out_dir / \"manifests\")  # no resolve/ subdir here\n# after\nassert (out_dir / \"resolve\" / \"effect_recipe.json\").is_file()\nvalidate_bundle(out_dir)","handlingStrategy":"validation","validationCode":"from pathlib import Path\ndef ensure_recipe(out_dir: Path) -> None:\n    p = out_dir / \"resolve\" / \"effect_recipe.json\"\n    if not p.is_file():\n        raise FileNotFoundError(f\"missing {p}; re-run the full pipeline\")","typeGuard":"def has_effect_recipe(out_dir) -> bool:\n    return (out_dir / \"resolve\" / \"effect_recipe.json\").is_file()","tryCatchPattern":"from tasteforge.contract import ContractError\ntry:\n    validate_bundle(out_dir)\nexcept ContractError as e:\n    if \"missing Resolve effect recipe\" in str(e):\n        regenerate_bundle(out_dir)","preventionTips":["Copy entire bundles including the resolve/ subdirectory","Verify all expected bundle artifacts (provenance, receipt, recipe, manifests, genres) exist before validation","Update custom generators to emit the effect recipe"],"tags":["contract","file-not-found","bundle","recipe"],"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"}