affaan-m/ECC · error · ContractError

stochastic schedule is periodic; repeating interval cycle

Error message

stochastic schedule is periodic; repeating interval cycle

What it means

ContractError raised when the sequence of intervals between consecutive event times repeats cyclically, even if not uniform. The periodicity check tries every candidate period p and rejects if intervals[i] == intervals[i % p] for all i. The contract forbids any repeating pattern so schedules remain genuinely stochastic.

Solutions

  1. Inject random jitter into each gap so no exact cycle repeats.
  2. Generate intervals from an i.i.d. random distribution instead of repeating a pattern.
  3. Extend the pattern with a long non-repeating tail, though true randomness is safer.
  4. Test your generator output against the same periodicity logic locally before running validate_bundle.

Example fix

// before
times = [0.0, 1.0, 3.0, 4.0, 6.0, 7.0]  # intervals 1,2,1,2,1 cycle
// after
import random
times, t = [0.0], 0.0
for _ in range(5):
    t += random.uniform(0.3, 2.5)
    times.append(round(t, 6))
Defensive patterns

Strategy: validation

Validate before calling

intervals = [round(b - a, 6) for a, b in zip(times, times[1:])]
for period in range(1, len(intervals) // 2 + 1):
    if all(iv == intervals[i % period] for i, iv in enumerate(intervals)):
        raise ValueError(f"interval cycle of period {period} detected")

Type guard

def has_repeating_interval_cycle(events) -> bool:
    times = [float(e["time"]) for e in events]
    iv = [round(b - a, 6) for a, b in zip(times, times[1:])]
    return any(all(x == iv[i % p] for i, x in enumerate(iv)) for p in range(1, len(iv) // 2 + 1))

Try / catch

try:
    validate_effect_recipe(recipe, reference_durations)
except ContractError as exc:
    if "repeating interval cycle" in str(exc):
        recipe["events"] = rejitter_times(recipe["events"])
    else:
        raise

Prevention

When it happens

Trigger: Calling validate_effect_recipe with intervals forming a repeating cycle, e.g. times yielding intervals [1.0, 2.0, 1.0, 2.0] (period 2), or [0.5, 1.0, 0.5, 1.0, 0.5, 1.0].

Common situations: Tiling a small hand-authored pattern of gaps across a longer timeline; generator code that repeats a template schedule; alternating on/off effect timings like [0,1,3,4,6,7] (intervals 1,2,1,2,...).

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/3a6826d7d147792b. Report an issue: GitHub.

Appendix: source

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

        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"}:
                raise ContractError(f"CV effect {event.get('effect')} has an invalid subject anchor")
            if anchor.get("lost_policy") != "disable_effect_until_track_recovers":
                raise ContractError(f"CV effect {event.get('effect')} must fail closed on anchor loss")

View on GitHub (pinned to 8321021c54)