affaan-m/ECC · error · ContractError

genre crosses the dry-run boundary

Error message

genre {spec.get('number')} crosses the dry-run boundary

What it means

Every genre spec must set dry_run to exactly True (identity check with `is not True`, not just truthy). This is a dry-run boundary: the validator refuses specs that have not explicitly opted into non-destructive measurement mode, so accidental live generation can never pass contract validation. Strings like "true" or 1 do not satisfy the check.

Solutions

  1. Set dry_run: true (a real boolean) on every genre spec in the bundle.
  2. Coerce loaded config values explicitly: spec["dry_run"] = spec.get("dry_run") is True or bool(...) with strict parsing.
  3. Check your config parser/loader for values arriving as strings or ints and normalize them at load time.
  4. Search the bundle for any specs missing the dry_run key and add it.

Example fix

// before
{"number": 3, "dry_run": "true", ...}
// after
{"number": 3, "dry_run": true, ...}
Defensive patterns

Strategy: validation

Validate before calling

def ensure_dry_run(specs):
    for s in specs:
        if s.get("dry_run") is not True:
            raise ValueError(f"spec {s.get('number')} must set dry_run: true (boolean)")

Type guard

def is_explicit_dry_run(spec: dict) -> bool:
    return spec.get("dry_run") is True

Try / catch

try:
    validate_genre_specs(specs)
except ContractError as e:
    if "crosses the dry-run boundary" in str(e):
        for s in specs:
            s["dry_run"] = (s.get("dry_run") is True)
    raise

Prevention

When it happens

Trigger: Passing a spec with dry_run missing, set to False, set to 1, or set to the string "true" into validate_genre_specs (directly or through validate_bundle).

Common situations: Hand-authored YAML/JSON configs where dry_run is written as "true" (a string); deserialized configs where JSON has no native bool and the value arrives as 1/0; templates that omit the field entirely; older bundle formats predating the dry-run requirement.

Understand the failure class

Background: "unknown output mode", "invalid value for flag", "expects true/false": fixing invalid flag value errors in CLI tools — this error's family across 24 libraries.

Related errors


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

Appendix: source

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

                    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):
                    raise ContractError(f"genre {spec.get('number')} has invalid time evidence")
                for group in groups:
                    if not isinstance(group, dict):
                        raise ContractError(f"genre {spec.get('number')} has invalid time evidence")

View on GitHub (pinned to 8321021c54)