Skip to content

source-control:babysit-prs + loop: dynamic /loop wakeups ignore the engine's own recommended_cadence field #504

Description

@kyle-sexton

Category: behavioral · Lane: babysit (dynamic /loop /source-control:babysit-prs, no fixed interval)

Triggering example

Across 2 consecutive cycles in one session, the snapshot's queue-state.json computed
recommended_cadence: "active" both times (per reference/cadence.md: 5-minute polling —
correct, since both cycles had genuinely pending CI / new blocking bot feedback on watched
PRs). Both times I (the orchestrator) called ScheduleWakeup with delaySeconds in the
1200-1500 range (20-25 min) instead — I never actually read the recommended_cadence field
out of the snapshot/state JSON at all. I picked the delay from the generic /loop skill's own
"idle tick" heuristic (1200-1800s) instead of this skill's domain-specific, already-computed
recommendation.

Net effect: PRs with pending CI (e.g. #490, #492 mid-cycle) or unresolved blocking feedback sat
unchecked for up to 4-5x longer than the skill's own adaptive-cadence contract calls for. User
noticed the lag empirically ("could wait 20 minutes and not realize PRs have been ready for
5-10+ minutes").

Observed vs expected

  • Observed: SKILL.md step 9 says "Schedule the next wake from the snapshot's
    recommended_cadence" and reference/cadence.md fully specifies the states
    (active=5m/normal=15m/quiet=1h/idle=1d), but nothing in the operational runbook tells the
    orchestrator how to translate that string into a concrete ScheduleWakeup call in dynamic
    /loop mode — so it's easy (and is exactly what happened) to fall back to the generic /loop
    skill's own delay-picking guidance instead, silently overriding the domain skill's tighter
    contract.
  • Expected: the runbook should explicitly say, e.g.: "map recommended_cadence to
    ScheduleWakeup.delaySeconds via {active: 300, normal: 900, quiet: 3600, idle: 3600} (idle's
    documented 1-day cadence must clamp to ScheduleWakeup's hard 3600s ceiling — call this out
    explicitly rather than leaving it to be silently truncated or ignored)."
  • Separately: ScheduleWakeup's [60, 3600] clamp cannot express cadence.md's "Idle: daily"
    state at all in a single-session /loop. Worth documenting as a known ceiling (durable
    /schedule cron is the correct tool for a real daily cadence) rather than a silent gap.

Related (already filed, referenced not duplicated)

#472 (fixed-interval /loop Nm overlaps long fan-out cycles — a different failure mode: this
issue is about dynamic /loop ignoring the engine's own cadence signal entirely, not about a
fixed cron interval being too short) · #477 (absorb v4 loop-prompt rules into the skill —
lists "loop-pacing guidance keyed to worker concurrency cap" but not this specific
recommended_cadence-consumption gap)

Suggested fix location

reference/loop.md §5.3 (the static cadence ladder / dynamic-mode wake guidance) — add the
explicit string-to-seconds mapping and the idle-ceiling caveat.

Metadata

Metadata

Assignees

No one assigned

    Labels

    priority: highSignificant impact, or blocks an imminent release; staff this cycle.status: readyTriaged, unblocked, and fully specified; eligible to pick up.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions