Conversation
…reg's key Money brakes nothing at $0: the hold is 0 and the daily cap adds 0, so one looping client can spend the shared vendor key's whole quota and every other team's access with it, after which its retries land on the capacity breaker for as long as the vendor holds the key. This is what happened on ContactOut's free availability routes. Any cost block may now declare `calls_per_team_day`, calls per team per UTC day on treg's key. The mechanism is price-agnostic; only the default is not: a `type: free` block that declares none falls back to `TREG_FREE_ALLOWANCE_PER_TEAM_DAY`, while a paid block has an allowance only when it declares one, because money already brakes it. The reservation takes the slot with one conditional upsert of a new `EndpointAllowance` row (revision 0040) in the same transaction, so the gate and the count are one statement, concurrent calls cannot overshoot, and a refused call writes nothing. Admitted attempts count, failures included, because the vendor's own limits count attempts. Fail-closed like the trial pools. A team's own key never meets the gate. The refusal is `429 endpoint_allowance_reached`, audited `refused_by=cap`, so a client retrying against it is a product refusal, not a platform failure. ContactOut's five free routes declare 1,000. Seven discovery and count routes whose legitimate use runs above the default declare higher figures. The validator refuses a figure below 1; `cost_view` shows the effective figure beside every price that carries one so a bare zero never reads as unlimited. Fragments: money.md (the gate), catalog.md (the field), api.md (the refusal), data-model.md, contactout.md, ops/deploy.md; llms.txt, skill.md and the plugin mirrors; AGENTS.md write list; the call-architecture allowlist.
stonexer
force-pushed
the
feat/free-endpoint-allowance
branch
from
September 17, 2026 02:04
791de35 to
83d5fdd
Compare
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.
Why
A
$0catalog endpoint served on treg's key passes every money gate trivially: the hold is 0 and the daily cap adds 0. One looping client can therefore spend the shared vendor key's whole quota and every other team's access with it, after which its retries are refused by the capacity breaker for as long as the vendor holds the key, and each refusal counts as a platform failure on the health dashboard. That is exactly what happened on ContactOut's free availability routes: the vendor rate-limited the shared key, the breaker locked the two endpoints, and the client kept retrying for hours.The trial pools already solve this for three whole-provider
$0rates. Most zeros in the catalog are single free routes on paid providers and had no brake at all.The mechanism is deliberately generic so a paid route can carry the same figure later without a table rename or a new error code; today only free routes need one.
What
cost.calls_per_team_dayon any cost block: calls per team per UTC day on treg's key. The mechanism is price-agnostic; only the default is not: atype: freeendpoint that declares none falls back toTREG_FREE_ALLOWANCE_PER_TEAM_DAY(default 5,000; 0 = no default), while a paid endpoint has an allowance only when it declares one, because money already brakes it. The case for a paid figure is a vendor whose per-key daily quota one team could spend for everyone. In practice the field is expected to live on free routes. The validator refuses any figure below 1._enforce_endpoint_allowanceinapplication.call.reserve, beside the trial allowance, takes the slot inside the reservation transaction with one conditional upsert of a newEndpointAllowancerow (Alembic0040): the WHERE is the check and the SET is the count, so concurrent calls cannot overshoot and a refused call writes nothing. Counted from its own row, never fromcallrecord, because audit rows are shed under load. Admitted attempts count, failures included, because the vendor's limits count attempts. Fail-closed like the trial pools.429 endpoint_allowance_reachedwithprovider,endpoint_id,allowance_per_day,used_today,resets_atand a connect-your-own-key message; auditedrefused_by=cap, so a client retrying against it is a product refusal on the dashboard, not a platform failure. A team's own key never meets the gate (non-negotiable 1); billed OAuth calls, owned async polls and authorized free final fetches skip it.cost_viewattaches the effectivecalls_per_team_daybeside every price that carries one (never beside a trial pool's own field), so a bare zero never reads as unlimited incatalog_getor the web.Tests
tests/test_endpoint_allowance.py: bites at the declared number, unbilled, before the vendor,refused_by=cap; failed attempts count; a refused call writes nothing; exact under 20 concurrent calls; per team; per UTC day; per endpoint not per provider; deployment default, zero default, own figure over default; own key never gated; a paid route is untouched by the default and gated by a declared figure; fail-closed; catalog exposure; validator rules. The call-architecture allowlist gainsendpoint_allowance_slot; alembic head/model parity passes. Full suite green locally.Fragments updated
architecture/money.md(§ The endpoint allowance),architecture/catalog.md(the cost field),interface/api.md(the refusal),architecture/data-model.md,architecture/contactout.md,ops/deploy.md;llms.txt,skill.mdand the generated plugin mirrors;AGENTS.mdwrite list.drift.shalso flagsapollo.yaml,hunter.extended.yamlandleadsforge.yamlas sources with no fragment; that gap predates this PR (only an allowance line changed in each).Deploy notes
Migration
0040is additive. The default applies at once afterpython -m treg upgrade; no environment change is required. Watchrefused_by=caprefusals witherror=endpoint_allowance_reachedafter rollout: a legitimate team hitting the default is the signal to raise that endpoint's YAML figure.