reserve raises NonPositiveEstimate (422) when the worst-case estimate rounds to 0. Because ceil_micro keeps any positive worst case at ≥ 1 micro, estimate == 0 happens only for a zero-token request or a zero-priced (free) model — so a genuinely free model always 4xxs on reserve.
Location: src/tollgate/application/handlers/reserve.py:145-148; src/tollgate/domain/pricing.py (estimate_micro).
Denying a free model is defensible (there is nothing to gate), but it may surprise callers routing free and paid models through the same guard. Filing to confirm intent: deny, admit-with-zero-hold, or document.
reserveraisesNonPositiveEstimate(422) when the worst-case estimate rounds to 0. Becauseceil_microkeeps any positive worst case at ≥ 1 micro,estimate == 0happens only for a zero-token request or a zero-priced (free) model — so a genuinely free model always 4xxs on reserve.Location:
src/tollgate/application/handlers/reserve.py:145-148;src/tollgate/domain/pricing.py(estimate_micro).Denying a free model is defensible (there is nothing to gate), but it may surprise callers routing free and paid models through the same guard. Filing to confirm intent: deny, admit-with-zero-hold, or document.