{"record":{"id":"aa7496ee18ddbd63","repo":"affaan-m/ECC","slug":"timeline-is-too-short-for-a-fail-closed-aperiodic-effect","errorCode":null,"errorMessage":"timeline is too short for a fail-closed aperiodic effect schedule","messagePattern":"timeline is too short for a fail-closed aperiodic effect schedule","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"skills/taste-application/scripts/tasteforge/workflow.py","lineNumber":462,"sourceCode":"    duration = max(duration, 6.0)\n    effect_names = {\n        \"flash-ethereal\": \"bloom_flash\",\n        \"3d-cyber-glitch\": \"cv_wireframe_lock\",\n        \"fluid-sketch\": \"fluid_contour_bleed\",\n    }\n    event_times: list[float] = []\n    clock = round(rng.uniform(0.35, 0.75), 6)\n    while clock <= duration - 0.08 and len(event_times) < 18:\n        event_times.append(clock)\n        clock = round(clock + rng.uniform(0.61, 2.17), 6)\n\n    # Short timelines use deterministic, aperiodic fallback positions rather\n    # than forcing later random draws beyond the declared duration.\n    if len(event_times) < 4:\n        event_times.extend(round(duration * fraction, 6) for fraction in (0.10, 0.28, 0.53, 0.82))\n        event_times = sorted({time for time in event_times if 0 <= time <= duration - 0.08})[:18]\n    if len(event_times) < 4:\n        raise ValueError(\"timeline is too short for a fail-closed aperiodic effect schedule\")\n\n    events: list[dict[str, Any]] = []\n    for index, clock in enumerate(event_times):\n        spec = specs[index % len(specs)]\n        ref = by_genre[spec[\"number\"]][index % len(by_genre[spec[\"number\"]])]\n        sample_times = ref[\"probe\"].get(\"sample_times\", [])\n        evidence_time = float(sample_times[index % len(sample_times)]) if sample_times else 0.0\n        source_duration = ref[\"source_duration\"]\n        requires_anchor = spec[\"slug\"] == \"3d-cyber-glitch\"\n        event_duration = round(min(rng.uniform(0.08, 0.42), duration - clock), 6)\n        event: dict[str, Any] = {\n            \"event_id\": f\"fx-{index:03d}\",\n            \"time\": clock,\n            \"duration\": event_duration,\n            \"genre_number\": spec[\"number\"],\n            \"effect\": effect_names.get(spec[\"slug\"], \"reference_accent\"),\n            \"requires_subject_anchor\": requires_anchor,\n            \"placement\": {","sourceCodeStart":444,"sourceCodeEnd":480,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/skills/taste-application/scripts/tasteforge/workflow.py#L444-L480","documentation":"Effect scheduling needs at least four valid event times within the timeline to build an aperiodic schedule. After clamping fallback positions to [0, duration - 0.08], fewer than four remain when the timeline is extremely short, so the builder fails closed instead of producing overlapping/degenerate effects.","triggerScenarios":"_build_effect_recipe is called with a computed/configured duration so small (after the 6.0s floor bypass or with filtered event times) that fewer than 4 event times survive the 0..duration-0.08 filter.","commonSituations":"Very short reference clips with measured total_duration near zero; config resolving to a tiny duration; sources whose features yielded almost no valid timestamps.","solutions":["Provide longer reference media so measured total_duration yields a usable timeline","Set resolve_duration explicitly to a sane value >= 6.0 in the config","Check probe output (sample_times/scene changes) — replace sources that produced no usable features"],"exampleFix":"// before\n\"resolve_duration\": 0.5\n// after\n\"resolve_duration\": 8.0","handlingStrategy":"validation","validationCode":"probe = probe_media(source)\ndur = config.get(\"resolve_duration\") or probe.get(\"total_duration\", 0)\nassert dur >= 6.0, f\"timeline too short: {dur}s — use longer source media or set resolve_duration >= 6\"","typeGuard":"def timeline_is_schedulable(duration: float, min_len: int = 4) -> bool:\n    slots = sorted({round(duration * f, 6) for f in (0.10, 0.28, 0.53, 0.82)\n                    if 0 <= duration * f <= duration - 0.08})\n    return duration > 0 and len(slots) >= min_len","tryCatchPattern":"try:\n    recipe = build_recipe(specs, config)\nexcept ValueError as e:\n    if \"timeline is too short\" in str(e):\n        config[\"resolve_duration\"] = max(6.0, config.get(\"resolve_duration\") or 6.0)\n        recipe = build_recipe(specs, config)\n    else:\n        raise","preventionTips":["Use reference clips long enough to yield >= 4 event times","Set an explicit resolve_duration >= 6.0 for very short sources","Check probe features (scene changes/sample_times) before building recipes"],"tags":["validation","timeline","effect-schedule"],"backgroundTag":"value-out-of-range","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"}