symfonic.core.prompt.blocks.sources.computed_contract¶
computed_contract ¶
The contract a computed block's host callable must satisfy.
The type of the callable, the two failure types it can produce, and the
three checks that decide which of them a given wrong answer is. Split out
of :mod:symfonic.core.prompt.blocks.sources.computed so the adapter
module holds the adapter and this one holds the rules it enforces.
Failures are typed; contract violations are not¶
The two ways a computed source can go wrong are not the same kind of event, and they are deliberately not the same kind of exception:
- The callable raised -- the database was down, the metadata service
timed out. That is environmental and transient, so it arrives as
:class:
ComputedBlockUnavailableError, a :class:~symfonic.core.protocols.StorageErrorthe resolver routes through the block'son_source_failurepolicy exactly like an unreadable file. - The callable returned the wrong shape -- a bare string, a 3-tuple,
a blank revision. That is a bug in host code. It is deterministic, it
will recur on every call, and it will never heal. It raises
:class:
ComputedBlockContractError, which derives from :class:TypeErrorand not fromStorageError, so it is not absorbed by the failure policy. Routing it there would mean a learned block whose policy isomitdisappears from every prompt, silently, for as long as the bug lives -- the exact months-later silent failure the block layer's construction-time checks exist to prevent. A loud failure on the first turn costs minutes; a silent one costs a quarter.
A :class:~symfonic.core.protocols.StorageError raised by the host
itself passes through unwrapped: a host that already typed its failure
(NotFoundError for a tenant with no row) knows more about it than
this adapter does, and re-wrapping would flatten that distinction.
BlockComputer
module-attribute
¶
BlockComputer: TypeAlias = Callable[[TenantScope, str], ComputedBlockResult | Awaitable[ComputedBlockResult]]
The host-supplied callable. Sync or async def; both are accepted.
ComputedBlockResult
module-attribute
¶
What a host callable returns: (content, revision), in that order.
ComputedBlockContractError ¶
Bases: TypeError
The host callable returned something that is not (content, revision).
Deliberately a :class:TypeError and not a
:class:~symfonic.core.protocols.StorageError: this is a
deterministic bug in host code, not an outage. It must not be
swallowed by an omit failure policy, because a block that
vanishes silently from every prompt is discovered months later, if at
all. See the module docstring.
ComputedBlockUnavailableError ¶
Bases: StorageError
The host callable raised while computing the block.
Typed as a :class:~symfonic.core.protocols.StorageError so the
resolver routes it through the block's on_source_failure policy
instead of letting an arbitrary exception from host code escape past
it and fail a turn whose policy said to omit the block.
reject_wrong_arity ¶
Raise :class:ComputedBlockContractError if compute cannot take (scope, block_id).
Checked at construction, where a mis-wired callable is a config
mistake at the site that supplied it, rather than at the first call,
where the TypeError Python raises for a bad signature is
indistinguishable from a real outage to :meth:ComputedBlockSource.load's
except Exception -- see the module docstring.
Some callables (certain builtins, some C extension types) have no
introspectable signature at all; :func:inspect.signature raises
ValueError for those, and the mismatch -- if any -- is left to
surface at call time rather than blocking construction of something
this function cannot actually check.
Source code in src/symfonic/core/prompt/blocks/sources/computed_contract.py
require_pair ¶
Return raw as a validated (content, revision) pair.
Source code in src/symfonic/core/prompt/blocks/sources/computed_contract.py
returns_awaitable ¶
Return whether compute must be awaited rather than threaded.
Checks the callable itself (covering plain async def and
functools.partial of one) and then its __call__, so a class
instance implementing async def __call__ is recognised too. A
sync function that returns a coroutine is not detected here and
does not need to be -- :meth:ComputedBlockSource.load awaits
whatever it gets back.