Repository navigation
Keep operator complexity in sync with clamped ticket complexity - #4
Merged
Merged
Conversation
bound_tickets and total_complexity are unsigned; a drifted counter made decrement() throw SQLSTATE 22003 on ticket close/unbind, which aborted projection and left the closed ticket bound to the operator.
Base automatically changed from
fix/clamp-operator-counter-decrements
to
master
November 10, 2026 10:34
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #3, based on its branch.
Problem
#3 stops the decrement from failing, but the counter still drifts below the real sum, and one source of that drift is
onTicketMetricsAdjusted:TicketProjectorclamps the ticket's complexity at zero:max(0, complexity + adjustment).OperatorProjectoradds the raw adjustment tototal_complexity.Ticket at
0, adjustment-5: the ticket stays at0but the operator loses5. A later+5adds5to both. The operator is now5below the sum of its tickets, and closing the ticket subtracts5from it again. Before #3 this ended inSQLSTATE[22003]: 1690 BIGINT UNSIGNED value is out of range, and it still happens in production.The handler also did read-modify-write in PHP (
update(['total_complexity' => ...])), which overwrote concurrent increments.Change
onTicketMetricsAdjustedadds the ticket's actual change to the operator,max(0, old + adjustment) - old, atomically:increment()for a positive delta,decrementToZero()from #3 for a negative one.$ticket->complexityis still the old value here becauseOperatorProjector(weight 0) runs beforeTicketProjector(weight 5).Verified
In the host app against local MySQL, with projector calls in
Projectionistorder, inside rolled-back transactions:0, adjustments-5then+5, then close: operator7 → 7 → 12 → 7. Before this change it was2after the first adjustment.4, adjustment-9: operator10 → 6. Before this change it was1.0, no exception.