Skip to content

[Feature]: Proactively explain blocked tasks and recovery actions without requiring dashboard inspection #4381

Description

@stone16

Problem / 用户影响

When a task becomes blocked, the owner should be told what is blocked, why, who can resolve it, and whether any owner action is required. A badge that is discoverable only by opening Tasks is insufficient. An agent continuing safe fallback work must not hide a newly blocked primary task.

当前任务进入受阻状态后,用户可能直到自行打开 Tasks 才发现。请首次主动说明阻塞原因、影响、解除责任人及下一步;Agent 能自行解决时明确“无需你操作”,不要把所有阻塞都变成用户审批。

Reproduction and verified scope

Installed Python distribution: LoopX 1.0.3. This is a synthetic, read-only projection reproduction; it does not claim a clean end-to-end notification-provider failure or that current upstream main is unchanged.

from loopx.control_plane.quota.should_run_prepare import _blocked_priority_fallback

blocked = {
    "todo_id": "todo_aaaaaaaaaaaa",
    "text": "[P0] Validate the primary deliverable",
    "status": "blocked",
    "task_class": "advancement_task",
    "reason": "Required input has not arrived",
}
fallback = {
    "todo_id": "todo_bbbbbbbbbbbb",
    "text": "[P1] Prepare independent documentation",
    "status": "open",
    "task_class": "advancement_task",
}
p = _blocked_priority_fallback({
    "first_open_items": [blocked, fallback],
    "first_executable_items": [fallback],
})
print(p["kind"], p["notify_user"], p["requires_user_action"])

Executed result: blocked_priority_fallback False False.

The installed builder sets both booleans to false. The heartbeat refinement only promotes this fallback to NOTIFY when notify_user is true. This establishes a projection gap, not proof that every other notification path fails. The agent also has a responsibility to explain blockers; the requested product contract should make that obligation explicit and verifiable.

Expected behavior / Acceptance criteria

  • On the first material transition into blocked, deliver an owner-visible notice through the active authorized interaction surface, including task, concrete reason/evidence, impact, responsible party, recovery condition, and next action.
  • Keep should inform owner distinct from requires owner action. Agent-owned blockers say that no owner action is required; actual owner gates ask one concrete question.
  • Preserve blocker visibility when safe fallback work continues, without requiring the entire Goal to stop.
  • Deduplicate unchanged notices by blocker identity/revision. Notify again on material changes or an applicable reminder policy, rather than on every poll.
  • Reconcile recorded approval, resolved dependencies, and superseding work. Do not keep requesting authorization already granted; validate recovery before reopening work, and distinguish resumed from completed.
  • Persist notification delivery/readback state. A status badge or NOTIFY intent alone must not be reported as successful delivery. If no delivery surface is available, expose that limitation and a pending notice.
  • Cover agent-owned blocker, owner-action blocker, blocked-primary plus runnable fallback, unchanged-repeat suppression, and resolution/supersession with regression tests.

Suspected surface and relationship

Hypothesis: blocked Todo transition semantics, quota/heartbeat notification projection, and owner-facing delivery need one coherent contract. Do not simply change every blocked state to NOTIFY on every tick; scheduled future monitors are not newly blocked work.

Related: #3786 (broader intelligent review/presentation RFC). This issue requests one narrow blocker-transition and recovery slice with executable acceptance criteria.

Activity

  1. yilin-succeed commented on Sep 16, 2026

    @yilin-succeed
    Contributor

    PR #4543 covers the blocker-visibility slice of this issue: blocked_priority_fallback now sets notify_user: True for an advancement Todo that is blocked or waiting on an unsatisfied resume condition, while requires_user_action stays False, and a Todo merely scheduled for a future monitor window stays a silent deferral.

    The issue's own reproduction now returns blocked_priority_fallback True False. Delivery/readback persistence, deduplication by blocker identity/revision, and resolution/supersession reconciliation remain open.

  2. BigDataDZ commented on Sep 17, 2026

    @BigDataDZ
    Contributor

    Claiming this task. Plan: introduce a typed blocked-transition notification contract on the quota/heartbeat notification projection so the first substantive entry into blocked (task, cause/evidence, impact, owner, recovery condition, next step) is delivered through an authorized interaction surface — distinguishing "owner must know" from "owner must act" — with per-blocker identity/version dedup and persisted delivery state, while fallback work continues. Regression tests will cover the five scenarios listed in the issue (agent-own block, user action required, blocked primary + running fallback, duplicate suppression, resolved/superseded reconciliation). I'll follow up with a PR linked here.

  3. YZJF commented on Sep 18, 2026

    @YZJF
    Contributor

    Delivered the follow-up slice in #4692 (branch YZJF:yzjf/blocked-transition-notice-contract, commit c3800390026e1938990c9d10929a9b137cfbc3fd), picking up where #4543 stopped.

    What #4692 adds, per the gaps #4543 listed as still open:

    • a typed blocked-transition notice (task, cause, evidence, impact, responsible party, recovery condition, next action), with owner_must_know and owner_must_act kept separate — an agent-owned blocker states that no owner action is required, an owner gate asks one concrete question. The owner-facing reason now carries that notice instead of the generic fallback prose.
    • dedup by blocker identity and revision: an unchanged revision already delivered is suppressed, a materially changed one is told again, a reminder window (not every poll) governs repeats, and a granted approval is never requested twice.
    • persisted delivery/readback state: with no delivery surface the notice stays pending and the limitation is exposed, so a NOTIFY intent is never reported as a successful delivery. Reconciliation archives a blocker as resolved or superseded and flags one that returns after an unvalidated recovery.

    Still open from this issue: binding the ledger to a concrete authorized delivery surface so a heartbeat run actually persists it. I deliberately left that out of this slice — picking the surface is a separate decision, and wiring it before that decision would encode the wrong answer. Happy to take it as a follow-up if you name the surface.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions