affaan-m/ECC · error · ContractError

genre references collapsed into a generic style; distinct…

Error message

genre references collapsed into a generic style; distinct specs required

What it means

validate_genre_specs enforces that every genre spec in a bundle carries a genuinely distinct style reference. It collects each spec's style_fingerprint and computed _semantic_signature and raises this ContractError when two or more specs share the same fingerprint or semantic signature, meaning the genre references have collapsed into one generic style. The library throws this to prevent bundles that silently reference the same aesthetic under multiple genre numbers.

Solutions

  1. Give each spec a unique style_fingerprint that genuinely reflects its source material.
  2. If two specs are truly the same style, merge them into one genre spec instead of duplicating.
  3. Check any code that builds specs for shared/copied dicts (e.g. dict(spec) shallow copies reusing the same nested style data) and vary the style inputs.
  4. Log the fingerprints/signatures per spec before validating to find which specs collide.

Example fix

// before
specs = [
    {"number": 1, "style_fingerprint": "abc123", ...},
    {"number": 2, "style_fingerprint": "abc123", ...},
]
// after
specs = [
    {"number": 1, "style_fingerprint": "fingerprint-jazz-abc123", ...},
    {"number": 2, "style_fingerprint": "fingerprint-lofi-def456", ...},
]
Defensive patterns

Strategy: validation

Validate before calling

def specs_are_distinct(specs):
    fps = [s.get("style_fingerprint") for s in specs]
    if len(fps) != len(set(fps)):
        return False
    sigs = [repr(sorted(s.get("signature", {}).items())) for s in specs]
    return len(sigs) == len(set(sigs))

Type guard

def is_unique_fingerprints(specs: list[dict]) -> bool:
    fps = [s.get("style_fingerprint") for s in specs]
    return len(fps) == len(set(fps))

Try / catch

try:
    validate_genre_specs(specs)
except ContractError as e:
    if "collapsed into a generic style" in str(e):
        for s in specs:
            print(s.get("number"), s.get("style_fingerprint"))
    raise

Prevention

When it happens

Trigger: Calling validate_genre_specs (directly or via validate_bundle) with a list of specs where at least two specs have identical style_fingerprint values, or whose _semantic_signature hashes are equal (e.g. duplicated spec dicts, copy-pasted specs, or signatures collapsed to identical defaults).

Common situations: Copy-pasting a spec and only changing its genre number but not the style fingerprint; programmatically generating specs from a template without varying the fingerprint; a preprocessing step that normalizes/strips style fields so all specs hash the same; tests like test_collapsing_references_into_one_generic_style_is_rejected exercise exactly this rejection.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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

Appendix: source

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

                    raise ContractError(f"output bundle contains a symlink: {entry.path}")
                if entry.is_dir(follow_symlinks=False):
                    pending.append(Path(entry.path))
                elif not entry.is_file(follow_symlinks=False):
                    raise ContractError(f"output bundle contains a special file: {entry.path}")


def validate_genre_specs(specs: list[dict[str, Any]]) -> None:
    """Require complete, semantically distinct numbered genre specs."""
    if not specs:
        raise ContractError("at least one genre spec is required")
    numbers = [spec.get("number") for spec in specs]
    if len(numbers) != len(set(numbers)):
        raise ContractError("genre numbers must be distinct")

    fingerprints = [spec.get("style_fingerprint") for spec in specs]
    signatures = [_semantic_signature(spec) for spec in specs]
    if len(fingerprints) != len(set(fingerprints)) or len(signatures) != len(set(signatures)):
        raise ContractError("genre references collapsed into a generic style; distinct specs required")

    for spec in specs:
        if spec.get("dry_run") is not True:
            raise ContractError(f"genre {spec.get('number')} crosses the dry-run boundary")
        measured = spec.get("measured_features")
        if measured is not None:
            if not isinstance(measured, dict):
                raise ContractError(f"genre {spec.get('number')} has invalid measured evidence")
            _validate_numeric_evidence(measured, label=f"genre {spec.get('number')} evidence")
            total_duration = measured.get("total_duration")
            if not _is_finite_real(total_duration):
                raise ContractError(f"genre {spec.get('number')} has invalid total duration")
            total_duration = cast(float, total_duration)
            if float(total_duration) <= 0:
                raise ContractError(f"genre {spec.get('number')} has invalid total duration")
            for group_name in ("sample_times",):
                groups = measured.get(group_name, [])
                if not isinstance(groups, list):

View on GitHub (pinned to 8321021c54)