feat: coverage V2 - historical evidence miner, KB evidence model + promotion audit + revalidation, Kodebar/OSCBR limits, KB/provider panel, seed import; 1.3.2 (Hub only)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
gti
2026-09-26 08:14:57 -03:00
co-authored by Claude Sonnet 5
parent 19e145ea47
commit ac1ecccc50
41 changed files with 1418 additions and 74 deletions
+18 -4
View File
@@ -79,7 +79,7 @@ class QuotaManager:
return row
# ---- decision ----------------------------------------------------------------------------------------------------------------------------------
def allow(self, provider: Provider) -> tuple[bool, str | None, datetime | None]:
def allow(self, provider: Provider, purpose: str = "OPERATIONAL", reserve_percent: int = 0) -> tuple[bool, str | None, datetime | None]:
state, now = self.state(provider), self.now()
if not provider.configured:
return False, "NOT_CONFIGURED", None
@@ -91,6 +91,12 @@ class QuotaManager:
if provider.daily_limit and usage.requests >= provider.daily_limit and state.quota_kind != "REMOTE_QUOTA":
state.status = "RATE_LIMITED"
return False, "RATE_LIMITED", state.reset_at and _aware(state.reset_at) or next_utc_midnight(now)
if purpose == "BACKFILL" and provider.daily_limit: # backfill may only use what is left above the operational reserve
used = usage.requests
if state.quota_kind == "REMOTE_QUOTA" and state.remaining is not None:
used = provider.daily_limit - state.remaining
if used >= provider.daily_limit * (100 - reserve_percent) / 100:
return False, "OPERATIONAL_RESERVE", state.reset_at and _aware(state.reset_at) or next_utc_midnight(now)
window = (provider.burst[1] if provider.burst else 60)
limit = (provider.burst[0] if provider.burst else provider.rate_per_minute)
if limit:
@@ -123,6 +129,10 @@ class QuotaManager:
usage.success += 1
if not result.found:
usage.not_found += 1
else:
usage.found += 1
if result.ncm:
usage.ncm_found += 1
state.consecutive_failures = 0
state.circuit_open_until = None
state.status = "ONLINE"
@@ -147,7 +157,7 @@ class QuotaManager:
usage.rate_limited += 1
state.status = "RATE_LIMITED"
wait = timedelta(seconds=error.retry_after) if error.retry_after else None
state.circuit_open_until = now + (wait or (state.reset_at and max(timedelta(minutes=5), _aware(state.reset_at) - now) or timedelta(minutes=15)))
state.circuit_open_until = now + (wait or (state.reset_at and max(timedelta(minutes=15), _aware(state.reset_at) - now) or timedelta(minutes=60)))
if state.reset_at is None:
state.reset_at = state.circuit_open_until
elif error.kind == "AUTH_ERROR":
@@ -165,6 +175,10 @@ class QuotaManager:
state.status = "OFFLINE"
self.session.commit()
def record_kb_hit(self):
"""A resolution answered by the KB alone (no provider asked): counted once per day under the pseudo-provider 'kb'."""
self.usage("kb").kb_hits += 1
def record_cache(self, provider_name: str, hit: bool):
usage = self.usage(provider_name)
if hit:
@@ -200,7 +214,7 @@ class ProviderGateway:
row.found, row.data, row.fetched_at, row.expires_at = product.found, data, now, now + ttl
self.session.commit()
def lookup(self, provider: Provider, gtin: str) -> Outcome:
def lookup(self, provider: Provider, gtin: str, purpose: str = "OPERATIONAL", reserve_percent: int = 0) -> Outcome:
hit = self._cached(provider, gtin)
if hit is not False:
self.quota.record_cache(provider.name, True)
@@ -216,7 +230,7 @@ class ProviderGateway:
self.session.commit()
return Outcome(provider.name, "CACHE_HIT", hit or None, from_cache=True) if hit else Outcome(provider.name, "NOT_FOUND", None, from_cache=True)
self.quota.record_cache(provider.name, False)
ok, reason, retry_at = self.quota.allow(provider)
ok, reason, retry_at = self.quota.allow(provider, purpose, reserve_percent)
if not ok:
self.session.commit()
return Outcome(provider.name, "SKIPPED", None, reason, retry_at)