affaan-m/ECC · error · ContractError

stochastic schedule is periodic; intervals must vary

Error message

stochastic schedule is periodic; intervals must vary

What it means

ContractError raised when all intervals between consecutive effect event times are identical (or there is effectively one distinct interval, e.g. a single interval). The tasteforge contract enforces that stochastic schedules are not periodic; a schedule with uniform spacing is considered periodic and rejected. This guarantees empirically varied event spacing in generated media.

Solutions

  1. Generate event times with jitter, e.g. add random noise to each time before validation.
  2. Use a non-uniform distribution (Poisson process, exponential inter-arrival times) for event times.
  3. Ensure at least two distinct intervals exist (>=3 events with differing gaps).
  4. Increase rounding precision awareness: intervals are rounded to 6 decimals; near-identical intervals are treated as equal.

Example fix

// before
times = [i * 1.0 for i in range(5)]  # all intervals 1.0
// after
import random
times = [0.0]
for _ in range(4):
    times.append(round(times[-1] + random.uniform(0.4, 1.8), 6))  # intervals vary
Defensive patterns

Strategy: validation

Validate before calling

intervals = [round(b - a, 6) for a, b in zip(times, times[1:])]
if len(set(intervals)) <= 1:
    raise ValueError("schedule intervals must vary; add jitter or >= 3 distinct gaps")

Type guard

def intervals_vary(events) -> bool:
    times = [float(e["time"]) for e in events]
    intervals = [round(b - a, 6) for a, b in zip(times, times[1:])]
    return len(set(intervals)) > 1

Try / catch

try:
    validate_effect_recipe(recipe, reference_durations)
except ContractError as exc:
    if "intervals must vary" in str(exc):
        recipe["events"] = add_jitter(recipe["events"])
        validate_effect_recipe(recipe, reference_durations)
    else:
        raise

Prevention

When it happens

Trigger: Calling validate_effect_recipe with events spaced at a constant delta (e.g. times [0, 1, 2, 3] -> all intervals 1.0), or a recipe with exactly two events yielding one interval (set of intervals has size 1).

Common situations: Using numpy.linspace or a fixed-tick generator to build event times; authoring a simple 'every N seconds' schedule by hand; test fixtures with evenly spaced events copied from an older contract version.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

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

        if float(start) + float(duration) > float(timeline) + 1e-9:
            raise ContractError("effect event end exceeds the declared timeline")
        evidence = event.get("evidence")
        if not isinstance(evidence, dict):
            raise ContractError(f"effect {event.get('effect')} lacks reference evidence")
        _validate_media_time(
            evidence.get("time"), evidence.get("source_duration"), label="effect evidence time"
        )
        if reference_durations is not None:
            digest = evidence.get("reference_sha256")
            expected_duration = reference_durations.get(digest) if isinstance(digest, str) else None
            if expected_duration is None or evidence.get("source_duration") != expected_duration:
                raise ContractError("effect evidence source duration is not bound to its receipt reference")
    times = [float(event["time"]) for event in events]
    if times != sorted(times) or len(times) != len(set(times)):
        raise ContractError("effect event times must be unique and increasing")
    intervals = [round(b - a, 6) for a, b in zip(times, times[1:])]  # noqa: RUF007
    if len(set(intervals)) <= 1:
        raise ContractError("stochastic schedule is periodic; intervals must vary")
    for period in range(1, len(intervals) // 2 + 1):
        if all(intervals[index] == intervals[index % period] for index in range(len(intervals))):
            raise ContractError("stochastic schedule is periodic; repeating interval cycle")
    if recipe.get("periodic") is not False:
        raise ContractError("effect recipe must explicitly declare periodic=false")
    for event in events:
        cv_effect = str(event.get("effect", "")).startswith("cv_")
        if cv_effect and event.get("requires_subject_anchor") is not True:
            raise ContractError(f"CV effect {event.get('effect')} must require a subject anchor")
        if event.get("requires_subject_anchor"):
            anchor = event.get("subject_anchor")
            required = {
                "mode", "target", "source_ref_sha256", "evidence_time",
                "source_duration", "lost_policy",
            }
            if not isinstance(anchor, dict) or not required.issubset(anchor):
                raise ContractError(f"CV effect {event.get('effect')} lacks a valid subject anchor")
            if anchor.get("mode") not in {"object_track", "point_track", "segmentation_track"}:

View on GitHub (pinned to 8321021c54)