{"record":{"id":"ec595965aa6367ce","repo":"affaan-m/ECC","slug":"genre-spec-get-number-has-an-empty-signature-axis-including","errorCode":null,"errorMessage":"genre {spec.get('number')} has an empty signature axis, including avoid","messagePattern":"genre (.+?) has an empty signature axis, including avoid","errorType":"validation","errorClass":"ContractError","httpStatus":null,"severity":"error","filePath":"skills/taste-application/scripts/tasteforge/contract.py","lineNumber":170,"sourceCode":"                        _validate_media_time(\n                            time, group.get(\"source_duration\"),\n                            label=f\"genre {spec.get('number')} time evidence\",\n                        )\n            temporal = measured.get(\"temporal\", {})\n            if isinstance(temporal, dict):\n                for group in temporal.get(\"scene_change_evidence\", []):\n                    for time in group.get(\"times\", []):\n                        _validate_media_time(\n                            time, group.get(\"source_duration\"),\n                            label=f\"genre {spec.get('number')} scene evidence\",\n                        )\n        signature = spec.get(\"signature\")\n        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\")","sourceCodeStart":152,"sourceCodeEnd":188,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/skills/taste-application/scripts/tasteforge/contract.py#L152-L188","documentation":"Every signature axis must be a non-empty list — including the avoid axis, as the message states. validate_genre_specs raises this ContractError when any signature[axis] is an empty list, because an empty axis means the style signature carries no information (or no explicit avoidances) and cannot discriminate this genre from others.","triggerScenarios":"Calling validate_genre_specs / validate_bundle with any signature axis set to [], e.g. {\"palette\": [], \"rhythm\": [...], \"avoid\": []}.","commonSituations":"A signature-extraction run that matched zero descriptors for an axis and wrote the empty list; the mistaken belief that an empty avoid list means 'avoid nothing' — the contract requires explicit avoid entries; filtering logic that stripped all descriptors of one axis.","solutions":["Populate every axis with at least one descriptor from the signature analysis.","Add explicit avoid descriptors to the avoid axis (e.g. [\"harsh-distortion\"]) rather than leaving it empty.","Re-run the signature extraction for the spec if the analysis produced no matches.","Pre-check before validating: all(len(signature[axis]) > 0 for axis in axes)."],"exampleFix":"// before\nspec[\"signature\"] = {\"palette\": [\"warm\"], \"avoid\": []}\n// after\nspec[\"signature\"] = {\"palette\": [\"warm\"], \"avoid\": [\"harsh-distortion\"]}","handlingStrategy":"validation","validationCode":"def axes_are_nonempty(spec, axes):\n    sig = spec.get(\"signature\") or {}\n    return all(isinstance(sig.get(a), list) and sig[a] for a in axes)","typeGuard":"def is_nonempty_axis(value) -> bool:\n    return isinstance(value, list) and len(value) > 0","tryCatchPattern":"try:\n    validate_genre_specs(specs)\nexcept ContractError as e:\n    if \"empty signature axis\" in str(e):\n        sig = spec[\"signature\"]\n        for a, v in sig.items():\n            if not v:\n                raise ValueError(f\"spec {spec.get('number')}: axis '{a}' is empty; re-run signature extraction\")\n    raise","preventionTips":["Re-run signature extraction when an axis matches zero descriptors.","Always author at least one explicit avoid entry — empty avoid lists are rejected.","Check filtering logic for stripping all descriptors from an axis.","Pre-validate with all(len(sig[a]) > 0 for a in axes) before bundle validation."],"tags":["validation","empty-list","signature"],"backgroundTag":"empty-required-field","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"}