What goes wrong
After #962 (dev 3114937), a split drawing that the turn has already taken withdraws its owed cut through Agent.dropOwedCut (internal/session/steer.go:245-264, called from internal/session/checkpoint.go:2872-2875). But the owe still runs on the sidecar's goroutine and can land after the withdrawal: the CAS at sidecar.go:153 wins for the act, the turn takes and drops an empty slot, then the act's cutGeneration sets cutOwed. On handOverRunningTurn(...).moved == false and on checkpointSettle's ctx.Err() arm, the next beginGeneration then spends one immediately-cancelled request plus a bogus addUsage / turnLane.answered sample.
The ordering itself is still close-then-CAS (sidecar.go:150-153) and take does not consult spent (sidecar.go:219-229); the harm is closed by the withdrawal, and the withdrawal has this one hole. dropOwedCut's doc sentence ("exact rather than racy") is an argument about the take and the spend, not about the owe.
Replication a stranger can run
internal/session/cutboundary_test.go has the fixtures: stage a drawing whose act is delayed past the take (the besideWatch seam from #952 lets a test hold the act), take it, then assert cutOwed is empty and that the next beginGeneration does not cancel itself. Today it does.
Acceptance (end to end first)
- A split drawing taken at the boundary never costs the next request: the call log shows no row with
ms under the wire's own floor and cause errMarkCut following a mark row whose decision is split.
- Fix shape: remember the withdrawal for the turn and clear it where
markAside.start buys the next reading; correct the dropOwedCut sentence in the same change.
Found by the post-merge architecture review of #962 (~/af-review-962.md, "Post-merge at 3114937"). Related: #956, #871.
Drafted with CodeAF · reviewed and owned by the author
What goes wrong
After #962 (dev 3114937), a split drawing that the turn has already taken withdraws its owed cut through
Agent.dropOwedCut(internal/session/steer.go:245-264, called frominternal/session/checkpoint.go:2872-2875). But the owe still runs on the sidecar's goroutine and can land after the withdrawal: the CAS atsidecar.go:153wins for the act, the turn takes and drops an empty slot, then the act'scutGenerationsetscutOwed. OnhandOverRunningTurn(...).moved == falseand oncheckpointSettle'sctx.Err()arm, the nextbeginGenerationthen spends one immediately-cancelled request plus a bogusaddUsage/turnLane.answeredsample.The ordering itself is still close-then-CAS (
sidecar.go:150-153) andtakedoes not consultspent(sidecar.go:219-229); the harm is closed by the withdrawal, and the withdrawal has this one hole.dropOwedCut's doc sentence ("exact rather than racy") is an argument about the take and the spend, not about the owe.Replication a stranger can run
internal/session/cutboundary_test.gohas the fixtures: stage a drawing whose act is delayed past the take (thebesideWatchseam from #952 lets a test hold the act), take it, then assertcutOwedis empty and that the nextbeginGenerationdoes not cancel itself. Today it does.Acceptance (end to end first)
msunder the wire's own floor and causeerrMarkCutfollowing a mark row whose decision issplit.markAside.startbuys the next reading; correct thedropOwedCutsentence in the same change.Found by the post-merge architecture review of #962 (
~/af-review-962.md, "Post-merge at 3114937"). Related: #956, #871.Drafted with CodeAF · reviewed and owned by the author