graflo.architecture.query.caps¶
Hard limits on what a read request may ask for.
Caps live in core, not in route handlers, so that no surface can opt out of them by forgetting to check. A handler that skips a check is a silent hole; a model that will not construct is not.
The central decision here is that :class:QueryCaps is not a field on any
query model. If it were, a request body could carry {"caps": {"max_hops": 99}}
and "enforced in core" would be false by construction. Queries validate against
the module-level :data:HARD_CAPS, and :meth:GraphQuery.narrowed is the only
way to change a limit — downward.
CapExceededError
¶
Bases: ValueError
A query asked for more than a cap allows.
Carries the cap's name so the surface can say which limit was hit rather than returning a generic validation failure — an agent that is told "too many hops, max is 3" can retry; one told "invalid request" cannot.
Source code in graflo/architecture/query/caps.py
QueryCaps
¶
Bases: ConfigBaseModel
Ceilings a read request must fit inside.
Defaults are the core ceiling. A deployment narrows them per connection via
:meth:GraphQuery.narrowed; nothing widens them.
Source code in graflo/architecture/query/caps.py
narrow(other)
¶
Combine two cap sets, taking the stricter of each.
Narrowing is a lattice meet, not an override: a policy that tried to raise a ceiling silently becomes a no-op rather than a privilege escalation.