hermes: retain dual-provider quota health
Some checks failed
Tests / Declarative: Post Actions failed: 39, skipped: 19, passed: 2757

This commit is contained in:
jenkins 2026-08-23 02:52:42 -03:00
parent 81b3e6b992
commit fe7832efaf
4 changed files with 44 additions and 3 deletions

View File

@ -25,7 +25,7 @@ spec:
ai.bstein.dev/execution: Hermes Kanban with durable direct Codex and Claude Code CLI workers ai.bstein.dev/execution: Hermes Kanban with durable direct Codex and Claude Code CLI workers
ai.bstein.dev/model-policy: Jetson-assisted AUTO routing, low through xhigh, cross-provider fallback ai.bstein.dev/model-policy: Jetson-assisted AUTO routing, low through xhigh, cross-provider fallback
ai.bstein.dev/placement: rpi5 preferred; Jetson deferred until state storage is available ai.bstein.dev/placement: rpi5 preferred; Jetson deferred until state storage is available
ai.bstein.dev/config-rev: "20260823-claude-quota-headers" ai.bstein.dev/config-rev: "20260823-dual-provider-quota-health"
prometheus.io/scrape: "true" prometheus.io/scrape: "true"
prometheus.io/path: /metrics prometheus.io/path: /metrics
prometheus.io/port: "9010" prometheus.io/port: "9010"
@ -1037,6 +1037,7 @@ spec:
- {name: ATLAS_AI_CLAUDE_OAUTH_TOKEN_FILE, value: /claude-oauth-access/token} - {name: ATLAS_AI_CLAUDE_OAUTH_TOKEN_FILE, value: /claude-oauth-access/token}
- {name: ATLAS_AI_CLAUDE_QUERY_TIMEOUT_SECONDS, value: "30"} - {name: ATLAS_AI_CLAUDE_QUERY_TIMEOUT_SECONDS, value: "30"}
- {name: ATLAS_AI_CLAUDE_QUOTA_MODEL, value: claude-haiku-4-5-20251001} - {name: ATLAS_AI_CLAUDE_QUOTA_MODEL, value: claude-haiku-4-5-20251001}
- {name: ATLAS_AI_AUTHENTICATION_GRACE_SECONDS, value: "1200"}
- {name: ATLAS_AI_PROVIDER_HEALTH_ROOT, value: /provider-health} - {name: ATLAS_AI_PROVIDER_HEALTH_ROOT, value: /provider-health}
- {name: ATLAS_AI_USAGE_INTERVAL_SECONDS, value: "300"} - {name: ATLAS_AI_USAGE_INTERVAL_SECONDS, value: "300"}
- {name: ATLAS_AI_USAGE_PORT, value: "9010"} - {name: ATLAS_AI_USAGE_PORT, value: "9010"}

View File

@ -21,6 +21,10 @@ import ai_usage_polling as polling_engine
PROVIDER_HEALTH_ROOT = Path( PROVIDER_HEALTH_ROOT = Path(
os.environ.get("ATLAS_AI_PROVIDER_HEALTH_ROOT", "/provider-health") os.environ.get("ATLAS_AI_PROVIDER_HEALTH_ROOT", "/provider-health")
) )
AUTHENTICATION_GRACE_SECONDS = max(
60,
int(os.environ.get("ATLAS_AI_AUTHENTICATION_GRACE_SECONDS", "1200")),
)
CLAUDE_WINDOWS = ( CLAUDE_WINDOWS = (
"five_hour", "five_hour",
"seven_day", "seven_day",
@ -331,6 +335,10 @@ class Collector:
state = self._providers[provider] state = self._providers[provider]
state.last_attempt = started state.last_attempt = started
state.duration = time.monotonic() - monotonic_started state.duration = time.monotonic() - monotonic_started
# A successful first-party quota request is direct authentication
# proof. Broker health files may be quiet when no routed model call
# has occurred recently, so they must not demote this live result.
state.authenticated = True
state.fetch_success = True state.fetch_success = True
state.samples = samples state.samples = samples
state.last_success = time.time() state.last_success = time.time()
@ -342,8 +350,15 @@ class Collector:
provider: ProviderState(**vars(state)) provider: ProviderState(**vars(state))
for provider, state in self._providers.items() for provider, state in self._providers.items()
} }
now = time.time()
for provider, state in states.items(): for provider, state in states.items():
state.authenticated = _provider_authenticated(provider) quota_proves_access = (
state.last_success > 0
and 0 <= now - state.last_success <= AUTHENTICATION_GRACE_SECONDS
)
state.authenticated = (
_provider_authenticated(provider) or quota_proves_access
)
samples: list[Sample] = [] samples: list[Sample] = []
for provider, state in states.items(): for provider, state in states.items():
labels = {"provider": provider} labels = {"provider": provider}

View File

@ -263,9 +263,10 @@ def test_manifest_rolls_out_the_bounded_codex_deadline_and_poller_module():
environment = {item["name"]: item["value"] for item in exporter["env"]} environment = {item["name"]: item["value"] for item in exporter["env"]}
assert annotations["ai.bstein.dev/config-rev"] == ( assert annotations["ai.bstein.dev/config-rev"] == (
"20260823-claude-quota-headers" "20260823-dual-provider-quota-health"
) )
assert environment["ATLAS_AI_CODEX_QUERY_TIMEOUT_SECONDS"] == "45" assert environment["ATLAS_AI_CODEX_QUERY_TIMEOUT_SECONDS"] == "45"
assert environment["ATLAS_AI_AUTHENTICATION_GRACE_SECONDS"] == "1200"
assert environment["ATLAS_AI_CLAUDE_OAUTH_TOKEN_FILE"] == ( assert environment["ATLAS_AI_CLAUDE_OAUTH_TOKEN_FILE"] == (
"/claude-oauth-access/token" "/claude-oauth-access/token"
) )

View File

@ -209,6 +209,28 @@ def test_provider_authentication_uses_only_fresh_non_secret_health(tmp_path, mon
assert not mod._provider_authenticated("anthropic") assert not mod._provider_authenticated("anthropic")
def test_recent_quota_success_keeps_access_healthy_when_broker_snapshot_is_quiet(
monkeypatch,
):
mod = load_module()
collector = mod.Collector()
collector._providers["openai"].last_success = 1_000
monkeypatch.setattr(mod, "_provider_authenticated", lambda _provider: False)
monkeypatch.setattr(mod.time, "time", lambda: 1_300)
rendered = collector.render().decode()
assert 'atlas_ai_provider_authenticated{provider="openai"} 1' in rendered
monkeypatch.setattr(
mod.time,
"time",
lambda: 1_000 + mod.AUTHENTICATION_GRACE_SECONDS + 1,
)
rendered = collector.render().decode()
assert 'atlas_ai_provider_authenticated{provider="openai"} 0' in rendered
def test_collector_refreshes_both_providers_and_contains_unknown_provider( def test_collector_refreshes_both_providers_and_contains_unknown_provider(
monkeypatch, capsys monkeypatch, capsys
): ):
@ -225,6 +247,8 @@ def test_collector_refreshes_both_providers_and_contains_unknown_provider(
collector.refresh_provider("anthropic") collector.refresh_provider("anthropic")
assert collector._providers["openai"].fetch_success assert collector._providers["openai"].fetch_success
assert collector._providers["anthropic"].fetch_success assert collector._providers["anthropic"].fetch_success
assert collector._providers["openai"].authenticated
assert collector._providers["anthropic"].authenticated
assert collector._providers["openai"].last_success > 0 assert collector._providers["openai"].last_success > 0
collector.record_failure("openai") collector.record_failure("openai")