Skip to content

Wave digest can finalize twice when a member is done-but-unreported #8554

Description

@CrysisDeu

Symptom

A multi-member wave can emit its final digest twice, or emit a premature partial "wave finished", when one member's SubagentInfo.done = True is set before that member's terminal report reaches the gateway completion consumer (_subagent_done).

Mechanism (pre-existing on main)

batch_members_pending() treats a member as no longer outstanding the moment info.done flips, but the member's done-count contribution to the consumer's bp["done"] only lands when its (shielded, possibly slow) terminal report task actually invokes the consumer. In that gap, ANY sibling completion that reaches the consumer sees done < total AND batch_members_pending() == False, so the last-member fallback finalizes early; the in-flight report then re-creates the batch-progress record and "finalizes" the same batch again.

This is reachable with two RUNNING members alone (member A done-but-unreported while member B's report executes the consumer) — it predates the Stop-all work in #8270 and is merely easier to hit now that stopped/unqueued members also flow through the consumer. The synthetic unqueue announces added for #8270 already bridge their own version of this window with _batch_unqueued_pending + a per-batch bounded lock; NORMAL terminal reports have no equivalent "done-but-unreported" accounting.

Direction

Extend the same protocol to normal terminal reports: count a member as outstanding from done=True until its report enters the consumer (e.g. a per-batch done-but-unreported count decremented at the top of the report path), or make the consumer's finalize decision consult report-task liveness. Needs care around the report shield, _force_reap, and cancel-recovery paths — which is why it is split out rather than folded into #8270's fix.

References

  • Consumer fallback: src/kiro_crew/slack/gateway.py (_last = ... not batch_members_pending(batch_id))
  • Report path: src/kiro_crew/subagent_manager/terminal.py
  • The Stop all leaves queued subagents running #8270 bridge for unqueued members: src/kiro_crew/subagent_manager/cancellation.py::_unqueue_impl

Found by a model review lane while verifying the #8270 fix.

Activity

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

    area: agentsACP runtime, sub-agents, session lifecyclebugSomething is not workingcrew: needs humanKiro Crew Issue Radar: needs a human or product decisionneeds-investigationTriage: requires deep analysis before a fix

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions