Finalize reliable execution policy decisions
This commit is contained in:
@@ -2,7 +2,9 @@
|
||||
|
||||
**Status:** Feature roadmap; not implemented. This document defines the target
|
||||
end state. A separate implementation plan will supply sequential stages and
|
||||
prompt-level steps after the remaining decisions are resolved.
|
||||
prompt-level steps. The four policy decisions reviewed with the maintainer are
|
||||
settled below; exact API spelling, event field layout, and backoff timing values
|
||||
remain implementation-plan details.
|
||||
|
||||
## Purpose
|
||||
|
||||
@@ -42,13 +44,26 @@ retries. The initial policy uses two additional attempts by default and permits
|
||||
an unambiguous explicit zero to disable them. Initial eligible statuses are
|
||||
429, 500, 502, 503, and 504, not every unsuccessful response or every 5xx status.
|
||||
|
||||
Configure an engine default with a request-scoped retry-count override, using
|
||||
presence to distinguish omission from zero. Keep retry policy out of profile
|
||||
YAML initially. Per-request control supports mixed workflows without requiring
|
||||
separate engines and splitting their capacity pools. Use a modest fixed backoff
|
||||
policy; concrete timing values belong in the implementation plan, not a new
|
||||
public timing-configuration surface.
|
||||
|
||||
- Retry delays use exponential backoff with jitter and honor valid provider
|
||||
`Retry-After` timing. Invalid or absent timing falls back to local policy.
|
||||
`Retry-After` timing as a minimum delay, subject to cancellation, rather than
|
||||
truncating it and retrying too early. Invalid or absent timing falls back to
|
||||
local policy.
|
||||
- Caller cancellation and deadlines interrupt both waiting and active attempts.
|
||||
Cancellation is never itself a reason to retry.
|
||||
- Permanent request failures, malformed successful response envelopes, and
|
||||
structurally invalid generated content do not enter this transient loop.
|
||||
Structural invalidity remains the separate output-repair mechanism.
|
||||
- Transport failures are classified and exposed without automatic replay in
|
||||
this scope. A generic network error does not prove that no billable work
|
||||
occurred. Conservative eligibility reduces ambiguity; even HTTP-status
|
||||
retries do not promise zero duplicate billing.
|
||||
- Retry one resolved generation request: retain its messages, model, endpoint,
|
||||
settings, structured-output constraint, and resolved credential throughout
|
||||
that retry sequence. Do not rerender or reload application sources between
|
||||
@@ -70,6 +85,14 @@ provider attempts for that execution is (R + 1) × (P + 1). Cancellation and
|
||||
non-retryable failures can reduce that count. Application-owned semantic retries
|
||||
are separate executions and may multiply it further.
|
||||
|
||||
Existing generation/HTTP timeouts remain per-attempt limits. The caller's
|
||||
context bounds the complete operation, including capacity waiting, retry delays,
|
||||
and repair; its deadline is never reset between attempts. Callers needing a
|
||||
total time budget must provide a deadline, since multiple attempts can exceed
|
||||
one attempt's timeout. An expired caller deadline ends the run rather than
|
||||
starting another attempt. This preserves existing transport-setting semantics
|
||||
without adding a competing total-timeout setting.
|
||||
|
||||
### Shared Capacity, Not A Second Scheduler
|
||||
|
||||
Every actual generation attempt, including retries and repair, participates in
|
||||
@@ -110,6 +133,14 @@ Provide an optional request-scoped observer through the public facade. It receiv
|
||||
metadata about an execution without requiring a logging or metrics framework.
|
||||
Promptkit does not retain a global execution history or persist reports.
|
||||
|
||||
Deliver callbacks synchronously and in order within an execution. Concurrent
|
||||
executions may invoke a shared callback concurrently. Do not invoke consumer
|
||||
code under capacity-manager locks or add a background delivery queue. Callbacks
|
||||
cannot return execution-policy errors; consumers keep them fast and handle their
|
||||
own reporting failures. Panics follow ordinary injected-code behavior rather
|
||||
than being silently swallowed. This keeps delivery straightforward without
|
||||
buffering, dropping, or shutdown machinery; slow callbacks can still delay a run.
|
||||
|
||||
The observable lifecycle covers successful execution, completed invalid output,
|
||||
and operational failure, including failures before any model call. Expose only
|
||||
identities available at that point; do not invent selected profiles or backends
|
||||
@@ -187,66 +218,3 @@ failover, streaming/tool support, telemetry dependency, persistent run store,
|
||||
or additional content-retention facility. Existing fallback-profile behavior
|
||||
is not repurposed as runtime provider failover. Licensing is already complete
|
||||
in source and is not a further implementation dependency.
|
||||
|
||||
## Open Decisions
|
||||
|
||||
Resolve these before making the companion implementation plan decision-complete.
|
||||
API spelling and event field layout also belong in that plan.
|
||||
|
||||
### Retry Configuration And Timing
|
||||
|
||||
**Recommendation:** An engine default with a request-scoped retry-count override,
|
||||
using presence to distinguish omission from zero. Keep policy out of profile
|
||||
YAML initially. Use a modest fixed exponential backoff policy with jitter;
|
||||
select concrete timing values in the plan. Treat valid `Retry-After` as a minimum
|
||||
delay subject to cancellation rather than truncating it and retrying too early.
|
||||
This supplies normal defaults and per-operation control without another profile
|
||||
inheritance dimension.
|
||||
|
||||
**Alternative:** Engine-only retry configuration is smaller but makes mixed
|
||||
single-attempt and retrying workflows require separate engines, splitting their
|
||||
capacity pools. A richer public timing policy is viable for consumer tuning but
|
||||
adds a broader contract before there is demonstrated need.
|
||||
|
||||
### Transport-Failure Eligibility
|
||||
|
||||
**Recommendation:** Initially retry only the selected HTTP statuses, and expose
|
||||
transport failures for consumer handling without automatic replay. This avoids
|
||||
pretending a generic network error proves that no billable work occurred.
|
||||
|
||||
**Alternative:** Include a narrow documented set of transient transport failures.
|
||||
This recovers more outages but requires precise classification, testing, and
|
||||
clear duplicate-work warnings. Even HTTP-status retries do not promise zero
|
||||
duplicate billing; conservative eligibility only reduces ambiguity.
|
||||
|
||||
### Timeout Scope
|
||||
|
||||
**Recommendation:** Keep existing generation/HTTP timeouts as per-attempt limits;
|
||||
the caller's context bounds the complete operation, including capacity waiting,
|
||||
retry delays, and repair. Do not reset the caller's deadline between attempts.
|
||||
This preserves the meaning of the existing transport settings and avoids adding
|
||||
another competing total-timeout setting. Document that callers needing a total
|
||||
time budget must provide a deadline; multiple attempts can exceed one attempt's
|
||||
timeout. An expired caller deadline ends the run, never starts another attempt.
|
||||
|
||||
**Alternative:** Apply the configured generation timeout across an entire retry
|
||||
sequence. This provides a tighter aggregate bound without caller changes, but
|
||||
reinterprets an existing setting and gives later attempts less time following
|
||||
capacity contention or provider-directed delays. It also needs a clear boundary
|
||||
between separate repair generations and their retry sequences.
|
||||
|
||||
### Observer Delivery
|
||||
|
||||
**Recommendation:** Synchronous callbacks, ordered within an execution, with
|
||||
concurrent invocations possible across executions sharing a callback. Do not
|
||||
invoke consumer code under capacity-manager locks or add a background delivery
|
||||
queue. Callbacks cannot return execution-policy errors; callers keep them fast
|
||||
and handle their own reporting failures. Panics follow ordinary injected-code
|
||||
behavior rather than being silently swallowed. This minimizes machinery and
|
||||
makes delivery timing understandable; slow callbacks can still delay a run.
|
||||
|
||||
**Alternative:** Return a separate execution report on both success and failure.
|
||||
This avoids callback latency but requires a broader result/error API and retains
|
||||
attempt history internally. Async delivery offers isolation but introduces
|
||||
buffering, dropping, shutdown, and completion semantics disproportionate to the
|
||||
current need.
|
||||
|
||||
Reference in New Issue
Block a user