Summary
With two backends on one Xum root, backend B can run a turn under attempt A without rotating the attempt. A peer or manual send in B binds, unowned, to the row's current attempt ID. Backend A, which owns A, is locally idle meanwhile. A's process-local checks (attemptCannotStillReport: no obligation, no live turn or stream in this process) therefore pass. A Stop in A persists interrupted and writes a settlement receipt that says "no report", while B's stream can still publish one: publishAgentTaskReport accepts an interrupted row whose attempt ID still matches.
Two backends can share a root with XUM_ALLOW_MULTIPLE_INSTANCES=1, or when the desktop app and xum server share ~/.xum. Electron's single-instance lock does not cover the CLI server, so a backend cannot detect its peers.
Scope
This follows from the admission model on main: an unowned send binds to a foreign attempt without rotating it. #4308's staged contract already says two-backend ownership is not guaranteed. G2 PR A (#4540) makes the gap observable, because a receipt is a durable claim. PR A scopes its receipts to one backend per root and never lets a receipt override a report:
- A receipt is evidence that one backend settled the attempt. It is never proof that no report exists.
- G2 PR B's classifier reads the report artifact first. A receipt followed by a report counts as reported.
Fix directions
- Rotate the attempt when a backend other than the owner admits a turn under it, so the owner's attempt is superseded and its receipt is skipped.
- Or write per-attempt execution evidence (a durable marker or lease) from any backend that runs a turn under an attempt, and check it before minting a receipt.
Related
#4308, #4414, #4415, #4540.
Generated with xum • Model: anthropic:claude-opus-5-5 • Thinking: high
Summary
With two backends on one Xum root, backend B can run a turn under attempt A without rotating the attempt. A peer or manual send in B binds, unowned, to the row's current attempt ID. Backend A, which owns A, is locally idle meanwhile. A's process-local checks (
attemptCannotStillReport: no obligation, no live turn or stream in this process) therefore pass. A Stop in A persistsinterruptedand writes a settlement receipt that says "no report", while B's stream can still publish one:publishAgentTaskReportaccepts an interrupted row whose attempt ID still matches.Two backends can share a root with
XUM_ALLOW_MULTIPLE_INSTANCES=1, or when the desktop app andxum servershare~/.xum. Electron's single-instance lock does not cover the CLI server, so a backend cannot detect its peers.Scope
This follows from the admission model on
main: an unowned send binds to a foreign attempt without rotating it. #4308's staged contract already says two-backend ownership is not guaranteed. G2 PR A (#4540) makes the gap observable, because a receipt is a durable claim. PR A scopes its receipts to one backend per root and never lets a receipt override a report:Fix directions
Related
#4308, #4414, #4415, #4540.
Generated with
xum• Model:anthropic:claude-opus-5-5• Thinking:high