affaan-m/ECC · error · ContractError

missing Resolve effect recipe

Error message

missing Resolve effect recipe

What it means

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.

Solutions

  1. Re-run the full tasteforge pipeline so resolve/effect_recipe.json is generated
  2. Copy the complete bundle including the resolve/ subdirectory
  3. Point validate_bundle at the correct bundle root that contains resolve/effect_recipe.json
  4. If writing a custom generator, emit the effect recipe into out_dir/resolve/ before validation

Example fix

# before
validate_bundle(out_dir / "manifests")  # no resolve/ subdir here
# after
assert (out_dir / "resolve" / "effect_recipe.json").is_file()
validate_bundle(out_dir)
Defensive patterns

Strategy: validation

Validate before calling

from pathlib import Path
def ensure_recipe(out_dir: Path) -> None:
    p = out_dir / "resolve" / "effect_recipe.json"
    if not p.is_file():
        raise FileNotFoundError(f"missing {p}; re-run the full pipeline")

Type guard

def has_effect_recipe(out_dir) -> bool:
    return (out_dir / "resolve" / "effect_recipe.json").is_file()

Try / catch

from tasteforge.contract import ContractError
try:
    validate_bundle(out_dir)
except ContractError as e:
    if "missing Resolve effect recipe" in str(e):
        regenerate_bundle(out_dir)

Prevention

When it happens

Trigger: 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.

Common situations: Copying bundles without the resolve/ subdirectory, older pipeline outputs predating the recipe step, or custom generators that never write effect_recipe.json.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16). Data as JSON: /api/errors/7279ccda7f6833b1. Report an issue: GitHub.

Appendix: source

Thrown at skills/taste-application/scripts/tasteforge/contract.py:483

            or receipt.get("provider_calls") != 0):
        raise ContractError("receipt crosses the dry-run boundary")
    validate_artifact_receipt(out_dir, receipt)

    reference_durations: dict[str, float] = {}
    for reference in receipt.get("references", []):
        digest = reference.get("sha256")
        duration = reference.get("source_duration")
        if not isinstance(digest, str) or not _is_finite_real(duration):
            raise ContractError("receipt reference cannot bind recipe evidence")
        duration = float(duration)
        previous = reference_durations.get(digest)
        if previous is not None and previous != duration:
            raise ContractError("receipt reference digest has conflicting source durations")
        reference_durations[digest] = duration

    recipe_path = out_dir / "resolve" / "effect_recipe.json"
    if not recipe_path.is_file():
        raise ContractError("missing Resolve effect recipe")
    validate_effect_recipe(
        json.loads(recipe_path.read_text(encoding="utf-8")),
        reference_durations=reference_durations,
    )

View on GitHub (pinned to 8321021c54)