{"record":{"id":"3a6826d7d147792b","repo":"affaan-m/ECC","slug":"stochastic-schedule-is-periodic-repeating-interval-cycle","errorCode":null,"errorMessage":"stochastic schedule is periodic; repeating interval cycle","messagePattern":"stochastic schedule is periodic; repeating interval cycle","errorType":"validation","errorClass":"ContractError","httpStatus":null,"severity":"error","filePath":"skills/taste-application/scripts/tasteforge/contract.py","lineNumber":224,"sourceCode":"        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\"}:\n                raise ContractError(f\"CV effect {event.get('effect')} has an invalid subject anchor\")\n            if anchor.get(\"lost_policy\") != \"disable_effect_until_track_recovers\":\n                raise ContractError(f\"CV effect {event.get('effect')} must fail closed on anchor loss\")","sourceCodeStart":206,"sourceCodeEnd":242,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/skills/taste-application/scripts/tasteforge/contract.py#L206-L242","documentation":"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.","triggerScenarios":"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].","commonSituations":"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,...).","solutions":["Inject random jitter into each gap so no exact cycle repeats.","Generate intervals from an i.i.d. random distribution instead of repeating a pattern.","Extend the pattern with a long non-repeating tail, though true randomness is safer.","Test your generator output against the same periodicity logic locally before running validate_bundle."],"exampleFix":"// before\ntimes = [0.0, 1.0, 3.0, 4.0, 6.0, 7.0]  # intervals 1,2,1,2,1 cycle\n// after\nimport random\ntimes, t = [0.0], 0.0\nfor _ in range(5):\n    t += random.uniform(0.3, 2.5)\n    times.append(round(t, 6))","handlingStrategy":"validation","validationCode":"intervals = [round(b - a, 6) for a, b in zip(times, times[1:])]\nfor period in range(1, len(intervals) // 2 + 1):\n    if all(iv == intervals[i % period] for i, iv in enumerate(intervals)):\n        raise ValueError(f\"interval cycle of period {period} detected\")","typeGuard":"def has_repeating_interval_cycle(events) -> bool:\n    times = [float(e[\"time\"]) for e in events]\n    iv = [round(b - a, 6) for a, b in zip(times, times[1:])]\n    return any(all(x == iv[i % p] for i, x in enumerate(iv)) for p in range(1, len(iv) // 2 + 1))","tryCatchPattern":"try:\n    validate_effect_recipe(recipe, reference_durations)\nexcept ContractError as exc:\n    if \"repeating interval cycle\" in str(exc):\n        recipe[\"events\"] = rejitter_times(recipe[\"events\"])\n    else:\n        raise","preventionTips":["Never tile a fixed gap pattern across the timeline","Generate each gap independently from a random distribution","Test generated schedules with the same periodicity scan the contract uses","Keep an entropy floor: prefer continuous distributions over quantized gaps"],"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"}