Repository navigation
RFC: run-scoped usage, budget, and cancellation controls for AgentOptimizer (OptimizationRunContext + OptimizerCapabilities) #6357
Description
Summary
Optimizer-owned model calls are currently opaque to callers: AgentOptimizer.optimize(initial_agent, sampler) accepts no per-run control, exposes no usage ledger, no cancellation signal, and no capability declaration. Governance wrappers (quality flywheels, budget-enforced CI optimization, cost-attributed experimentation) cannot observe or stop the model calls the optimizer itself makes.
This RFC proposes the smallest additive seam: an optional run-scoped OptimizationRunContext on optimize(...), instrumentation of SimplePromptOptimizer and GEPARootAgentPromptOptimizer, and conservative OptimizerCapabilities defaults for every optimizer so a wrapper can fail preflight instead of discovering opacity after spend.
Target reviewed: main at 9d306f5 (2026-07-10). Downstream consumer with a pinned contract waiting on this seam: GoogleCloudPlatform/BigQuery-Agent-Analytics-SDK#318.
Why the current surface is not enough
SimplePromptOptimizercallsBaseLlm.generate_content_async()directly per candidate;LlmResponse.usage_metadatais available but discarded.GEPARootAgentPromptOptimizer/GEPARootAgentOptimizerown their reflection LLM callable and discard reflection usage;max_metric_callsbounds sampler evaluations, not reflection calls or tokens.RunConfig.max_llm_callsis enforced insideInvocationContext, but optimizer reflection bypasses Runner/InvocationContext; reusing it would mean manufacturing sessions and callback contexts for a non-agent workload.- OTel spans alone are observational: they cannot reject an opaque optimizer at preflight or stop the next logical model invocation on budget exhaustion.
- Related but separate: GEPA optimizer crashes with KeyError on failed eval cases #6004 (score coverage / GEPA
KeyError) and fix(eval): wire App.plugins / context-cache / resumability through adk eval #5534 (App plugin plumbing foradk eval, which leavescli_optimizeas follow-up). Neither addresses optimizer-owned call observability; this RFC does not change sampler/evaluator telemetry, which belongs to the supplied sampler/Runner.
Proposed contract (names directional)
Public shape
Existing callers pass nothing and remain observationally equivalent:
await optimizer.optimize(initial_agent, sampler)Governed callers may supply a one-shot context:
await optimizer.optimize(
initial_agent,
sampler,
run_context=run_context,
)The context attaches to exactly one optimization. Reuse or concurrent attachment is rejected. An unsupported-optimizer preflight happens before attachment, so a typed unsupported rejection does not consume the context.
OptimizationRunContext — control and audit state
The context owns a concurrency-safe, run-local ledger of logical BaseLlm.generate_content_async() invocations. It records control-plane metadata only; no prompt or response content is retained.
Call admission is one atomic operation: check cancellation, reserve the logical-call slot, assign the sequence ID, and create the ledger entry. A preflight rejection is not a call event.
Per-call fields:
- invocation ID/sequence and extensible stage string (initial values:
candidate_generation,reflection); - requested model and returned model version;
- start/end time;
- call status:
completed|provider_error|cancelled; - sanitized provider error code / exception type when present;
- provider-reported prompt / output / reasoning / cached / tool-use / total tokens when present; and
- usage coverage:
verified(provider suppliedtotal_token_count) |partial(some counters, no authoritative total) |unreported(none). Missing values staynull— never coerced to zero.
The final immutable snapshot separately records run-level state:
- run status:
completed|budget_exceeded|cancelled|failed; - configured limits and usage-coverage summary;
- reported-token budget status:
within_limit|exceeded|indeterminate; - the invocation ID that triggered a budget stop, when applicable; and
- cancellation reason / terminal error metadata.
This separation preserves the fact that the charged call which crosses a reported-token limit completed successfully even though the run subsequently terminates for budget_exceeded.
Budgets and truthful coverage
Logical-call limits are hard. The slot is reserved atomically before the provider call begins, so exactly the configured number of optimizer-owned logical calls can start. Provider/transport retries inside one BaseLlm.generate_content_async() invocation are not claimed as separate calls.
Token limits apply to authoritative provider-reported totals. Token totals commit after a terminal response. If cumulative verified total_token_count crosses max_provider_reported_tokens, the completed call is committed first and the run terminates. This is deliberately not described as a hard bound on billing or physical tokens: if any call is partial or unreported, actual-token compliance is indeterminate even when all known totals are below the configured limit. Downstream policy may fail closed on that state.
Terminal behavior is configurable: on_budget_exceeded: "raise" | "return_partial" (default "raise"). Both modes stop scheduling immediately: a logical-call preflight rejection starts no call, while a reported-token overshoot stops after the triggering in-flight call settles.
"raise"raisesOptimizationBudgetExceeded(snapshot)."return_partial"returns only the best result accepted before termination. The caller-owned context snapshot remains the authoritative marker withrun_status="budget_exceeded"; the existingOptimizerResultschema is unchanged.
For SimplePromptOptimizer, a partial result has overall_score=None unless a validation score had already completed; budget termination never schedules a final validation solely to populate the score. For GEPA, a partial result contains only the previously committed state/frontier, never a half-proposed candidate. An over-budget run can never carry run_status="completed".
Provider errors
With no context, existing optimizer behavior is unchanged. With a context, both raised provider exceptions and in-band LlmResponse.error_code responses commit the call as provider_error, preserve any reported usage, finalize the snapshot as failed, and terminate with a typed OptimizationProviderError(snapshot, error_code). A governed run cannot silently return success after an optimizer-owned provider error.
Cancellation and worker lifecycle
Cancellation is explicit and cooperative: thread-safe idempotent request_cancel(reason), observed before and after each optimizer-owned logical model invocation, before a GEPA sampler call is scheduled, immediately after an in-flight sampler future settles, and through a context-backed GEPA stopper.
In-flight provider/sampler operations are allowed to settle. Context-requested cancellation ends with OptimizationCancelledError(snapshot). Native task cancellation requests the same cooperative stop, shields and drains the GEPA executor future to its next boundary, then re-raises asyncio.CancelledError. A normal GEPA stopper return is post-checked so it cannot masquerade as success.
The no-orphan guarantee is conditional on the active provider/sampler operation eventually reaching a cancellation boundary; cooperative cancellation is not a time-bounded kill mechanism. A caller watchdog may request cooperative cancellation at a soft deadline and wait for a bounded grace period. If the grace period expires, the caller may abandon the wait, but then ADK cannot also guarantee that the still-blocked executor worker was drained. An absolute wall-clock bound requires provider/sampler timeouts or process isolation; native task cancellation alone cannot forcibly terminate an arbitrary blocked provider call or Python executor thread.
GEPA 0.1.x adaptation
GEPA checks stop callbacks between iterations, which is too late by itself to prevent candidate evaluation after a reflection call crosses the reported-token limit. The ADK adapter therefore uses this sequence:
- commit the completed reflection call and set the context terminal request;
- raise a private ADK iteration-abort sentinel from the reflection callable;
- allow GEPA 0.1.x to convert that reflection failure into no proposal;
- have the context-backed stopper end the run at the next loop boundary; and
- post-check the context after
gepa.optimize()returns, mapping it toraiseor the previously committed partial frontier.
Optional-dependency types and the sentinel stay private to the adapter. A regression test must prove that no sampler call is scheduled after the triggering reflection invocation commits.
OptimizerCapabilities — conservative and granular by default
Non-abstract instance property on AgentOptimizer, with all support flags defaulting to false:
accepts_run_context;optimizer_calls_observable;logical_call_limit_enforced;reported_token_limit_enforced;cooperative_cancellation; andsampler_usage_included(alwaysfalsein this RFC — sampler/Runner accounting belongs to the supplied sampler).
Callers must omit the run_context keyword entirely when accepts_run_context is false; this preserves runtime compatibility with existing third-party optimizer implementations whose override still has the old two-argument signature.
SimplePromptOptimizer and GEPARootAgentPromptOptimizer opt into the supported capabilities. GEPARootAgentOptimizer accepts the keyword only to issue a typed unsupported error before attachment or work; its capabilities remain false until the 2.4 root/skill surface is instrumented as a fast-follow. Third-party optimizers inherit unsupported defaults untouched.
Delivery
The in-memory ledger and final immutable snapshot are the only delivery mechanisms in the first implementation. The snapshot is readable from the caller-owned context on success and failure, so a wrapper can persist the complete attempt in finally.
Explicit non-goals for ADK
Price catalogs, currency estimates, storage/BigQuery writes, promotion policy, holdout governance, incumbent registries, sampler/Runner usage accounting, and a hard wall-clock/thread-kill mechanism are downstream or separate concerns. This seam observes and stops optimizer-owned calls; nothing more.
Implementation plan — one RFC, two independently reviewable stacked PRs
- PR 1 — contracts:
OptimizationRunContext, immutable snapshots, typed terminal exceptions, granularOptimizerCapabilities, and optional keyword-onlyoptimize(...)plumbing (newoptimization/run_context.py+ minimal touch toagent_optimizer.pyand built-in signatures). Additive only; no optimizer enforcement behavior yet. Stack PR 2 immediately so the contract is reviewed with a concrete consumer rather than as dead API. - PR 2 — enforcement: instrument
SimplePromptOptimizerandGEPARootAgentPromptOptimizer; implement atomic logical-call admission, normalized usage coverage, provider-error handling, the GEPA sentinel/stopper/post-check bridge, sampler-boundary cancellation checks, and executor shielding/drain; keep root/skill optimizer capabilities conservative.
The two PRs must collectively prove:
- the no-context path is observationally equivalent in call order, results, exceptions, and existing serialization;
- an old third-party optimizer override is never passed
run_contextafter capability preflight; - exact atomic logical-call limits, with provider retries explicitly out of scope;
- reported-token overshoot commits then terminates in both
raiseandreturn_partialmodes; - verified / partial / unreported classification, no zero coercion, and
indeterminatecompliance when coverage is incomplete; - call status remains
completedwhile the run status becomesbudget_exceededfor the triggering successful call; - partial Simple results never run post-stop validation and partial GEPA results expose only the prior committed frontier;
- raised and in-band provider errors preserve usage and cannot return governed success;
- context-requested and native cancellation cross the GEPA executor bridge, with the executor future shielded/drained once the in-flight operation reaches a boundary;
- no sampler work is scheduled after a reflection overshoot commits;
- context one-shot, pre-cancel, unsupported-preflight, reuse, concurrent-attachment, and atomic-call-admission behavior; and
- stopper/callback adaptation against both the declared minimum
gepa==0.1.0and the latest version admitted by ADK's unboundedgepa>=0.1dependency. If that matrix is not sustainable, define and test an upper bound.
Questions for maintainers
- Optional keyword-only context on
optimize(...)(recommended for per-run state), or constructor injection for built-in optimizers? OptimizerCapabilitiesas an instance property (recommended — support can depend on model/config), or class-level?- Is normalized-only usage (
input/output/reasoning/cached/tool_use/total+ coverage) the right experimental v1, leaving raw provider metadata out until a consumer proves need? - Is the caller-owned final snapshot an acceptable authoritative terminal marker for
return_partial, preserving the existingOptimizerResultschema, or would maintainers prefer a context-aware outcome wrapper?
Related follow-ups, not acceptance dependencies
- GEPA optimizer crashes with KeyError on failed eval cases #6004 should independently define exact score coverage as a
Samplerpostcondition or replace the raw GEPAKeyErrorwith a typed incomplete-result failure. No answer is required to accept or implement this RFC. - fix(eval): wire App.plugins / context-cache / resumability through adk eval #5534 covers App plumbing for
adk eval;cli_optimizeApp/plugin parity remains a separate follow-up. - Instrumenting
GEPARootAgentOptimizeris a fast-follow after the prompt-surface contract proves stable.
Definition of done
A caller can run either instrumented optimizer with an optional one-shot context; receive honest, granular capabilities for supported and unsupported optimizers; reconcile every ADK-owned logical model invocation with provider-reported usage when available; distinguish verified token-limit compliance from indeterminate coverage; terminate deterministically on logical-call or reported-token overshoot in either configured mode; stop cooperatively and drain GEPA's worker once the active provider/sampler operation reaches a boundary; and read the final immutable ledger snapshot on success or failure — with observationally equivalent behavior for existing no-context callers and no new required dependencies.
Activity
caohy1988 commentedon Jul 10, 2026
Fresh review — contract is sound after one precision pass
Verdict: no P0 architectural blocker. The proposed run-scoped seam is the right upstream boundary, all load-bearing claims check out against current ADK
main, and the two-PR sequence matches ADK's focused-PR contribution rule. The fresh pass found four P1 contract gaps and six bounded P2 improvements; I applied all of them to the issue body so the thread and normative RFC now agree.Verification performed
9d306f5is still currentmainas of this review.AgentOptimizer.optimize()has no run-scoped argument today.SimplePromptOptimizerand both GEPA optimizers directly own reflection/candidate LLM calls and discardLlmResponse.usage_metadata.max_metric_callslimits GEPA sampler evaluations, not reflection calls or tokens.RunConfig.max_llm_callsis enforced throughInvocationContext, which optimizer reflection bypasses.LlmResponseexposes both usage metadata and in-banderror_code.cli_optimizeApp plumbing to a follow-up.KeyErrorframing.gepa>=0.1; GEPA 0.1.0 providesstop_callbacks, but checks them at iteration boundaries and catches reflection/proposal exceptions into no proposal.P1 findings resolved in the body
A token ceiling cannot be called hard when usage may be partial or unreported. The revised contract reserves hard enforcement for atomic logical-call admission. Token enforcement is now explicitly over authoritative provider-reported totals, with
within_limit | exceeded | indeterminatecoverage. Missing totals can never be interpreted as proof that actual usage stayed below the ceiling.return_partialpreviously conflicted with zero-change result compatibility. Addingterminal_statusto the existing Pydantic result would change normal schema/serialization, and SimplePromptOptimizer may not have a completed validation score at the stop boundary. The revised contract leavesOptimizerResultunchanged, makes the caller-owned snapshot authoritative, pins normal run status tocompleted, definesoverall_score=Nonewhen validation never completed, and forbids post-stop validation.GEPA's stopper is too late by itself. The body now pins the required sequence: commit reflection usage, set terminal state, raise a private iteration-abort sentinel, let GEPA convert the interrupted reflection to no proposal, stop at the next loop boundary, then post-check and map to raise/partial. A test must assert that no sampler call occurs after the overshoot commits.
The no-orphan worker guarantee was unconditional. Cooperative cancellation cannot forcibly terminate a provider call or executor thread that never returns. The revised DoD guarantees shielding/draining once the active operation reaches a boundary and explicitly names the tradeoff: after a caller's bounded grace period, abandoning the wait forfeits the drain guarantee; an absolute wall-clock bound requires provider/sampler timeouts or process isolation.
P2 improvements applied
completed | provider_error | cancelled) from run status (completed | budget_exceeded | cancelled | failed).LlmResponse.error_codebehavior explicit: governed runs preserve usage and terminate with a typed provider error rather than silently succeeding.Non-blocking cleanup applied
Result
The RFC now makes three different claims separately and truthfully:
That distinction is the key governance property. With it, the RFC is ready for maintainer API feedback and then the stacked contracts/enforcement draft PRs. The BQAA-specific storage, pricing, promotion, and holdout responsibilities remain correctly outside ADK.
caohy1988 commentedon Jul 10, 2026
Draft implementation now up as the two-PR stack proposed above: #6358 (contracts:
OptimizationRunContext,OptimizerCapabilities,terminal_status) and #6359 (enforcement inSimplePromptOptimizer+GEPARootAgentPromptOptimizer, typed rejection inGEPARootAgentOptimizer). Fulltests/unittests/optimization/suite: 53/53 passing on the stack. Both drafts — naming and API shape follow whatever direction maintainers set on the questions above.align contracts with revised RFC: call/run status split, indeterminat…
feat(optimization): enforce run-context usage, budgets, and cancellat…
caohy1988 commentedon Jul 10, 2026
Review of the precision pass — verified, and the draft stack is now aligned
Reviewed the fresh-review comment above against the revised issue body and the actual sources. All four P1s are correctly reflected in the body, and the load-bearing behavioral claim is empirically confirmed: GEPA's engine catches per-iteration exceptions and continues the loop (
gepa/core/engine.py:588, withstop_callbackschecked at loop boundaries via_should_stop) — I reproduced this against the installedgepamatching ADK's declared floor. That claim was not academic: it exposed a real bug in the pre-revision draft #6359, where a typed budget error raised from the reflection callable was swallowed by the engine and sampler calls kept scheduling after the overshoot committed.Both draft PRs are now updated to the revised contract:
completed | budget_exceeded | cancelled | failed); token knob renamed tomax_provider_reported_tokenswith snapshot-leveltoken_budget_status: within_limit | exceeded | indeterminate(any partial/unreported call ⇒ indeterminate — missing totals are never read as compliance);OptimizerCapabilitiesexpanded to the six granular fields includingaccepts_run_context;terminal_statusremoved —OptimizerResultis unchanged and the caller-owned snapshot is authoritative;OptimizationProviderErroradded for governed in-banderror_codetermination.raise/return_partial(with GEPA's best-so-far candidates available in the partial path, an improvement over the pre-revision seed-only fallback).SimplePromptOptimizerterminates governed runs on in-banderror_codewith usage preserved, andreturn_partialreturnsoverall_score=Nonewith no post-stop validation.The body-mandated regression test is implemented and green: no sampler call is scheduled after the overshoot commits, proven against a gepa stub with faithful engine semantics (iteration exceptions swallowed; stoppers at loop boundaries). Full
tests/unittests/optimization/: 57/57 passing on the stack, including all pre-existing optimizer tests.One scope note for maintainers reading the stack: the GEPA-compatibility test scenario in the body (minimum plus latest admitted
gepa) is exercised in these drafts only against the installed release; pinning a CI matrix entry for both ends of the unboundedgepa>=0.1range is left to the PR-review round, where the right CI mechanism is a maintainer call.The thread, the normative body, and the draft implementation now agree. Awaiting maintainer direction on the four API questions.
caohy1988 commentedon Jul 10, 2026
Fresh cross-stack review: RFC #6357 + contracts #6358 + enforcement #6359
I re-reviewed the current issue body and both unchanged PR heads from first principles:
f345eee1e2bdb171abd58ca0fde8c5a8359b0956: full contract reviewc1f214ef22cf836c41da3f0c0fac42132d5730ae: full enforcement reviewFresh verdict: the RFC remains upstream-ready in direction, but the implementation stack is not yet aligned with the normative contract and should remain draft. The previous “all findings resolved / 57 of 57” conclusion overstates convergence: 57 official tests do pass, but a new RFC-derived adversarial set failed 16 of 16 cases.
What genuinely converged
The latest revisions correctly established several important foundations:
OptimizerResultremains unchanged and the snapshot is caller-owned.within_limit | exceeded | indeterminate, with missing totals never treated as proof of compliance.return_partialpreserves GEPA's actual best-so-far candidates; Simple returnsoverall_score=Noneand skips final validation.Those are meaningful improvements. The remaining gap is not the basic budget path; it is the terminal-state and cancellation contract around every other exit.
Load-bearing gaps found in the fresh pass
1. Provider failures can still return success through GEPA
The context records a provider-error call but does not make the run
FAILED. GEPA catches per-iteration reflection exceptions and continues; because the stopper sees no terminal run status, both in-band and raised provider errors can be converted into eventual normal success. Raised reflection errors also lose usage-so-far, and a simultaneous token overshoot masks the provider failure.The implementation needs atomic provider-failure commit, sanitized structured metadata, provider-error-first precedence, a GEPA sentinel conversion, and a final typed
OptimizationProviderErrormapping.2. The authoritative final snapshot is frequently not final
Normal success is never marked
COMPLETED. Several provider and native-cancellation paths remainNone. Calls can start after a terminal token overshoot, and a late cancellation can overwrite an earlier budget terminal state. The snapshot also lacks configured limits, the triggering invocation ID, and terminal error metadata named by this RFC.3. Advertised cancellation capability is not implemented at every pinned boundary
Simple performs baseline sampler work before checking a pre-cancelled context, does not check after candidate generation or around candidate/final scoring, and leaves native-cancelled model calls open. GEPA checks before sampler evaluation but not immediately after it. Its unconditional shield also changes legacy cancellation behavior when no context is supplied by draining the executor before propagating cancellation.
4. The governance ledger is mutable and can be corrupted across contexts
A handle from context A can be committed into context B; handle close is not atomic;
attach(None)can reuse a one-shot context; budgets remain caller-mutable during a run; and the documented immutable snapshots/events are mutable Pydantic objects.5. Contract and merge gates remain incomplete
ModelCallStageremains closed rather than extensible, negative budgets are accepted, and stale documentation still refers to the removedterminal_status. PR #6358 is not independently type-clean because it changes the abstract signature before updating built-ins. On the stacked head, Ruff, Pyink, Isort, and Mypy checks all identify new issues. The required real GEPA minimum-and-latest test matrix is absent; the critical tests use a fake GEPA loop and cover the budget path only.Recommended precision additions to the normative body
The body does not need another redesign. I recommend adding these explicit clauses so the next implementation pass is mechanically reviewable:
Definition-of-Done test additions
Before either PR is treated as aligned, the matrix should include:
COMPLETEDfor Simple and GEPA;Verification record
This does not invalidate the producer/consumer ownership boundary or the two-tier compatibility model. Those remain strong. It means the RFC should stay the normative target, while the draft PRs need another lifecycle-and-negative-path pass before the downstream flywheel or design doc can claim the upstream governance seam exists.
caohy1988 commentedon Jul 10, 2026
Cross-stack update following the adversarial review round: both drafts are rewritten to close every P1 — the contracts PR (#6358, head
bd5b94d) now implements the full first-terminal-wins state machine, provider-failure precedence, and a frozen/ownership-validated ledger, with the review's five failing adversarial probes now first-class passing tests; the enforcement PR (#6359, head0542043) implements every pinned cancellation boundary, the provider-error sentinel bridge (including the seed-evaluation escape path that runs outside GEPA's swallowing loop), governed-only shielding for absent-context parity, and exit-path finalization — verified by a Definition-of-Done test matrix including real-GEPA integration tests. Full optimization suite: 81/81. The recommended normative clauses (terminal transition ownership, provider-failure precedence, native cancellation finalization, absent-context parity, ledger integrity) are all now true in code; the min-plus-latest gepa CI matrix remains the one open gate, which needs maintainer CI configuration. Both PRs stay draft pending the API-shape questions.caohy1988 commentedon Jul 10, 2026
Fresh cross-stack review after the adversarial rewrite
Reviewed the RFC and both unchanged new heads from first principles, including the complete diffs, current
main, official tests, strict type/lint gates, real GEPA at both currently admitted versions, and a new set of contract-derived adversarial probes.bd5b94d: complete contract review0542043: complete enforcement reviewFresh verdict: the rewrite resolves most of the previous round, but the “all normative clauses are now true in code” disposition is still premature. Keep both PRs draft. The GEPA budget/provider bridge is now strong; the remaining P1s are concentrated at boundary normalization, concurrent terminal propagation, absent-context equivalence, setup failure, and native-cancellation accounting.
What is verified resolved
owner=None.COMPLETED.gepa==0.1.0and the current latestgepa==0.1.1: 81/81 on each. A real-GEPA provider-failure probe also passes on both.main; intervening main changes do not touch the optimization surface.Remaining P1s
1. No-context GEPA behavior changed
#6359 inspects
LlmResponse.error_codeand returns early inside_generate()even whenrun_context=None. The old path continued consuming the stream. A reproduced two-response stream returns the later"legacy final"on the legacy logic but an empty prompt on this head.This is a direct failure of the RFC's absent-context observational-equivalence requirement. The error-code branch must be governed-only.
2. Provider/control metadata is not normalized at the governance boundary
The contract claims sanitized identifiers but accepts and persists arbitrary values. A raised provider exception with numeric
error_code=429causes snapshot validation to throw PydanticValidationError, replacing the promisedOptimizationProviderErrorand making later snapshots unreadable. Long/multiline strings are retained unchanged.Usage conversion is also exception-unsafe: internal state is mutated before conversion completes, so invalid metadata can leave an event half-closed with no terminal state.
Normalization, bounding, and usage extraction must happen before atomic commit.
3. Terminal propagation has two concurrency gaps
finalize_success()can mark a pending cancellationCOMPLETED, producingcancel_requested=Truewith completed status.First-terminal-wins therefore protects the status field but does not yet protect all callers from continuing work. Success finalization must atomically observe pending cancellation/open calls; every already-in-flight completion must receive the first terminal before returning.
4. GEPA setup failures leave a consumed context in progress
#6359 attaches the context before importing GEPA, constructing the adapter/model, or reading sampler IDs, while its failure finalization begins only around the executor await. A reproduced sampler setup failure propagates normally but leaves
run_status=Noneon a context that can no longer be reused.Every failure after attachment must finalize, or fallible setup must occur before attachment.
5. Simple native cancellation drops usage already observed
If a streamed response reports usage and native cancellation arrives before the next response, Simple closes the call via
finalize_cancelled()without committinglast_usage. A reproduced seven-token call ends as cancelled withtotal_tokens=None,usage_coverage=unreported, andcompleted_calls=0.Cancellation needs a call-level terminal commit carrying usage/model metadata before run finalization.
Smaller contract and delivery findings
FAILEDterminal is re-emitted asOptimizationProviderError, including adapter/sampler failures finalized as non-provider crashes.completed_calls; counter semantics need to be made consistent or renamed.start_time/end_timearetime.monotonic()process-relative values. Rename them accordingly or add UTC timestamps for the persisted audit surface.Recommended RFC precision additions
The ownership boundary remains correct. Add these clauses so the next pass is mechanically reviewable:
Definition-of-Done additions
error_codeproduces the legacy result;COMPLETED;Verification record
GEPA matrix disposition
This is narrower than the previous open-gate wording: compatibility itself is currently verified locally at both existing endpoints, 0.1.0 and 0.1.1. The remaining gap is durable CI automation for both endpoints, or an upper bound if that matrix becomes unsustainable. That remains a legitimate maintainer configuration decision, not a demonstrated code incompatibility.
The RFC does not need another architectural rewrite. One focused contract pass and one enforcement pass should close these gaps. Until then, downstream #318/#357 should continue treating the upstream governance floor as not yet released and the drafts as implementation evidence, not a completed seam.
caohy1988 commentedon Jul 11, 2026
Fresh cross-stack review — RFC #6357 + PRs #6358/#6359
I performed a new review against the unchanged current heads:
bd5b94d054204357e1ba6Converged verdict: the architecture remains sound, but the implementation is not yet an authoritative governance boundary. Keep both PRs draft. The earlier disposition comment describes real improvements, especially the GEPA sentinel/stopper/post-check bridge, but it predates a later adversarial round. Because neither head has changed since that round, those findings remain open.
What is verified working
git diff --check.Remaining implementation blockers
finalize_success(), and an already-inflight call settling after another call terminates the run can return normally instead of observing the existing terminal.FAILEDterminal is reconstructed asOptimizationProviderError, including sampler/adapter failures.attach()and the executortry/except—including sampler-ID setup—leaverun_status=None.COMPLETED.Independent adversarial suite result: 11 failed / 4 passed. These are deterministic contract probes, not timing flakes.
Merge-quality gates
Recommended closure sequence
attach()through the complete optimizer lifecycle.The RFC’s producer/consumer boundary is still the right design: ADK should expose truthful model-call governance evidence, while BQAA owns sampler/evaluation accounting, pricing, promotion policy, and persistence. The implementation needs the fixes above so downstream policy can safely treat the caller-owned snapshot as authoritative rather than merely best-effort.
caohy1988 commentedon Jul 11, 2026
Round-2 closure: both heads rewritten to close every finding from the second adversarial round — contracts (#6358,
9ed15ac): atomic validate-before-commit settlement, complete terminal observation (including the in-flight-settlement-after-terminal gap and defensivefinalize_success), truthful failure typing (OptimizationFailedErrorvs provider-reservedOptimizationProviderError), settled-call counter semantics, wall-clock event timestamps; enforcement (#6359,b9293de): governed-only in-band error handling restoring byte-level no-context stream parity, full attached-lifecycle terminalization fromattach()onward, cancellation with usage evidence preserved, post-validation cancellation boundary, dual-layer provider-metadata normalization. Every reproduction from the round-2 reviews is now a first-class passing repository test. Suites: 70/70 isolated contracts, 96/96 stacked. Remaining open gates: the repo-config mypy comparison (not reproducible with default flags locally — will chase under the reviewer's invocation if deltas persist) and the min-plus-latest gepa CI matrix (maintainer-side). Both PRs remain draft pending the API-shape questions.caohy1988 commentedon Jul 11, 2026
Round-3 cross-stack review — RFC #6357 + PRs #6358/#6359
Reviewed current heads from scratch:
9ed15ac;b9293de;57e1ba6.Verdict: Round 2 correctly closes its entire finding list, but the implementation is not yet an authoritative governance boundary. Keep both PRs draft. The remaining architecture is sound; the fresh blockers are lifecycle ordering and repository delivery gates, not a need to rewrite the RFC.
Verified Round-2 closure
COMPLETED.Fresh P1 blockers
finalize_success()accepts open calls and silently returns for an existing raise-mode terminal.COMPLETEDwith an open call (started_calls=1,completed_calls=0).FAILEDwins over the already-pending cancellation.Delivery blockers
run_context.pymodule violates ADK's private-by-default module rule and is not exported throughoptimization.__init__/__all__.1.9is truncated to1and marked verified.Suggested implementation order
finalize_success()return only for existingCOMPLETED, re-raise every other terminal, and fail closed on open records.OptimizationFailedError, then the private GEPA sentinel.raise_on_exception=Truefor governed calls.RFC precision text worth adding
The ownership boundary remains right: ADK owns optimizer-call governance evidence; BQAA owns sampler accounting, prices, persistence, and promotion policy. These focused fixes make the snapshot safe enough for that downstream contract.
caohy1988 commentedon Jul 11, 2026
Round-3 closure: all findings from the third adversarial round are implemented and regression-tested on both heads — contracts (#6358,
b12baac):finalize_successas a true invariant boundary (open calls →FAILED/OPEN_MODEL_CALLS; committed terminals re-raise; pending cancellation cannot become success), complete event-field normalization (returned model version; fractional counters unreported rather than truncated),abort_model_calllocal-failure settlement, snapshot terminal provenance, ADK-style private module packaging (_run_context.py+__all__exports), typed internals for the strict mypy config, and the RFC-required concurrency races (16-thread attach, 16-thread admission under k=3, success-vs-settlement). Enforcement (#6359,ef7016b): pre-admission request construction, exception-complete post-admission settlement with truthful local-abort typing, pre-cancellation precedence over discovery in both optimizers, provenance-aware failure mapping, typed internals, corrected GEPA attribution withraise_on_exception=Truepinned on governed runs and the legacy call shape preserved exactly ungoverned, plus real-GEPA durable coverage for provider error / post-sampler cancel / reflection-request failure. Suites: 82 isolated contracts, 106/106 stacked. Open items: repo-config mypy verification (blocked in my environment by a numpy-stub syntax failure underpython_version=3.11— fixes applied structurally per the named lines; will clear any residue under the reviewer's invocation) and the min-plus-latest gepa CI matrix (maintainer-side). Both PRs remain draft pending the API-shape questions.caohy1988 commentedon Jul 11, 2026
Round-4 cross-stack review — RFC #6357 + PRs #6358/#6359
Reviewed current remote heads from source and with fresh adversarial probes:
b12baacef7016b57e1ba6Verdict: keep both PRs draft. Round 3 closes most prior findings, but the implementation is not yet a fully authoritative governance boundary. Two runtime semantics, two merge gates, and several evidence/documentation gaps remain.
Remaining blockers
started_calls=1,completed_calls=0, and no terminal call state._extract_usagemust degrade malformed/accessor-failing evidence to unreported rather than letting metadata defeat settlement.LlmRequestbefore admission correctly avoids a phantom call, but GEPA swallows the local failure and ADK recordsCOMPLETEDwith zero calls. Keep the ledger empty, but finalize the runFAILED/REQUEST_CONSTRUCTION_FAILUREand map through the private sentinel.OptimizationFailedErrors from worker threads and fails whenPytestUnhandledThreadExceptionWarningis promoted to an error._run_status.valueaccess in_run_context.py.Other fixes recommended before maintainer review
run_coroutine_threadsafe()fails before accepting them; the current scheduling-failure test leaks_generate().RFC body synchronization required
The normative issue body currently trails the implementation:
completed | provider_error | cancelled, omittingaborted;optimizer_calls_observable,logical_call_limit_enforced, andreported_token_limit_enforced, while the implementation exportsmodel_calls_observable,logical_call_limits_enforceable, andreported_token_limits_enforceable;optimization/run_context.py, while ADK correctly moved the implementation to private_run_context.pywith package exports;terminal_from_provider_callprovenance are not described;engine.py:588as the swallowing site, even though the actual reflection exception conversion is inreflective_mutation.pyandraise_on_exception=Truegoverns other engine failures.Suggested RFC precision text
Verification record
The producer/consumer boundary still holds: ADK should own truthful optimizer-call control and evidence; BQAA should own sampler accounting, pricing, persistence, and promotion policy. The remaining work is focused and mechanical enough for one more implementation round, but the request-construction false success and incomplete settlement boundary should be fixed before the API-shape review is treated as ready to converge.
caohy1988 commentedon Jul 11, 2026
Round-4 closure: all findings implemented and regression-tested on both heads. Contracts (#6358,
d0b10d5): boundary-hostile provider/custom-LLM inputs can no longer strand or corrupt the ledger (defensive accessor+conversion in usage extraction; hostile__str__degrades safely on every normalization path), duplicate settlement on a terminal run re-raises the committed terminal, admission/cancellation metadata is normalized (non-empty bounded stage enforced), the last strict-mypy optional-.valueread is narrowed, and the success/settlement race test is barrier-synchronized, outcome-captured, and clean under warning-as-error. Enforcement (#6359,8a19693): a governed request-construction failure is now truthfullyFAILED/REQUEST_CONSTRUCTION_FAILURE— the round-3 tests pinning the superseded clean-ledger-success shape are corrected rather than preserved — scheduling failures close the never-awaited coroutine (warning-as-error tested), and terminal settlements carryreturned_model_versionwith the same strength as successes. Suites: 89 isolated contracts, 116/116 stacked. The semantic pin from this round — a clean ledger means no model call began, not that the optimization succeeded — is now enforced in code and tests. Open items unchanged: repo-config mypy verification under the reviewer's environment, and the maintainer-side gepa min-plus-latest CI matrix. Both PRs remain draft pending the API-shape questions.llalitkumarrr commentedon Jul 13, 2026
Hello @caohy1988 ,
Thank you for the detailed report. We will review it and get back to you if we need any further information.
adk-bot commentedon Jul 21, 2026
🚨 Automated Spam Detection Alert 🚨
@maintainers, a suspected spam comment was detected in this thread.
Reason: