Skip to content

[Fix] The completion check skips every task delegated from a Session - #3083

Merged
mrubens merged 5 commits into
developfrom
fix/completion-check-delegated-request
Sep 22, 2026
Merged

mrubens merged 5 commits into
developfrom
fix/completion-check-delegated-request

Conversation

@mrubens

@mrubens mrubens commented Sep 22, 2026

Copy link
Copy Markdown
Contributor

Problem

First live observation of the turn-end completion check from #3071, on the nightly deployment: the harness ran it at turn end and the API answered skipped in 101 ms, before any judgment call.

A task delegated from a Session receives its request as a hidden <request> prompt (visibleInTranscript=false). The request loader filtered hidden prompts out, found no request, and skipped. That is most tasks.

Change

The loader reads every stored user prompt. Hidden ones are requests too: a delegated task's opening prompt is one, and the harness never persists its own reminders as prompts, so nothing else can get in. Test added with a hidden opening prompt.

Validation

  • task-completion-gate.test.ts (11), pnpm lint:fast, pnpm check-types:fast, pnpm knip.

@roomote-community

roomote-community Bot commented Sep 22, 2026 •

Copy link
Copy Markdown
Contributor

No code issues found. See task

  • Queued harness continuations preserve their source through RuntimePromptQueue.restore(), so reconnects and replays remain excluded from completion-gate follow-ups.
  • Hidden platform notices with non-opencode-* sources, such as environment-setup, are excluded from follow-ups while a hidden opening request is retained.

Reviewed 293dae1

and(
eq(taskMessages.taskId, taskId),
eq(taskMessages.eventType, ACP_ENVELOPE_EVENT_TYPES.UserPrompt),
sql`coalesce(${taskMessages.metadata} ->> 'visibleInTranscript', 'true') <> 'false'`,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removing this filter also admits the harness's hidden UserPrompt records. For example, submitPrompt() persists the completion-gate reminder with visibleInTranscript: false; on the next gate pass it becomes a follow-up request. That can make the judgment evaluate its own remediation instructions and repeatedly flag an otherwise completed task. Keep filtering those system-injected/reminder prompts while allowing the delegated opening request, and add a regression test for a hidden completion-gate reminder.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The source check does not cover the hidden continuations sent through drainQueuedPrompts(). Provider-error/rate-limit retries, visual-proof recovery, and plan-exit continuations are enqueued with visibleInTranscript: false but no source; the drain persists them as UserPrompt rows without a source. With the visibility SQL filter removed, these messages still enter followUps and can influence a later completion judgment. Preserve an origin/source for queued harness prompts (or otherwise exclude them) and add coverage for one queued hidden continuation.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is still possible after a queue restore: RuntimePromptQueue.restore() rebuilds each message without copying source. A reconnect, or a shouldBlockPrompt/shouldReconnect replay, therefore drains the hidden continuation without its opencode-* marker and lets it enter completion-gate follow-ups. Preserve source in restore() and cover a restored hidden continuation.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copying source through restore() fixes the reconnect path, but the predicate only excludes opencode-* sources. run-task.ts also delivers hidden environment-setup notices with source: 'environment-setup'; handleSendMessage() persists those as UserPrompt rows. They now pass isHarnessPrompt() and are included as completion-gate follow-ups, so the judge can still receive a platform notification as user work. Exclude known non-user hidden prompt sources (or retain a reliable request-origin marker) and cover this path.

@mrubens

mrubens commented Sep 22, 2026

Copy link
Copy Markdown
Contributor Author

Addressed with a source filter and a regression test. For the record, the premise was off: submitPrompt() only calls promptAsync; user prompts are persisted by the StartNewTask/SendMessage handlers and the queue drain, so the completion-gate and stop-hook reminders never reach task_messages. The filter guards against that changing.

@mrubens
mrubens marked this pull request as ready for review September 22, 2026 02:12
@mrubens
mrubens merged commit 85698cc into develop Sep 22, 2026
17 checks passed
@mrubens
mrubens deleted the fix/completion-check-delegated-request branch September 22, 2026 02:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant