Follow-up to #68 / #69, from a review finding on that PR that landed after it merged.
The check-in gate claims its anchor before the upstream usr-activity call, which is what makes the burst race safe to close. The cost is that a check-in which never reached the backend still holds the window: if the upstream call times out or 5xxs, another attempt for that account inside the window is absorbed with a 201, even though nothing was ever recorded.
That is the same shape as the bug #69 fixed, just with a narrower trigger. It is bounded in practice, since the clients' own poll interval is longer than the window and an upstream that is failing would refuse the retry anyway, but the gate should not hold a window on a check-in it knows did not land.
Proposed fix
Release the anchor when the upstream call did not deliver. Upstream.Pipe turns a transport failure into 504/500, so a 5xx on the response is exactly the "not delivered" set; an upstream 4xx is a deliberate rejection that a retry would not change, so it keeps the window.
The release must name the exact anchor it claimed and remove only that one, so a stale release arriving after the account has checked in again cannot discard the live anchor.
Deliberately not doing the alternative of awaiting the upstream result and stamping only on success: it would mean hand-rolling the Express-compatible response path that Pipe owns (invariant 3), and a 2xx from the backend does not mean the check-in was credited anyway, since that is decided later by its verifier.
Follow-up to #68 / #69, from a review finding on that PR that landed after it merged.
The check-in gate claims its anchor before the upstream
usr-activitycall, which is what makes the burst race safe to close. The cost is that a check-in which never reached the backend still holds the window: if the upstream call times out or 5xxs, another attempt for that account inside the window is absorbed with a 201, even though nothing was ever recorded.That is the same shape as the bug #69 fixed, just with a narrower trigger. It is bounded in practice, since the clients' own poll interval is longer than the window and an upstream that is failing would refuse the retry anyway, but the gate should not hold a window on a check-in it knows did not land.
Proposed fix
Release the anchor when the upstream call did not deliver.
Upstream.Pipeturns a transport failure into 504/500, so a 5xx on the response is exactly the "not delivered" set; an upstream 4xx is a deliberate rejection that a retry would not change, so it keeps the window.The release must name the exact anchor it claimed and remove only that one, so a stale release arriving after the account has checked in again cannot discard the live anchor.
Deliberately not doing the alternative of awaiting the upstream result and stamping only on success: it would mean hand-rolling the Express-compatible response path that
Pipeowns (invariant 3), and a 2xx from the backend does not mean the check-in was credited anyway, since that is decided later by its verifier.