Record accepted execution control decisions
This commit is contained in:
@@ -1,9 +1,8 @@
|
||||
# Execution Controls For Coordinated Turns
|
||||
|
||||
Status: proposed follow-up to v0.22.0. This document describes the target behavior
|
||||
and implementation work; the significant choices at the end remain open. No code
|
||||
changes are authorized by this roadmap. Public names and signatures are not yet
|
||||
selected.
|
||||
Status: all four design decisions accepted; ready for API and staged
|
||||
implementation planning from v0.22.0. No code changes are authorized by this
|
||||
roadmap. Public names and signatures are not yet selected.
|
||||
|
||||
## Purpose
|
||||
|
||||
@@ -50,6 +49,10 @@ 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
|
||||
@@ -88,7 +91,7 @@ again. Retaining or modifying delivered details must not mutate the execution.
|
||||
The application can retain them after provider failure or cancellation even when
|
||||
no ordinary result or exchange is returned. If preparation fails, no complete
|
||||
snapshot is required. Cancellation before notification does not promise delivery;
|
||||
its precise boundary is proposed in Open Decision 3.
|
||||
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
|
||||
@@ -106,15 +109,15 @@ events or counting attempts twice.
|
||||
Avoid changing the coordinator to an explicit public prepare/run sequence merely
|
||||
to obtain details: that would change ordinary admission and preparation-failure
|
||||
observation behavior. Reuse the execution path and its existing ownership
|
||||
boundaries. Exact public controls and split-preparation semantics remain open
|
||||
below; do not silently ignore a newly supplied option on one entry point.
|
||||
boundaries. Follow the accepted split-preparation and callback semantics below;
|
||||
do not silently ignore a newly supplied option on one entry point.
|
||||
|
||||
## Work From The Baseline
|
||||
|
||||
1. **Settle the public lifecycle.** Resolve the open decisions below and write
|
||||
small ordinary-run, coordinated-turn, and split-preparation usage sketches.
|
||||
Specify omitted/zero/negative timeout handling using ordinary duration
|
||||
conventions, callback invocation timing, and retained callback cleanup.
|
||||
1. **Design the public API.** Write small ordinary-run, coordinated-turn, and
|
||||
split-preparation usage sketches under the accepted lifecycle below. Specify
|
||||
omitted/zero/negative timeout handling using ordinary duration conventions,
|
||||
and express the selected callback timing and cleanup in the public contract.
|
||||
Choose names and signatures without adding a broader lifecycle-hook framework.
|
||||
2. **Add operation-budget handling.** Establish and clean up the child scope at
|
||||
the selected execution boundary. Preserve earlier parent deadlines and public
|
||||
@@ -126,7 +129,7 @@ below; do not silently ignore a newly supplied option on one entry point.
|
||||
Preserve credential handling and release resources on cancellation or panic.
|
||||
Avoid snapshot-copy work when the capability is not selected.
|
||||
4. **Integrate and verify coordination.** Have ordinary execution honor the
|
||||
selected controls on the callback-returned request under the recommended API.
|
||||
selected controls on the callback-returned request under the accepted approach.
|
||||
Preserve capture and observer composition; verify the next-turn callback runs
|
||||
with the parent context after admission and child-budget cleanup.
|
||||
5. **Document and demonstrate.** Update public GoDoc, the
|
||||
@@ -143,13 +146,14 @@ are needed. Keep implementation proportional to the two requested controls.
|
||||
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 lifecycle choices ultimately selected:
|
||||
and the accepted lifecycle choices:
|
||||
|
||||
- Successive turns receive fresh budgets: their combined duration may exceed one
|
||||
operation budget without exhausting either individual operation.
|
||||
- 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.
|
||||
- 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.
|
||||
- Prepared details precede generation, contain the assembled continuation, and
|
||||
@@ -159,38 +163,50 @@ and the lifecycle choices ultimately selected:
|
||||
observer lifecycle is introduced. Existing credential redaction remains intact.
|
||||
- Preparation failure, cancellation around notification, and callback panic follow
|
||||
the selected delivery rules and do not strand admission or retained resources.
|
||||
- Split preparation follows its documented budget and callback lifecycle. Neither
|
||||
discarded nor unsuccessfully claimed handles start execution notifications.
|
||||
- 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.
|
||||
|
||||
## Open Decisions
|
||||
## Accepted Decisions
|
||||
|
||||
All four decisions below are accepted. No significant product decisions remain
|
||||
open. Exact public names, signatures, timeout-value conventions, and the Go
|
||||
representation of timeout identity remain for API and implementation planning.
|
||||
|
||||
### 1. Narrow Execution Controls Or Caller-Delegated Execution?
|
||||
|
||||
**Recommendation:** 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.
|
||||
**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.
|
||||
|
||||
**Viable alternative:** 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. Prefer it only if concrete API sketches show it is materially simpler
|
||||
than the narrow controls, not merely more extensible.
|
||||
**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?
|
||||
|
||||
**Recommendation:** 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.
|
||||
**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
|
||||
@@ -198,21 +214,22 @@ 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.
|
||||
|
||||
**Viable alternative:** 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.
|
||||
**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?
|
||||
|
||||
**Recommendation:** 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.
|
||||
**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
|
||||
@@ -227,31 +244,32 @@ 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.
|
||||
|
||||
**Viable alternative:** 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. Select it if that broader control has a concrete
|
||||
consumer need; optional write failures can still be handled locally either way.
|
||||
**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?
|
||||
|
||||
**Recommendation:** preserve standard context matching and provide a narrow,
|
||||
**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.
|
||||
Choose its Go representation during API design; no new error-report hierarchy
|
||||
or terminal-event category is implied.
|
||||
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. Choose its Go representation during API design; 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.
|
||||
|
||||
**Viable alternative:** 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. It supplies weaker attribution; choose it only if Audita confirms that this
|
||||
meets its classification requirement.
|
||||
**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.
|
||||
|
||||
Reference in New Issue
Block a user