affaan-m/ECC · error · ContractError
genre has an incomplete signature
Error message
genre {spec.get('number')} has an incomplete signature What it means
Every genre spec must carry a signature: a dict containing all axes in _SIGNATURE_AXES. This ContractError fires when signature is missing, not a dict, or missing one or more required axis keys — the spec's style signature is incomplete and downstream style-matching cannot run.
Solutions
- Inspect _SIGNATURE_AXES in contract.py and add every required axis key to the spec's signature dict.
- If an axis is unknown, run the signature-extraction step for that spec instead of guessing values.
- Upgrade the bundle-generation script to the current schema so all axes are emitted.
- Print set(_SIGNATURE_AXES) - set(signature) before validating to see exactly which axes are missing.
Example fix
// before
spec["signature"] = {"palette": ["warm"], "rhythm": ["syncopated"]} # missing avoid axis
// after
spec["signature"] = {"palette": ["warm"], "rhythm": ["syncopated"], "avoid": ["harsh-brass"]} Defensive patterns
Strategy: validation
Validate before calling
from skills.taste_application.scripts.tasteforge.contract import _SIGNATURE_AXES
def signature_is_complete(spec):
sig = spec.get("signature")
return isinstance(sig, dict) and _SIGNATURE_AXES.issubset(sig) Type guard
def has_complete_signature(spec: dict, axes: set[str]) -> bool:
sig = spec.get("signature")
return isinstance(sig, dict) and axes.issubset(sig.keys()) Try / catch
try:
validate_genre_specs(specs)
except ContractError as e:
if "incomplete signature" in str(e):
for s in specs:
missing = _SIGNATURE_AXES - set(s.get("signature") or {})
print(f"spec {s.get('number')} missing axes: {missing}")
raise Prevention
- Import _SIGNATURE_AXES and validate signature completeness right after extraction.
- Re-run signature extraction when an axis is missing instead of hand-filling it.
- Version bundle schemas so older bundles missing new axes are detected and migrated.
- Never build signature dicts conditionally with partial axes.
When it happens
Trigger: Calling validate_genre_specs / validate_bundle with a spec lacking a signature key, signature set to a list/string instead of dict, or signature containing only some axes (e.g. only the positive axes but not the avoid axis).
Common situations: Older bundle format from before an axis was added, missing the new key; hand-written specs omitting the avoid axis; signature built conditionally so an empty analysis produced {}.
Understand the failure class
Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.
Related errors
- Canonical session snapshot requires session.sourceTarget to…
- Canonical session snapshot requires session to be an object
- Canonical session snapshot requires workers to be an array
- clip has no 'path
- clip has no 'path
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/515cc836d7b46a78.
Report an issue: GitHub.
Appendix: source
Thrown at skills/taste-application/scripts/tasteforge/contract.py:166
for group in groups:
if not isinstance(group, dict):
raise ContractError(f"genre {spec.get('number')} has invalid time evidence")
for time in group.get("times", []):
_validate_media_time(
time, group.get("source_duration"),
label=f"genre {spec.get('number')} time evidence",
)
temporal = measured.get("temporal", {})
if isinstance(temporal, dict):
for group in temporal.get("scene_change_evidence", []):
for time in group.get("times", []):
_validate_media_time(
time, group.get("source_duration"),
label=f"genre {spec.get('number')} scene evidence",
)
signature = spec.get("signature")
if not isinstance(signature, dict) or not _SIGNATURE_AXES.issubset(signature):
raise ContractError(f"genre {spec.get('number')} has an incomplete signature")
if not all(isinstance(signature[axis], list) for axis in _SIGNATURE_AXES):
raise ContractError(f"genre {spec.get('number')} signature axes must be lists")
if not all(signature[axis] for axis in _SIGNATURE_AXES):
raise ContractError(f"genre {spec.get('number')} has an empty signature axis, including avoid")
def validate_effect_recipe(
recipe: dict[str, Any], *, reference_durations: dict[str, float] | None = None
) -> None:
"""Require a seeded aperiodic schedule and anchors on subject-aware effects."""
if (recipe.get("dry_run") is not True
or type(recipe.get("provider_calls")) is not int
or recipe.get("provider_calls") != 0
or recipe.get("provider_execution") is not False):
raise ContractError("effect recipe crosses the dry-run provider boundary")
if not isinstance(recipe.get("seed"), int) or isinstance(recipe.get("seed"), bool):
raise ContractError("effect recipe must have an integer seed")
if recipe.get("rng_algorithm") != "python.random.Random/v1":View on GitHub (pinned to 8321021c54)