Summary
An issue that emitted the input-required sentinel on every successful run was redispatched by the poller 49 consecutive times, accumulating 49 🤖 **Agent needs your input** comments posted by Itervox itself on the tracker issue, before the loop was manually broken by a human. The sentinel-pause contract did not hold across redispatches.
What was observed
- 49 consecutive Itervox dispatches of the same tracker issue.
- 68 emissions of
<!-- itervox:needs-input --> across those runs (some runs emitted the sentinel more than once in their final message).
- 49 corresponding
🤖 **Agent needs your input** comments posted on the tracker issue by Itervox's TerminalInputRequired handler.
- The issue's tracker state during the loop was one of the configured
active_states throughout — no custom or unusual states involved.
- 0 human replies to any of the 49 input-required questions during the loop. The loop ended only after manual intervention.
What should have happened
After the first successful sentinel emission, the issue should have been added to state.InputRequiredIssues and filtered out by IneligibleReason on every subsequent poll cycle until a human reply landed.
If Itervox restarted between dispatches, recoverInputRequired should have re-detected the unanswered 🤖-prefixed comment on the next dispatch attempt and re-populated InputRequiredIssues without dispatching a fresh worker.
In the observed case, neither path held: 49 sentinels were emitted, 49 prefixed question comments were posted by Itervox itself, and the poller continued to pick the issue up between each emission.
Why this matters
The sentinel is the only mechanism a prompt template has to pause an issue without manual intervention. When sentinel-pause is unreliable:
- Agents waste turns and API credits re-deriving the same conclusion on every redispatch.
- The tracker issue accumulates duplicate question comments — one per dispatch.
- The
<!-- itervox:needs-input --> contract documented for prompt authors becomes effectively meaningless: emitting the sentinel produces no reliable suppression of subsequent dispatches.
Relevant code paths (for triage)
internal/agent/runner.go:50-83 — FinalizeResult / sentinel detection on the assistant text.
internal/orchestrator/event_loop.go:957-977 — TerminalInputRequired handler. Sets state.InputRequiredIssues synchronously; posts the 🤖-prefixed comment in a fire-and-forget goroutine, errors logged and ignored.
internal/orchestrator/event_loop.go:235-280 — recoverInputRequired. Walks comments in reverse for the last 🤖-prefixed one and treats it as a pause signal only if no non-prefixed comment appears after it.
internal/orchestrator/dispatch.go:13-68 — IneligibleReason skips issues present in state.InputRequiredIssues.
internal/orchestrator/orchestrator.go:73, internal/orchestrator/snapshot.go:210-285 — inputRequiredFile persistence is optional; without it the in-memory map is the only store.
Reproduction notes
To reproduce on any tracker, dispatch a workflow whose prompt template always emits <!-- itervox:needs-input --> as its final message. Let the poller run for several intervals while observing:
- Whether the issue is dispatched again between successive sentinel emissions.
- Whether the issue's
state.InputRequiredIssues entry persists across dispatches.
- Whether
recoverInputRequired finds the prior 🤖-prefixed comment on each fresh dispatch attempt.
- Whether tracker comment ordering returned by
FetchIssueDetail matches insertion order.
A workflow that posts its own tracker comments during the run (e.g. via custom GraphQL mutations from the prompt body, before the sentinel-emitting final message) is more likely to expose the issue, because non-prefixed comments interleaved with the 🤖-prefixed ones can defeat recoverInputRequired's "no non-prefixed comment after" check.
Summary
An issue that emitted the input-required sentinel on every successful run was redispatched by the poller 49 consecutive times, accumulating 49
🤖 **Agent needs your input**comments posted by Itervox itself on the tracker issue, before the loop was manually broken by a human. The sentinel-pause contract did not hold across redispatches.What was observed
<!-- itervox:needs-input -->across those runs (some runs emitted the sentinel more than once in their final message).🤖 **Agent needs your input**comments posted on the tracker issue by Itervox'sTerminalInputRequiredhandler.active_statesthroughout — no custom or unusual states involved.What should have happened
After the first successful sentinel emission, the issue should have been added to
state.InputRequiredIssuesand filtered out byIneligibleReasonon every subsequent poll cycle until a human reply landed.If Itervox restarted between dispatches,
recoverInputRequiredshould have re-detected the unanswered🤖-prefixed comment on the next dispatch attempt and re-populatedInputRequiredIssueswithout dispatching a fresh worker.In the observed case, neither path held: 49 sentinels were emitted, 49 prefixed question comments were posted by Itervox itself, and the poller continued to pick the issue up between each emission.
Why this matters
The sentinel is the only mechanism a prompt template has to pause an issue without manual intervention. When sentinel-pause is unreliable:
<!-- itervox:needs-input -->contract documented for prompt authors becomes effectively meaningless: emitting the sentinel produces no reliable suppression of subsequent dispatches.Relevant code paths (for triage)
internal/agent/runner.go:50-83—FinalizeResult/ sentinel detection on the assistant text.internal/orchestrator/event_loop.go:957-977—TerminalInputRequiredhandler. Setsstate.InputRequiredIssuessynchronously; posts the🤖-prefixed comment in a fire-and-forget goroutine, errors logged and ignored.internal/orchestrator/event_loop.go:235-280—recoverInputRequired. Walks comments in reverse for the last🤖-prefixed one and treats it as a pause signal only if no non-prefixed comment appears after it.internal/orchestrator/dispatch.go:13-68—IneligibleReasonskips issues present instate.InputRequiredIssues.internal/orchestrator/orchestrator.go:73,internal/orchestrator/snapshot.go:210-285—inputRequiredFilepersistence is optional; without it the in-memory map is the only store.Reproduction notes
To reproduce on any tracker, dispatch a workflow whose prompt template always emits
<!-- itervox:needs-input -->as its final message. Let the poller run for several intervals while observing:state.InputRequiredIssuesentry persists across dispatches.recoverInputRequiredfinds the prior🤖-prefixed comment on each fresh dispatch attempt.FetchIssueDetailmatches insertion order.A workflow that posts its own tracker comments during the run (e.g. via custom GraphQL mutations from the prompt body, before the sentinel-emitting final message) is more likely to expose the issue, because non-prefixed comments interleaved with the
🤖-prefixed ones can defeatrecoverInputRequired's "no non-prefixed comment after" check.