{"record":{"id":"9d2f347f247bfc6b","repo":"affaan-m/ECC","slug":"stochastic-schedule-is-periodic-intervals-must-vary","errorCode":null,"errorMessage":"stochastic schedule is periodic; intervals must vary","messagePattern":"stochastic schedule is periodic; intervals must vary","errorType":"validation","errorClass":"ContractError","httpStatus":null,"severity":"error","filePath":"skills/taste-application/scripts/tasteforge/contract.py","lineNumber":221,"sourceCode":"        if float(start) + float(duration) > float(timeline) + 1e-9:\n            raise ContractError(\"effect event end exceeds the declared timeline\")\n        evidence = event.get(\"evidence\")\n        if not isinstance(evidence, dict):\n            raise ContractError(f\"effect {event.get('effect')} lacks reference evidence\")\n        _validate_media_time(\n            evidence.get(\"time\"), evidence.get(\"source_duration\"), label=\"effect evidence time\"\n        )\n        if reference_durations is not None:\n            digest = evidence.get(\"reference_sha256\")\n            expected_duration = reference_durations.get(digest) if isinstance(digest, str) else None\n            if expected_duration is None or evidence.get(\"source_duration\") != expected_duration:\n                raise ContractError(\"effect evidence source duration is not bound to its receipt reference\")\n    times = [float(event[\"time\"]) for event in events]\n    if times != sorted(times) or len(times) != len(set(times)):\n        raise ContractError(\"effect event times must be unique and increasing\")\n    intervals = [round(b - a, 6) for a, b in zip(times, times[1:])]  # noqa: RUF007\n    if len(set(intervals)) <= 1:\n        raise ContractError(\"stochastic schedule is periodic; intervals must vary\")\n    for period in range(1, len(intervals) // 2 + 1):\n        if all(intervals[index] == intervals[index % period] for index in range(len(intervals))):\n            raise ContractError(\"stochastic schedule is periodic; repeating interval cycle\")\n    if recipe.get(\"periodic\") is not False:\n        raise ContractError(\"effect recipe must explicitly declare periodic=false\")\n    for event in events:\n        cv_effect = str(event.get(\"effect\", \"\")).startswith(\"cv_\")\n        if cv_effect and event.get(\"requires_subject_anchor\") is not True:\n            raise ContractError(f\"CV effect {event.get('effect')} must require a subject anchor\")\n        if event.get(\"requires_subject_anchor\"):\n            anchor = event.get(\"subject_anchor\")\n            required = {\n                \"mode\", \"target\", \"source_ref_sha256\", \"evidence_time\",\n                \"source_duration\", \"lost_policy\",\n            }\n            if not isinstance(anchor, dict) or not required.issubset(anchor):\n                raise ContractError(f\"CV effect {event.get('effect')} lacks a valid subject anchor\")\n            if anchor.get(\"mode\") not in {\"object_track\", \"point_track\", \"segmentation_track\"}:","sourceCodeStart":203,"sourceCodeEnd":239,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/skills/taste-application/scripts/tasteforge/contract.py#L203-L239","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Generate event times with jitter, e.g. add random noise to each time before validation.","Use a non-uniform distribution (Poisson process, exponential inter-arrival times) for event times.","Ensure at least two distinct intervals exist (>=3 events with differing gaps).","Increase rounding precision awareness: intervals are rounded to 6 decimals; near-identical intervals are treated as equal."],"exampleFix":"// before\ntimes = [i * 1.0 for i in range(5)]  # all intervals 1.0\n// after\nimport random\ntimes = [0.0]\nfor _ in range(4):\n    times.append(round(times[-1] + random.uniform(0.4, 1.8), 6))  # intervals vary","handlingStrategy":"validation","validationCode":"intervals = [round(b - a, 6) for a, b in zip(times, times[1:])]\nif len(set(intervals)) <= 1:\n    raise ValueError(\"schedule intervals must vary; add jitter or >= 3 distinct gaps\")","typeGuard":"def intervals_vary(events) -> bool:\n    times = [float(e[\"time\"]) for e in events]\n    intervals = [round(b - a, 6) for a, b in zip(times, times[1:])]\n    return len(set(intervals)) > 1","tryCatchPattern":"try:\n    validate_effect_recipe(recipe, reference_durations)\nexcept ContractError as exc:\n    if \"intervals must vary\" in str(exc):\n        recipe[\"events\"] = add_jitter(recipe[\"events\"])\n        validate_effect_recipe(recipe, reference_durations)\n    else:\n        raise","preventionTips":["Avoid linspace/arange for event-time generation; use random gaps","Always generate at least 3 events with distinct gaps","Add jitter proportional to a seed you control for reproducibility","Lint generators with a periodicity check mirroring the contract"],"tags":["validation","contract","stochastic"],"backgroundTag":"invalid-argument-value","analyzedSha":"8321021c54d670126ce3b2969d5deb880b4b0c2a","analyzedAt":"2026-09-16T10:08:13.343Z","contentChangedAt":"2026-09-16T10:08:13.343Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}