{"record":{"id":"11c53530f77ea889","repo":"affaan-m/ECC","slug":"effect-recipe-must-have-an-integer-seed","errorCode":null,"errorMessage":"effect recipe must have an integer seed","messagePattern":"effect recipe must have an integer seed","errorType":"validation","errorClass":"ContractError","httpStatus":null,"severity":"error","filePath":"skills/taste-application/scripts/tasteforge/contract.py","lineNumber":183,"sourceCode":"        if not isinstance(signature, dict) or not _SIGNATURE_AXES.issubset(signature):\n            raise ContractError(f\"genre {spec.get('number')} has an incomplete signature\")\n        if not all(isinstance(signature[axis], list) for axis in _SIGNATURE_AXES):\n            raise ContractError(f\"genre {spec.get('number')} signature axes must be lists\")\n        if not all(signature[axis] for axis in _SIGNATURE_AXES):\n            raise ContractError(f\"genre {spec.get('number')} has an empty signature axis, including avoid\")\n\n\ndef validate_effect_recipe(\n    recipe: dict[str, Any], *, reference_durations: dict[str, float] | None = None\n) -> None:\n    \"\"\"Require a seeded aperiodic schedule and anchors on subject-aware effects.\"\"\"\n    if (recipe.get(\"dry_run\") is not True\n            or type(recipe.get(\"provider_calls\")) is not int\n            or recipe.get(\"provider_calls\") != 0\n            or recipe.get(\"provider_execution\") is not False):\n        raise ContractError(\"effect recipe crosses the dry-run provider boundary\")\n    if not isinstance(recipe.get(\"seed\"), int) or isinstance(recipe.get(\"seed\"), bool):\n        raise ContractError(\"effect recipe must have an integer seed\")\n    if recipe.get(\"rng_algorithm\") != \"python.random.Random/v1\":\n        raise ContractError(\"effect recipe must declare its seeded RNG algorithm\")\n    events = recipe.get(\"events\")\n    if not isinstance(events, list) or len(events) < 3:\n        raise ContractError(\"effect recipe needs at least three scheduled events\")\n    timeline = recipe.get(\"timeline_duration\")\n    if not _is_finite_real(timeline):\n        raise ContractError(\"effect recipe must declare a finite positive timeline duration\")\n    timeline = cast(float, timeline)\n    if float(timeline) <= 0:\n        raise ContractError(\"effect recipe must declare a finite positive timeline duration\")\n    for event in events:\n        start = event.get(\"time\")\n        duration = event.get(\"duration\")\n        if (not _is_finite_real(start) or not _is_finite_real(duration)\n                or float(start) < 0 or float(duration) <= 0):\n            raise ContractError(\"effect event start and duration must be finite positive timeline values\")\n        start = cast(float, start)","sourceCodeStart":165,"sourceCodeEnd":201,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/skills/taste-application/scripts/tasteforge/contract.py#L165-L201","documentation":"Every effect recipe must carry an integer seed so its aperiodic schedule is reproducible. The check isinstance(seed, int) and not isinstance(seed, bool) rejects missing, non-int, and bool seeds (bool is a subclass of int in Python, so it is explicitly excluded).","triggerScenarios":"validate_effect_recipe called with a recipe whose 'seed' key is absent, is a float/str/None, or is True/False.","commonSituations":"Loading recipes from JSON where the seed was serialized as a string; passing a numpy integer or float like 42.0; accidentally setting seed=True; a generator that leaves seed unset when the user declines randomization.","solutions":["Set recipe['seed'] to a plain Python int, e.g. recipe['seed'] = 42.","Convert numeric input with int(seed) after verifying it is integral.","Reject or coerce bools explicitly before validation (bool(seed) is not acceptable)."],"exampleFix":"# before\nrecipe[\"seed\"] = \"42\"\n# after\nrecipe[\"seed\"] = int(\"42\")","handlingStrategy":"validation","validationCode":"seed = recipe.get(\"seed\")\nif not isinstance(seed, int) or isinstance(seed, bool):\n    raise ValueError(\"recipe seed must be a non-bool int\")","typeGuard":"def has_int_seed(recipe: dict) -> bool:\n    seed = recipe.get(\"seed\")\n    return isinstance(seed, int) and not isinstance(seed, bool)","tryCatchPattern":"try:\n    validate_effect_recipe(recipe)\nexcept ContractError as exc:\n    if \"integer seed\" in str(exc):\n        recipe = {**recipe, \"seed\": int(recipe.get(\"seed\") or 0)}\n        validate_effect_recipe(recipe)\n    else:\n        raise","preventionTips":["Serialize seeds as JSON numbers, never strings or booleans.","Reject True/False as seeds in your own config loaders (bool is an int subclass).","Generate seeds with random.randrange(2**32) to guarantee an int."],"tags":["validation","seed","type-safety"],"backgroundTag":"invalid-argument-value","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"}