mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-07 04:12:04 +00:00
A gateway can answer a failed generation with HTTP 200 and put the reason in the body: a top-level `error` object and no `choices`, or `choices[0].error` beside `finish_reason: "error"` when a generation dies mid-flight. Both fell through to the empty-content throw, so a dead credit balance, a data-policy block, a rate limit and a model that is down all recorded the same hop: status 0, reason "returned empty content", no excerpt. Nothing on the provider health card told them apart. Raise the shape a non-2xx reply raises instead, with the gateway's own message leading and its `error.code` as the status when that code is an HTTP error status. The chain classifier, the health ledger and the card then see 402 / 403 / 429 / 503 and treat each of them the way they treat the same status on the wire. Message and excerpt are bounded and key-redacted by the same helper the non-2xx path uses, so remote text is no more trusted here than it is there. Gated on the gateway tag: api.openai.com signals every failure with a status, so the pinned tags parse exactly as before, and a genuine empty reply stays the empty-content throw it was. The local-endpoint provider had the same hole on its buffered path, its buffered-reply fallback and its stream, and gets the same treatment. The body classifier learned the two account-side refusals a gateway words in its own vocabulary rather than the vendor's.