Problem
A valid line-start @target can be persisted but never invoke its target when that cat already has an active or queued agent entry. This drops an ordinary A2A handoff rather than retaining it until the target slot is free.
Observed in thread thread_mruayc4owlyzazbx:
- Fable posted a valid line-start
@sol with the Q3/Q4 handoff (0001786435553718-000283-0311fbcd).
- Sol was completing an earlier turn in the same timing window; the first response did not consume Q3/Q4.
- A later manual
@sol (0001786436054020-000300-40672525) did invoke Sol, which then answered Q3/Q4. This rules out handle parsing, availability, and provider failure.
Root cause
resolveInlineCat() returns skip: dedup_active whenever hasActiveAgent(cat) is true. routeSerial() then immediately continues, so the ordinary text-derived handoff never reaches claimOrDeferA2ATarget(), the lower path that is designed to durably enqueue an occupied target.
Relevant paths:
packages/api/src/domains/cats/services/agents/routing/routing-decision.ts
packages/api/src/domains/cats/services/agents/routing/route-serial.ts
packages/api/src/domains/cats/services/agents/invocation/QueueProcessor.ts
The present unit test explicitly locks in the losing behavior: routing-decision.test.js expects skip: dedup_active for a processing target.
Expected behavior
A busy target must prevent a concurrent invocation, not erase the handoff. Preserve one durable A2A carrier using the original trigger message as a2aTriggerMessageId; when the active slot is released, invoke the target exactly once. Repeated identical handoffs may coalesce, but must remain observable and must not silently disappear.
Acceptance criteria
- A line-start mention to a target with an active/queued agent entry produces a durable queued/coalesced A2A carrier instead of
skip: dedup_active.
- The carrier retains the originating message ID and target, survives target-slot release, and invokes the target exactly once.
- No concurrent duplicate target invocation is started.
- A regression test exercises the real queue-backed route path (not only
routeSerial with the active-queue hook omitted).
- F167 custody/diagnostic projections observe a real queued handoff rather than a text-only false success.
Relation to #1312
Related to #1312 (F254 message delivery attempts), but not part of its scope. #1312 begins after a durable queue carrier exists and provides per-target failure/retry custody. This defect occurs before carrier admission, so there is nothing for #1312 to retry. Keep the fixes separate; both may share queue/custody primitives after the admission contract is corrected.
Problem
A valid line-start
@targetcan be persisted but never invoke its target when that cat already has an active or queued agent entry. This drops an ordinary A2A handoff rather than retaining it until the target slot is free.Observed in thread
thread_mruayc4owlyzazbx:@solwith the Q3/Q4 handoff (0001786435553718-000283-0311fbcd).@sol(0001786436054020-000300-40672525) did invoke Sol, which then answered Q3/Q4. This rules out handle parsing, availability, and provider failure.Root cause
resolveInlineCat()returnsskip: dedup_activewheneverhasActiveAgent(cat)is true.routeSerial()then immediatelycontinues, so the ordinary text-derived handoff never reachesclaimOrDeferA2ATarget(), the lower path that is designed to durably enqueue an occupied target.Relevant paths:
packages/api/src/domains/cats/services/agents/routing/routing-decision.tspackages/api/src/domains/cats/services/agents/routing/route-serial.tspackages/api/src/domains/cats/services/agents/invocation/QueueProcessor.tsThe present unit test explicitly locks in the losing behavior:
routing-decision.test.jsexpectsskip: dedup_activefor a processing target.Expected behavior
A busy target must prevent a concurrent invocation, not erase the handoff. Preserve one durable A2A carrier using the original trigger message as
a2aTriggerMessageId; when the active slot is released, invoke the target exactly once. Repeated identical handoffs may coalesce, but must remain observable and must not silently disappear.Acceptance criteria
skip: dedup_active.routeSerialwith the active-queue hook omitted).Relation to #1312
Related to #1312 (F254 message delivery attempts), but not part of its scope. #1312 begins after a durable queue carrier exists and provides per-target failure/retry custody. This defect occurs before carrier admission, so there is nothing for #1312 to retry. Keep the fixes separate; both may share queue/custody primitives after the admission contract is corrected.