# Execution Controls For Coordinated Turns Status: all four design decisions accepted. This document defines the target state from v0.22.0; [implementation.md](implementation.md) selects the concrete API and staged implementation work. The feature is not yet implemented. ## Purpose Enable applications using `Engine.Coordinate` to select a fresh timeout for each continuation and retain the exact prepared request before generation. These are execution capabilities useful for bounded operations and optional diagnostics, without assumptions about prompt content or application workflows. [Audita's request](audita-request.md) supplies the motivating requirements. Audita already uses one child context across explicit preparation and execution, and retains prepared details for diagnostics. The goal is to make those controls available during coordinator-owned execution without requiring a downstream replacement for PromptKit's turn loop. PromptKit owns history assembly, execution, cancellation propagation, and observations. Applications select budgets, interpret results, run validators, schedule branches, and own diagnostic destinations, disclosure policy, and write failure handling. This work adds no artifact store or reporting framework. ## Current Baseline [PromptKit v0.22.0](../releases/v0.22.0.md) supplies captured exchanges, continuation, sequential coordination, and explicit execution groups. - The [coordinator](../../coordinate.go) attaches the current exchange and composes request/coordinator observers, then calls `Engine.Run` with the parent context. Its callback returns a request, not an execution context or prepared handle. - Ordinary [run execution](../../internal/usecase/runner.go) resolves the target, obtains logical admission, completes preparation, and generates and validates the response. Admission is released before the next-turn callback. - Explicit [prepared execution](../../prepared_execution.go) already supplies detached `Details()` and executes the retained snapshot. Preparation and execution are separate calls; preparation does not reserve backend capacity. - Ordinary [observations](../internal/observation.md) are metadata-only. Ordinary runs observe preparation failures; split preparation itself emits no execution events. A claimed prepared handle starts its observation lifecycle at execution. A timeout around the entire coordinator includes all turns and application callbacks. Provider timeouts cover a different scope. Neither provides a fresh whole-operation budget for each selected turn. Separately calling `Prepare` would duplicate preparation and would not bind the inspected details to the request actually executed. An exchange cannot supply a failed turn's prepared request when execution returns no result. ## Target End State The selected approach is optional per-request controls honored by ordinary `Run` and therefore by `Coordinate`. The accepted decisions below specify their lifecycle; the coordinator does not delegate execution to an application executor. ### Optional Operation Timeout An application can select a duration for each requested continuation. When that continuation starts, establish a fresh child deadline before preparation and use it for the entire operation: preparation, admission waiting, retries, generation, structural validation, and structural repair, including the prepared-details notification. Do not restart the budget between phases or attempts. The selected timeout covers work according to the entry point: | Entry point | Selected timeout behavior | | --- | --- | | `Run`, including coordinated turns | Starts before preparation and covers preparation and execution. | | `PrepareExecution` | Retains the duration for later execution; preparation uses its supplied context. | | `RunPrepared` | Starts the retained duration when invoked, covering the remaining execution. | Idle time between split preparation and execution does not consume the retained execution budget. Applications wanting one budget across both calls can pass the same caller-created deadline context through them. `Prepare` and `ValidateRequest` continue using their supplied contexts without starting the execution timeout. Respect parent cancellation and earlier parent deadlines. A local timeout ends the affected operation and coordination under the existing operational-error rule; it does not cancel the parent or siblings. Release child-context resources before returning to the application's next-turn callback. Assessment calls from that callback retain their own application-selected contexts and budgets. Determine the execution result and any local-timeout identity before publishing the terminal observation, so the returned error and observed outcome agree. A slow terminal observer or subsequent child-context cleanup must not retroactively turn a completed operation into a timeout. Preserve the existing coordinator behavior for completed responses, parent cancellation before next-turn callback delivery, and the single undelivered response. No automatic replay or new recovery policy is added. No selected timeout means existing context behavior. This adds no framework-wide recommended duration or mandatory cap. Additional-turn, transport-retry, structural-repair, and provider-generation budgets keep their existing meanings. Cancellation remains cooperative; a deadline does not forcibly terminate application callbacks or injected collaborators that ignore their context, or guarantee that the public call returns by that deadline. ### Opt-In Prepared Details Before Generation Provide explicitly selected access to caller-owned details of the logical request selected for execution, after successful preparation and before its first generation attempt. Reuse the existing prepared-details representation and credential redaction where practical. Include assembled captured history, rendered follow-up messages, caller-appended messages, and ordinary resolved execution metadata. Use the execution's prepared snapshot rather than rendering or reading inputs again. Retaining or modifying delivered details must not mutate the execution. Once delivered, details remain available to the application after provider failure or cancellation even when no ordinary result or exchange is returned. Diagnostic access is available only when execution reaches the prepared-notification point, not for every failed operation. Preparation failure requires no complete snapshot; ordinary admission failure or timeout may occur before preparation completes. Do not add rendering or rearrange admission solely to manufacture diagnostics for those failures. Cancellation before notification does not promise delivery; follow the context checks in [Decision 3](#3-what-is-the-prepared-details-callback-contract). This access exposes logical prepared content, not raw HTTP envelopes or internal structural-repair requests. Keep it separate from metadata-only observers and execution-group summaries. It is not another next-turn callback: ordinary execution may already hold backend admission at the notification point. ### Compatibility And Composition Applications selecting neither capability retain existing behavior. Preserve conversation assembly, capture, final-turn delivery, branching, and grouping contracts. Request observers, coordinator observers, and explicitly selected groups continue receiving ordinary execution facts without duplicate lifecycle events or counting attempts twice. Preserve ordinary admission, preparation-failure observation, and ownership behavior. A simple replacement of ordinary `Run` with the public `PrepareExecution`/`RunPrepared` sequence would change those behaviors. This does not freeze the internal call structure: consolidation or refactoring is welcome where it preserves the selected lifecycle. Document which controls each entry point applies or retains. Execution-only controls need not take effect during `Prepare` or `ValidateRequest`; accepting request-shaped input there does not itself justify rejecting such controls or starting a timer. Follow the accepted split-preparation and callback semantics. ## Affected Areas The target spans request controls, execution-context lifetime, detached prepared details, public error projection, and ordinary coordinator integration. It is an additive runtime feature; no collection-format or ConfigKit changes are needed. Public GoDoc will own exact API contracts, the [consumer guide](../consumers/pkg-promptkit.md) will explain use, and internal lifecycle documentation will describe the implementation when it lands. The implementation plan owns API selections, task sequencing, concrete changes, and validation steps. Keep that work proportional to the two requested controls. ## Validation Targets Use offline public-boundary tests and existing execution collaborators, with controlled cancellation and synchronization rather than fragile timing margins. Cover the consumer request's [acceptance scenarios](audita-request.md#acceptance-scenarios) and the accepted lifecycle choices: - Successive turns receive fresh budgets: their combined duration may exceed one operation budget without exhausting either individual operation. - For ordinary and coordinated runs, preparation, admission waiting, retries, validation, and repair share the same operation deadline. Local expiry stops coordination without canceling parent or sibling work; earlier parent cancellation/deadlines remain effective. - Next-turn assessment uses the parent context after release, including another call to a backend with capacity one. Timeout identity survives public wrapping. - A slow terminal observer or child-context cleanup does not change a completed outcome into a local timeout; the returned error and terminal observation agree. - Prepared details precede generation, contain the assembled continuation, and remain available after later failure. Mutation of the delivered copy or source changes after preparation do not change the executed snapshot. - Diagnostic access introduces no additional preparation or inference calls, notification per internal repair, or duplicate observer lifecycle. Ordinary retries and structural repair remain allowed. Credential redaction remains intact. - Admission or preparation failure before the notification point does not require diagnostic delivery or additional rendering to produce a snapshot. - Preparation failure, cancellation around notification, and callback panic follow the selected delivery rules and do not strand admission or retained resources. - Split preparation uses its supplied context and retains the selected duration for `RunPrepared`; idle time does not consume that execution budget. A shared caller deadline can still bound both calls. Neither discarded nor unsuccessfully claimed handles start execution notifications. - The prepared notification receives detached details and the operation context, has no error return, and runs synchronously within the operation budget. - Local-budget expiry has a narrow inspectable identity while preserving standard context matching; parent and provider deadlines are not mislabeled as local. - Observers/groups retain ordinary facts on success and failure. No-option use, completed-result delivery, and final-turn behavior remain compatible. ## Accepted Decisions All four decisions below are accepted. No significant product decisions remain open. The implementation plan selects public names, signatures, timeout-value conventions, and the Go representation of timeout identity. ### 1. Narrow Execution Controls Or Caller-Delegated Execution? **Accepted approach:** add optional per-request execution controls honored by ordinary `Run` and thus by `Coordinate`, including a timeout and prepared-details callback. This keeps history, capture, admission, errors, and observers in their existing owners and makes the capability useful outside coordination. A caller can select different controls on each returned request; an additional coordinator-wide configuration layer is not needed for the demonstrated use case. **Alternative considered, not selected:** let the coordinator delegate a turn to a caller-provided executor or prepared-execution adapter. This would reuse Audita's existing adapter and accommodate other execution customizations. It also requires a larger contract for exchange assembly, capture, observer composition, handle cleanup, and admission release. The narrow controls meet the demonstrated need with fewer ownership questions; caller-delegated execution is not part of this feature. ### 2. What Does A Timeout Mean For Split Preparation And Execution? **Accepted approach:** bound each `Run` invocation from before preparation. For `PrepareExecution`, retain the selected duration as an execution control and apply it when `RunPrepared` starts; preparation itself continues using its supplied context. Do not retain a live timer across an idle prepared handle. Explicitly explain that this bounds the remaining execution, not preparation already done. Callers needing one total budget across both calls can continue passing the same caller-created deadline context, as Audita does today. This preserves the distinction between executing now and preparing for later, while letting a prepared handle carry the same selected execution controls. It requires clear documentation: the duration alone does not retroactively cover split preparation. `Prepare` and `ValidateRequest` likewise do not become timed executions merely because they accept request-shaped input. **Alternative considered, not selected:** start a budget during `PrepareExecution` and carry its remaining deadline into `RunPrepared`. This directly bounds preparation and execution together without caller context plumbing. It also counts idle time, requires timer/context ownership and discard semantics, and changes what a prepared handle retains. This is useful if a consumer needs a whole prepared operation lifetime, but exceeds the current coordinated-turn requirement. ### 3. What Is The Prepared-Details Callback Contract? **Accepted approach:** a synchronous notification receiving the operation context and a detached prepared value, with no error return. Invoke it once after the snapshot is ready and before generation, only when execution proceeds to that point. For prepared handles, retain the callback until execution and clear it on claim/discard like the existing observer; inspection remains available earlier through `Details()` without triggering the notification. Check context before notification and again before generation. Include callback time in the operation budget and retain ordinary cooperative cancellation and panic propagation, with resource cleanup on unwind. Do not add background delivery or stronger terminal-event guarantees. The application can retain details and perform optional writes under its own policy; it need not turn a diagnostic write failure into an inference failure. Under the current ordinary run path this notification executes while logical admission is held. Document that fact rather than promise the next-turn callback's capacity-one nested-execution behavior. Do not prohibit arbitrary callback work; applications must account for the held capacity and operation budget. Releasing and reacquiring admission solely for notification is not necessary for this scope. **Alternative considered, not selected:** let the callback return an error to veto generation. This supports mandatory audit persistence or an application pre-generation check, with ordinary cleanup and error propagation. It also makes the callback an execution gate and requires failure classification semantics absent from the optional-diagnostics request. The selected notification satisfies that request; a generation veto would require a separate demonstrated need. ### 4. How Precisely Should Local Timeout Errors Be Identified? **Accepted approach:** preserve standard context matching and provide a narrow, inspectable operation-timeout identity when this newly selected budget causes termination. Keep parent cancellation/deadlines and provider-local failures under their existing identities. The marker must survive public wrapping and must not be inferred from any arbitrary `DeadlineExceeded` returned by a collaborator. Its Go representation is selected in the implementation plan; no new error-report hierarchy or terminal-event category is implied. This lets callers distinguish the requested local budget from an earlier parent or provider deadline without retaining the internal child context. Define cause selection around races using the child context's recorded cause; do not promise perfect ordering of independently simultaneous cancellations. **Alternative considered, not selected:** return only existing context errors and let callers inspect their parent context. This is smaller and often sufficient when the parent remains active. However, `DeadlineExceeded` alone may also originate in a provider timeout, and a parent may become canceled before the caller inspects it. That weaker attribution does not meet the selected distinction as directly as a narrow operation-timeout identity.