Preserve typed provider failures for central admission and provenance #674
Loading…
Reference in a new issue
No description provided.
Delete branch "fix/anima-a1-provider-outcomes"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Preserve typed provider failures/reset provenance through model boundaries so central admission can use exact account/model windows without polling providers.
Targets main. Supplies Q1 #795 and the compatibility floor for the stack. No PR merge, deployment, live recovery or canary.
Review fixes
Reset tests now reach the actual backoff branch: no Retry-After plus named5s reset waits at least5s before a second send; named2h reset with1s deadline rejects after one send. Configured identities match Anima's
[A-Za-z0-9_.:/-]{1,128}grammar. Usage-limit rejection never retries locally; missing identity decodes as unknown. This PR also supplies the metadata-tolerant reader rollback floor required by #677/#678; unknown control events still fail closed.Exact consumer contract
Model failure v1 (A1; Anima Q1/S3)
RuntimeJob.errorandTurnRecord.errorretain their existingFault.codeandmessage. An optionalmodel_failurefield carries sanitized model-boundaryobservations. It is omitted for legacy/non-model faults; missing values are
unknown, never zero, and this contract grants no authority to replay work.
Required metadata fields:
schema_version:1andcause. The cause vocabulary israte_limit,usage_limit,context_limit,output_limit,deadline,cancelled,transport,provider_error,incomplete. Optional fields arehttp_status:u16,retry_after_secs:u64,provider_code:string,provider_type:string,provider_request_id:string,finish_reason:string,attempts:u32.Provider identifiers and finish reasons allow ASCII alphanumeric,
_,-,.and at most 128 characters. No raw provider body or prompt enters metadata.
retry_after_secsis present only for numeric Retry-After in 0..=30. It preservesthe final rejection's header even at attempt three; it does not request another
retry. No header means absent metadata, despite the runtime's local 1s/2s default
backoff. Invalid, HTTP-date or >30s headers stop local retry and remain absent.
Only explicit HTTP 429 responses can retry, at most three sends. Cancellation
and the enclosing turn deadline still interrupt sends, reads and backoff. Partial
streams, transport ambiguity and tools are not retried. HTTP
lengthfinish mapsto
output_limit; explicit context-refusal codes map tocontext_limit; missingfinish/DONE stays
incomplete. A native finish reason never invents HTTP status,request identity or a provider attempt count. Legacy model-boundary lifecycle
codes remain
model_incomplete/model_cancelledso continuation reconciliationand operator fences retain their semantics.
Consumers should first parse the optional typed metadata, retain their exact
legacy structured-error parser, and preserve unknown fields/versions as unknown.
A1 supplies classification for Q1's durable admission cooldown; per-call usage,
actual model revision and context/elision provenance are separate A3/S3 work.
Source evidence is
analysis-anima-3w/synthesis.mdE02/E04/E06, not a deploymentor historical provider-model attestation. Deployment and authorized canary pending.
Durable usage-limit windows (operator extension)
Rate/usage rejections also carry optional
model_failure.limit:All five members are present.
kindisrequests|tokens|monthly_usage|null;reset_at_msis nullable absolute UTC Unix milliseconds, including long waits;reset_sourceis nullable{kind:header|body,name:string}.identityhas nullableprovider,account,model. Provider uses explicitModelEndpoint.provider_identityor endpoint DNS host, account only explicit opaque
account_identity, model theexact request binding. Configured identities are validated, never sanitized into
another value. No credential, token digest, default account or model alias is
substituted. An endpoint proxy host identifies that endpoint, not its hidden backend.
Supported sources: Retry-After integer seconds or HTTP-date; named
x-ratelimit-reset[-requests|-tokens|-project-requests|-project-tokens] in compound
durations (including ms), Unix epoch seconds/milliseconds or RFC3339; Anthropic
request/token/input-token/output-token reset RFC3339 headers. Header names retain
the selected canonical name from the HTTP library. Positive matching remaining
counts exclude unexhausted windows. Among exhausted or unknown windows and body
fields, select the latest valid reset conservatively, with its exact source/kind.
Body allowlist:
/error/or rootreset_at_ms,reset_at,resets_at,retry_after,retry_after_seconds,retry_after_ms; source name is its JSONpointer. Only explicit
limit_kind/limit_type,monthly_usage_limitcode, or literalmonthly usage limitwording establish body kind. An unrelated namedrequest/token window is excluded when the body names a different limit kind.
Malformed/ambiguous values remain null.
insufficient_quotayieldsusage_limitbut does not establish a monthly quota. Historical records remain unknown.
The legacy
retry_after_secsremains independently bounded to numeric <=30.Local sends retain the explicit-429 three-attempt policy. A known reset extends
backoff (never earlier than reset); if this exceeds 30s or remaining turn deadline,
return the original typed rejection immediately, rather than consuming the deadline.
Invalid/date/>30 Retry-After still stops local retry, while its parsed reset is
available to durable central admission. No rate/usage endpoint is queried.
Header format references: OpenAI rate limits,
Claude rate limits.
Review refinements: configured identities use
[A-Za-z0-9_.:/-]{1,128}, matching Anima (no @). Missing limit identity defaults to all unknown. UsageLimit stops on the first rejection even without a reset; transient rate limits retain the three-send bound. ModelEndpoint uses deny_unknown_fields: rollback must also restore the older profile configuration before starting the older runtime.Runtime/session readers in this compatibility release skip future model_observation/context_transform/turn_usage metadata when unsupported, while unknown control events still fail closed. This is the minimum rollback floor for the telemetry stack; binaries predating this floor require a pre-upgrade store/config snapshot, not an in-place rollback.
Validation
Fable Round2 approved reviewed head
b79e50adb8d3. Current follow-up head:b2452e081e25604a5ce76da103075d7bfeef5b15.The beyond-deadline case uses a20s named-header reset and10s deadline: ordinary1s retry spacing <10s deadline <20s reset <30s local cap. It asserts one send, typed requests limit, exact header provenance and immediate return before the deadline. This isolates the remaining-deadline check; the5s in-deadline reset still waits and retries successfully.
Current-head focused reset test:1 passed (r2-followup-a1.log). Final integrated #678 suite115 passed/1 existing real-backend ignored. Full exact-head Solstice CI remains a merge gate; local results do not substitute for it. No merge, force-push, deployment or canary.
Finished task target was reclaimed after verifying no open files;37.08GiB free at10:16Z. Peer target preserved.