tauopt.engine.ask#
engine.ask – the one suggest entry point (local driver and service both call this).
Semantics: explicit config or policy routing, then never-fail execution down
the robustness ladder. In the default on_timeout="ladder" mode,
ask() NEVER raises for math reasons: the ladder ends at the stdlib-only random rung
and every fallback is visible in provenance (fallback_from).
The wait budget is USER-OWNED: max_wait_s deadlines the whole ask (each GP
rung’s timebox derives from the remaining budget), and on_timeout="fail" re-raises
TimeboxExceeded instead of degrading – callers who prefer their own backoff get an
honest error. Non-timeout math failures ladder in BOTH modes: a budget preference
should never turn a numerics crash into an outage. A bad params value refuses at the
ask boundary (AskValidationError) before any rung for the built-in strategies (a custom
strategy without read_params keeps the ladder); nothing is silently repaired.
The timebox_mode x max_wait_s matrix (exhaustive):
budget x any -- rung timeboxes capped by the remaining ask budget;
between-rung expiry raises in fail mode
off x any -- injection-wins: the request bound rides as a
budget-mode execution pair; no-scrub both branches
caps x unset -- pure capped compute, no answer-shaping clock anywhere
(measurement-only telemetry exempt)
caps x set -- cooperative rung-boundary refusal + ONE post-completion
delivery decision, both ``AskDeadlineExceeded`` -- NEVER
injection, NEVER a timeout callback, NEVER a budget-pair
rewrite. A started rung runs to completion; an expired
delivery decision DISCARDS the computed drafts (the
withheld answer byte-equals what a longer deadline
returns -- availability may be wall-dependent, the answer
never is). ``AskDeadlineExceeded`` is structurally
invisible to the P6 ladder (never caught, never
substituted -- reusing TimeboxExceeded would BE ladder
substitution) and fires in BOTH on_timeout modes; state
never advances on refusal.
Suggestions are validated in-bounds before they leave the engine.
Deduplication (config.dedup): the suggest-time boundary. Exact re-suggestion
is refused against observed union pending union the current batch (canonical active-only
equality); REPAIR belongs to the owning strategy (the boundary DETECTS,
verifies, and descends the ladder with the exclusion set propagated); on
admitted finite spaces (raw universe <= 1,024) the enumeration path fills
remaining slots in the declared order and, when it completes with slots still
unfilled, PROVES exhaustion (space_exhausted). Typed intent requests may
then fill remaining slots as authorized duplicates – authorization recomputed
from canonical (state, config), never trusted (engine._intents). Flag-off asks
take the plain path (pinned byte-for-byte).
Queue selection (config.queue_selection, requires dedup): temperature-
annealed selection over each slot’s already-budgeted candidate queue. gp_ei and
ucb_cl expose per-slot ranked queues (their retained restart pools – generation
streams identical to the dedup path, selection deviates AFTER); the boundary’s
SlotSelector (engine._select) applies the dedup eligibility filter, distance
scoring, and the hashed temperature protocol, and records one provenance entry
per slot. Rungs without queues fill pass-through, recorded. Flag-off asks are
byte-identical to the dedup path (pinned).
Module Contents#
Classes#
The ask surface (additive schema): |
Functions#
Produce up to |
API#
- exception tauopt.engine.ask.AskValidationError#
Bases:
ValueErrorThe caller’s argument error at the ask boundary – the
ValueErrorclass both drivers answer as 400validation_error:n < 1, amax_wait_soutside (0, 300],strategy: "auto"withparams, intents withoutdedup, aparamskey the strategy does not read, or aparamsvalue the strategy’s reader refuses (the wrong type, out of range, an unknown enum value, a two-writer or posture conflict, or a composition of valid values the strategy cannot run on this space). Any otherValueErrorout of the engine is the engine’s own fault and surfaces as a 500internal_errorinstead of being blamed on the caller (a pydanticValidationErrordeep in a strategy, a partition violation in a record).Initialization
Initialize self. See help(type(self)) for accurate signature.
- exception tauopt.engine.ask.AskFailed(message: str, *, error_type: str, details: dict | None = None)#
Bases:
RuntimeErrorThe ask could not answer and the failure is the engine’s, not the caller’s: raised OUTSIDE the never-fail net, carrying a machine-readable
error_typeand adetailspayload both drivers forward – the local driver as a 500ApiErrorof the sameerror_typeanddetails, the hosted service as the same JSON error shape with the exception TEXT redacted (a constant message per type;detailswithoutexception_text, which stays in the service log under the response’sX-Request-Id), which the transport passes through unchanged. Two kinds:all_rungs_failed: every rung of the fallback chain failed, the stdlib-only random rung included (its one honest refusal is the rejection cap on a thin linear-constrained region).detailscarriesintendedandattempts(one record per failed rung:rung,stage,exception_type,exception_text, the same evidencefallback_attemptscarries on a served suggestion);__cause__is the last rung’s exception; the message is the attempts summary.integrity_violation: an integrity postcondition failed after a rung answered – a center-flagged sobol answer without a center record, or queue-selection drafts that fail canonical key computation or disagree with the selector’s commit ledger.detailscarriescheck(center_record,selection_key,selection_ledger). Fail-closed by design: a receipt that would lie is never shipped.
Initialization
Initialize self. See help(type(self)) for accurate signature.
- class tauopt.engine.ask.AskResult(/, **data: Any)#
Bases:
pydantic.BaseModelThe ask surface (additive schema):
draftsare the returned candidates (unique fills first, then authorized grants – the slot-fill order); the counters partitionrequested_q. Precedence:space_exhaustedis set whenever the enumeration PROOF holds – including alongside a full batch of authorized replicas;unique_candidate_unavailableonly when slots remain UNFILLED without proof, and it is NON-RETRYABLE for identical (state, config) – P4 guarantees the same answer until the state hash changes. The partition invariants are MODEL-ENFORCED: a counter that cannot partitionrequested_qdies at construction, never ships.Initialization
Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.- model_config#
‘ConfigDict(…)’
- drafts: tuple[tauopt.engine.strategies.base.SuggestionDraft, ...]#
None
- provenance: tauopt.engine.provenance.EngineProvenance#
None
- tauopt.engine.ask.ask(state: tauopt.engine.state.ExperimentState, *, config: tauopt.engine.config.OptimizerConfig | None = None, policy: tauopt.engine.policy.base.Policy | None = None, n: int = 1, max_wait_s: float | None = None, on_timeout: Literal[ladder, fail] = 'ladder', intents: Sequence[tauopt.engine._intents.IntentRequest] = ()) tauopt.engine.ask.AskResult#
Produce up to
nsuggestion drafts + the provenance that re-derives them.config(explicit, wins) orpolicy(defaults to DefaultPolicyV1) chooses the intended strategy.strategy: "auto"is the seedable policy path: it routes exactly likeconfig=Nonebut carries explicit top-level fields (seed,center_in_bootstrap,dedup,duplicate_intents,queue_selection,categorical_mode,timebox_mode,base_noise– the composable flag surface) into whatever rung the policy picks and down the fallback ladder.max_wait_sdeadlines the WHOLE ask;on_timeout="fail"re-raises TimeboxExceeded instead of laddering.intentsare typed duplicate requests, validated – never trusted – after unique search; they requireconfig.dedup. Flag-off asks always return exactlyndrafts; dedup asks may return fewer, with the shortfall accounted on the AskResult.