966c58a3b8
abandon() drained the target's stranded reply once and then reused that same Reply for every open task it walked past. Two open tickets on one target therefore both came back REPLIED with the same text — one of them a reply the worker never gave for that delegation. One worker answer can settle at most one delegation. It now goes to the oldest open task (lowest createdNanos) and every other open task keeps the ordinary WORKER_FAILED path. If the chosen task turns out to be already resolved by another path, the drained reply is published back to the inbox instead of being dropped. reply()'s matching side gets the same rule: more than one candidate means the reply goes to the inbox rather than to a guess. Reachability, checked rather than assumed: - matching.size() >= 2 alone is reachable and was a real bug before this change. - More than one candidate in reply() is not reachable today — hasAsyncQuestion matches any task with a stamped turnId, and answer()'s clearAsyncQuestion(turnId, false) leaves that stamp until the resumed turn resolves. Kept as defensive code, documented, no test seam added. - matching.size() >= 2 together with a live strand is not reachable either: send() and answer() are the only two lock holders and both open a Rendezvous waiter inside the lock, so "lock held" and "waiter open" are one fact, and an acceptance always clears the strand first. I checked the last point by building it in a scratch worktree: it can be forced by closing an accepted send's waiter directly through Rendezvous, and it does go red against the pre-fix loop — but that breaks the lock-and-waiter invariant from outside the class, so no such test is added. A note in abandon()'s javadoc says so, to save the next reader the same round trip. Worker's REPORT-cb137.md left out of main. mvn clean install: Tests run: 1071, Failures: 0, Errors: 0, Skipped: 0