Skip to content

aaa.validate and aaa.core

Validation

ValidationHandler

ValidationHandler(
    validators: dict[str, Callable[..., Any]],
)

Runs named, deterministic validators: aaa.validate.requested {candidate, validator, context} -> aaa.validate.completed {verdict}. The 'test' half of generate-test-repair; validators are plain (async) callables — unit tests, linters, schema checks, business rules.

Verdict

Bases: BaseModel

json_validator

json_validator(tp: Any) -> Callable[[str, dict], Verdict]

Deterministic check that a candidate is JSON matching any pydantic-validatable type.

Outcomes and errors

Outcome

Bases: BaseModel, Generic[T]

Terminal result of a run; failure modes are distinct, never conflated.

OutcomeKind

Bases: StrEnum

AAAError

Bases: Exception

Base class for all library errors.

ConcurrencyError

Bases: AAAError

Optimistic-concurrency check failed (expected_seq mismatch).

SchemaError

Bases: AAAError

Unknown, invalid, or un-migratable payload schema.

RunNotFinished

Bases: AAAError

Erasing or purging a run that is still open. Cancel it (or wait) first, or pass force=True.

TenantMismatch

Bases: AAAError

A run exists but belongs to a different tenant than the one asking. Deliberately reported exactly like a missing run by TenantScope, so tenants cannot probe each other's run ids.

Resilience

RetryPolicy

Bases: BaseModel

How long to keep trying before giving up on an infrastructure operation.

Retrying stops at the FIRST bound reached; a bound set to None is not applied, and a policy with both bounds None retries until the call succeeds (or the task is cancelled).

max_attempts class-attribute instance-attribute

max_attempts: int | None = Field(default=None, ge=1)

Total tries including the first.

max_elapsed_s class-attribute instance-attribute

max_elapsed_s: float | None = Field(default=30.0, gt=0)

Total time budget for backing off (not counting the time the operation itself takes).

jitter class-attribute instance-attribute

jitter: bool = True

Full jitter (uniform in [0, delay]) so many workers do not retry in lock-step.

delay

delay(attempt: int) -> float

Backoff before retry number attempt (1-based).

forever classmethod

forever(
    base_delay_s: float = 0.2, max_delay_s: float = 5.0
) -> RetryPolicy

Never give up: for results that must not be lost (a tool that already ran).

is_transient

is_transient(exc: BaseException) -> bool

True if exc looks like a temporary infrastructure problem worth retrying.

Deliberately conservative: logical errors (ConcurrencyError, SchemaError, validation errors, bugs) are never transient, so a genuine fault still fails fast instead of looping.

retrying async

retrying(
    fn: Callable[[], Awaitable[T]],
    policy: RetryPolicy,
    *,
    classify: Callable[
        [BaseException], bool
    ] = is_transient,
    what: str = "store operation",
) -> T

Run fn, retrying transient failures per policy. Non-transient errors propagate untouched; exhausting the policy raises StoreUnavailable (chained to the last error).

StoreUnavailable

Bases: AAAError

The event/blob store could not be reached within the retry budget (a transient outage that outlasted RetryPolicy). Never a reason to fail a run: the work is retried or redelivered.

Redeliver

Bases: AAAError

Raised by a bus handler to say: "I could not finish this event because of a temporary problem; do NOT acknowledge it, deliver it again later". The engine raises it when a handler hit a store outage that outlasted its local retries. It is not an error in the run.

Ids

new_id

new_id() -> str

Time-sortable, monotonic ULID (26 chars, Crockford base32).

stable_id

stable_id(*parts: object) -> str

Deterministic id from its inputs: re-deriving the same effect after a crash yields the same id, so the store's idempotent append absorbs the repeat (effectively-once on the log).