Skip to content

regression(orchestrator): Blocked → Rework Kanban move remains scheduler-blocked during degraded status refresh #1482

Description

@michaelhvisser
schema: 1
effort: xhigh

Problem

On Detent v0.48.0 (87d1438), an operator can successfully move cards from Blocked to Rework through the integrated Kanban, while the scheduler continues skipping those same Rework candidates as internally blocked.

This makes the board look correctly requeued but leaves the Rework slots idle until a later successful reconciliation or a process restart clears the stale runtime state.

Live evidence

Observed on 2026-07-22 in the Parable project:

  1. Four cards were moved through POST /api/v1/kanban/move:
    • getparable/parable#1351
    • getparable/parable#1516
    • getparable/parable#1524
    • getparable/parable#1634
  2. Every mutation returned HTTP 200: {"message":"Moved card to Rework.","ok":true}.
  3. The live board immediately showed:
    • Blocked: 14 → 10
    • Rework: 0 → 4
  4. At 2026-07-22T11:57:36Z, scheduler decisions 114028–114031 saw all four candidates in lane Rework, with project_state_available: 2 and project_state_used: 0, but skipped every one with:
    • result=skipped
    • reason=blocked
    • wait_reason=blocked
  5. /api/v1/state still reported the old blocked count while the Kanban showed the cards in Rework.
  6. The same refresh window had degraded GitHub hydration/status reads from the REST fan-out cap. After restarting Detent, the stale runtime state disappeared and fix(board): hide scheduled recovery pacing #1351/#1516 dispatched immediately into the two Rework slots.

Likely seam

The integrated Kanban mutation updates the tracker and web mutation overlay, but does not synchronously invalidate the matching orchestrator state.Blocked entry.

In internal/orchestrator/tick.go, a failed/degraded blocked-status transition refresh can merge previous.blockedStatusIssues back into the current set before dispatch. clearBlockedStatusIssue in internal/orchestrator/reconcile.go only clears through reconciliation, so a fresh candidate that is already visibly Rework can still be vetoed by stale project-status memory.

Related closed issue: #1378.

Expected behavior

A confirmed operator move away from Blocked must make that card dispatchable on the next scheduler decision, even if the broader observed-status refresh is temporarily degraded.

Acceptance criteria

  • A successful integrated Kanban move from Blocked to an active state invalidates the matching project-status blocked entry without waiting for a full tracker refresh.
  • Retry, claim, breaker, and blocked memory are reconciled only for the moved item; unrelated blockers are preserved.
  • A regression test moves Blocked → Rework, injects a failed/degraded blocked-status refresh, and proves the candidate dispatches when lane capacity exists.
  • Board, /api/v1/state, and scheduler-decision blocked counts converge without a process restart.
  • Audit/telemetry records the operator move as the reason the runtime block was cleared.

Metadata

Metadata

Assignees

No one assigned

    Labels

    detent:doneDetent state: complete.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions