affaan-m/ECC · error · ContractError

effect event end exceeds the declared timeline

Error message

effect event end exceeds the declared timeline

What it means

An event must fit inside the declared timeline: start + duration may not exceed timeline_duration (with a tiny 1e-9 tolerance for float rounding). An event that ends after the timeline is inconsistent with the recipe's declared bounds and is rejected.

Solutions

  1. Reduce the event's duration (or start) so time + duration <= timeline_duration.
  2. Increase recipe['timeline_duration'] to cover all events.
  3. Regenerate the schedule ensuring events are laid out within the timeline bound.

Example fix

# before
{"time": 28.0, "duration": 5.0}  # timeline 30.0
# after
{"time": 25.0, "duration": 5.0}  # ends at 30.0
Defensive patterns

Strategy: validation

Validate before calling

for ev in recipe["events"]:
    if float(ev["time"]) + float(ev["duration"]) > float(recipe["timeline_duration"]) + 1e-9:
        raise ValueError(f"event {ev} ends past timeline {recipe['timeline_duration']}")

Type guard

def event_fits_timeline(ev: dict, timeline: float) -> bool:
    return float(ev["time"]) + float(ev["duration"]) <= float(timeline) + 1e-9

Try / catch

try:
    validate_effect_recipe(recipe)
except ContractError as exc:
    if "exceeds the declared timeline" in str(exc):
        recipe = {**recipe, "events": [clip_event_to_timeline(ev, recipe["timeline_duration"]) for ev in recipe["events"]]}
        validate_effect_recipe(recipe)
    else:
        raise

Prevention

When it happens

Trigger: validate_effect_recipe called where any event satisfies time + duration > timeline_duration + 1e-9, e.g. start 28.0 with duration 5.0 on a 30.0 timeline.

Common situations: Editing event durations after fixing the timeline; generating events evenly spaced across a slightly-too-short timeline; unit mismatch between event times and timeline_duration; off-by-one when events are meant to end 'at' the boundary.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


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

Appendix: source

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

    events = recipe.get("events")
    if not isinstance(events, list) or len(events) < 3:
        raise ContractError("effect recipe needs at least three scheduled events")
    timeline = recipe.get("timeline_duration")
    if not _is_finite_real(timeline):
        raise ContractError("effect recipe must declare a finite positive timeline duration")
    timeline = cast(float, timeline)
    if float(timeline) <= 0:
        raise ContractError("effect recipe must declare a finite positive timeline duration")
    for event in events:
        start = event.get("time")
        duration = event.get("duration")
        if (not _is_finite_real(start) or not _is_finite_real(duration)
                or float(start) < 0 or float(duration) <= 0):
            raise ContractError("effect event start and duration must be finite positive timeline values")
        start = cast(float, start)
        duration = cast(float, duration)
        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):

View on GitHub (pinned to 8321021c54)