Honor period and reauthorization
How long a hold can be captured, what GAVEL does about it, and exactly what gate G3 is testing on the real sandbox.
In plain words
PayPal does not let a hold stay capturable forever. An authorization has an honor period: PayPal promises to honor a capture for a limited time after the hold, and may decline later ones. The authorization is also valid for a longer window. A reauthorization asks PayPal to renew the reservation, which is only useful in an auction that runs for days.
GAVEL's demo creates holds minutes before the capture, so none of this matters there. It matters for a multi-day auction. Because PayPal's real numbers are what is uncertain, GAVEL ships with reauthorization off and a real sandbox probe, gate G3, running to measure them.
Honor period and reauthorization: the model, the simulation and the real G3 probe
Scroll the figure sideways, or open it full size.
Model: Past the honor period. Strict model: a capture is refused and a reauthorization is allowed and gives a new authorization with a new honor clock. Lenient model: the capture still works. Which one PayPal follows is what G3 measures.
Real probe: checkpoint 1 of 3 (day 3.5) is due. No result is recorded yet.
Hover or focus a marker or bar for what it means and which file it comes from.
packages/payments/src/fake/core.ts (assumptions A07 to A11, all unverified) and the simulated scenarios S2 to S5 in docs/evidence/SIM/SIM-MULTIDAY.md; PayPal's real values are not verified. The third group is the real probe in packages/payments/gates/g3.ts and g3-timed.ts, run by .github/workflows/gate-g3.yml with day 0 on 7 Nov 2026 03:06 UTC. Gate G3 is IN PROGRESS; the final reading is about 12 Nov 06:17 UTC and no result is claimed here.Text version of this diagram
- Model: an authorization is held for a 3 day honor period and is valid for 29 days. A capture after the honor period is refused in the strict reading (the simulation uses it). A reauthorization is refused inside the honor period and, after it, returns a new authorization with its own id and a new honor clock.
- Policy: reauthorization is off by default (GAVEL_REAUTH). When on, a hold older than 2 days 18 hours is reauthorized before the capture, once, never above its ceiling. A hold older than 2 hours at settlement start is only flagged stale and is still captured.
- Simulation: S2 closes at day 2.5 and captures inside the honor period, and a too-early reauthorization at day 2.9 is refused without blocking the capture. S3 captures at day 3.5 with reauthorization and, with it off, nobody is charged. S4 reauthorizes at day 3.04 and captures at day 5. S5 lets holds expire at day 30 and the runner-up is charged its own price.
- Real probe G3 (in progress, day 0 is 7 Nov 2026 03:06 UTC): day 0 tries an immediate reauthorize on a fresh authorization and creates three authorizations. At 3.5, 4 and 5 days (10 Nov 15:06, 11 Nov 03:06, 12 Nov 03:06 UTC) it reads one, tries a 1.00 partial capture, tries a reauthorize and reads again. No result is recorded yet.
What GAVEL does about it
At settlement start, a hold older than GAVEL_HOLD_MAX_AGE_MS (default 2 hours) is flagged stale and one stale_hold audit row is written. It is a flag only: the hold is still captured. It tells an operator that a hold has aged.
What gate G3 tests
G3 asks: how long does an authorization stay capturable, and does reauthorize extend it? The probe in packages/payments/gates/g3.ts runs from the gate-g3 workflow:
Day 0
A headless browser signs in as the sandbox buyer and approves four orders. One fresh authorization gets an immediate reauthorize attempt (its error name is recorded) and is voided. Three others are kept, one per checkpoint, and the creation time is saved in the probe state.
Checkpoints at 3.5, 4 and 5 days
Scheduled runs (minute 17 of every sixth hour) pick the saved state up. At each checkpoint that is due, the probe reads the authorization, tries a 1.00 partial capture (not final), tries a reauthorize, and reads again. With day 0 at 7 Nov 03:06 UTC, the checkpoints are due on 10 Nov 15:06, 11 Nov 03:06 and 12 Nov 03:06 UTC.
The decision
decideG3 applies a fixed rule once the three checkpoints are done:
| Observation | Decision | Consequence |
|---|---|---|
| all three captures succeed | PASS | no reauthorization needed; keep the stale flag |
| a capture fails and a reauthorize works | PASS-WITH-FALLBACK | enable reauthorization |
| a capture fails and no reauthorize works | FAIL | create holds minutes before capture and document it |
The state travels between runs as an artifact; the final run writes the GATES.md entry. There is also an early reading of two older G2 authorizations (gate-g3-early.yml); no result from it is recorded in GATES.md.
What the simulation shows, and what it does not
SIMULATED Scenarios S2 to S5 of the 30 day simulation run GAVEL's own code over simulated days against the fake PayPal model, with a fake clock: a capture inside the honor period needs no reauthorization (S2); a capture at day 3.5 works with reauthorization and charges nobody without it (S3); a reauthorization at day 3.04 lets a capture at day 5 succeed (S4); holds never reauthorized expire cleanly and the runner-up is charged its own price (S5). The ledger balances to the cent in each.
That shows GAVEL behaves correctly if PayPal follows the model. It says nothing about whether PayPal does; G3 is the check. See the simulation and Gates.
Prop
Type
Where this lives in the code
- packages/payments/src/saga/reauth.tspolicy, request ids and persistence of a reauthorization
- packages/server/src/runtime/auction-service.tsreauthorizeDue: runs before the capture when the policy is on
- packages/payments/src/holds/recover.tsthe stale flag
- packages/payments/src/fake/core.tsthe model: honor period, validity, reauthorize
- packages/payments/src/fake/ASSUMPTIONS.mdA07 to A11, unverified
- packages/payments/gates/g3.tsthe real probe
- packages/payments/gates/g3-timed.tscheckpoints and decideG3
- .github/workflows/gate-g3.ymlday 0 and the scheduled checkpoints
- docs/evidence/SIM/SIM-MULTIDAY.mdthe simulated scenarios
Last updated on