tangl.vm.provision¶
Constraint, offer, and resolver mechanisms for satisfying frontier dependencies.
Related design docs
Related notes
Constraint types¶
- class Requirement(has_kind: type | None, has_identifier: str | None)[source]¶
Unsatisfied resource contract carried by a frontier edge.
Why¶
Requirements separate the shape of what is needed from the graph structure that carries that need. This lets the resolver reason about candidates, policy, and diagnostics before mutating runtime topology.
Key Features¶
Extends
Selectorso requirement matching reuses the engine’s normal selection semantics.Tracks satisfaction, selected policy, and resolution metadata for replay and diagnostics.
Supports soft requirements and deferred UPDATE or CLONE formulas.
API¶
satisfiedreports whether the requirement is currently fulfilled.satisfied_by()evaluates a candidate provider.from_identifier()builds a simple identifier-driven requirement.
Example
>>> e = Entity(label='foo') >>> req = Requirement.from_identifier('foo') >>> req.satisfied False >>> req.satisfied_by(e) True >>> req.provider_id = e.uid >>> req.satisfied True >>> req = Requirement(hard_requirement=False) >>> req.satisfied True
- class HasRequirement(requirement: Requirement[PT])[source]¶
Mixin that makes a registry-aware carrier expose one embedded requirement.
Why¶
Resolver logic needs a uniform way to read satisfaction state, retrieve the resolved provider, and write resolution metadata back to the carrier edge.
Key Features¶
Centralizes provider bookkeeping on the embedded
Requirement.Mirrors satisfaction and resolution metadata through simple properties.
Validates provider compatibility before storing the resolved provider id.
API¶
providerandset_provider()synchronize the embedded requirement with registry linkage.satisfiedandsatisfied_by()delegate to the embedded requirement.
Example
>>> reg = Registry() >>> r = HasRequirement(requirement={'has_identifier': 'foo'}); reg.add(r) >>> r.satisfied False >>> e = RegistryAware(label='foo'); reg.add(e) >>> r.satisfied_by(e) True >>> r.provider = e >>> r.satisfied True >>> r.provider <RegistryAware:foo> >>> f = RegistryAware(label='bar'); reg.add(f) >>> r.satisfied_by(f) False >>> try: ... r.provider = f ... except ValueError as e: ... print(e) Requirement ... not satisfied by <RegistryAware:bar>
- class Dependency(predecessor_id: UUID | None = None, requirement: Requirement[PT])[source]¶
Pull-resource edge whose predecessor declares a needed provider.
Why¶
Dependencies make missing topology explicit. A frontier node can advertise what it needs before any provider exists, then let the resolver bind a concrete successor later during planning.
Key Features¶
Couples one embedded
Requirementto graph topology.Keeps
providerandsuccessorsynchronized so resolution state is visible through normal edge traversal.
API¶
set_provider()validates and stores the resolved provider while synchronizingsuccessor.set_successor()provides a topology-first alias that also updates requirement state.
Example
>>> reg = Registry() >>> r = Dependency(requirement={'has_identifier': 'foo'}); reg.add(r) >>> r.satisfied False >>> e = RegistryAware(label='foo'); reg.add(e) >>> r.successor = e >>> r.satisfied True >>> r.provider <RegistryAware:foo> >>> r.successor <RegistryAware:foo>
- class Affordance(predecessor_id: UUID | None = None, requirement: Requirement[PT])[source]¶
Push-resource edge whose predecessor offers a provider to nearby consumers.
Why¶
Affordances model already-available local providers that should be treated as preferred EXISTING offers before wider search proceeds.
Key Features¶
Couples one embedded
Requirementto a provider edge that pushes availability outward from its predecessor.Keeps
providerandsuccessorsynchronized so local offer graphs stay consistent.
API¶
set_provider()validates and stores the resolved provider while synchronizingsuccessor.set_successor()provides a topology-first alias that also updates requirement state.
Example
>>> reg = Registry() >>> r = Affordance(requirement={'has_identifier': 'foo'}); reg.add(r) >>> r.satisfied False >>> e = RegistryAware(label='foo'); reg.add(e) >>> r.successor = e >>> r.satisfied True >>> r.provider <RegistryAware:foo> >>> r.successor <RegistryAware:foo>
Offers and provisioners¶
- class ProvisionPolicy(*values)[source]¶
Bitflag describing allowed or selected provisioning offer kinds.
Requirement instances use these flags to restrict acceptable offer types, while
ProvisionOfferinstances use them to declare what kind of action they represent.
- class ProvisionOffer(_ctx=None, *, uid=<factory>, label=None, tags=<factory>, templ_hash=None, seq=None, origin_id=None, policy, callback, priority=Priority.NORMAL, distance_from_caller=999, specificity=0, exact_kind_match=False, scope_distance=0, build_plan=None, target_ctx=None, candidate=None, **kwargs)[source]¶
Deferred, ranked candidate for satisfying one requirement.
Why¶
Resolution gathers many possible candidates before committing to any single one.
ProvisionOfferkeeps the selection process pure by storing a lazy callback instead of materializing providers eagerly.
- class Provisioner(*args, **kwargs)[source]¶
Structural protocol implemented by offer-producing provisioning helpers.
- class FindProvisioner(values, distance=0)[source]¶
Offer EXISTING providers already present in local entity groups.
- class TemplateProvisioner(registries=(), request_ctx='', graph=None, story_materialize=None, materialize_node=None)[source]¶
Offer CREATE candidates from template registries using scope matching.
- class TokenProvisioner(catalogs=())[source]¶
Offer CREATE token providers from singleton token catalogs.
- class InlineTemplateProvisioner(materialize_node=None, story_materialize=None)[source]¶
Offer inline requirement templates as normal CREATE candidates.
- class StubProvisioner[source]¶
Preview-oriented provisioner that synthesizes minimal matching entities.
- class UpdateCloneProvisioner[source]¶
Synthesizes deferred UPDATE/CLONE offers from selected FIND/CREATE offers.
This provisioner never executes upstream callbacks while constructing offers. It selects the best FIND and CREATE candidates by sort key and emits deferred composite callbacks that sub-accept only when the composite offer itself is accepted by the resolver.
- CloneProvisioner¶
alias of
UpdateCloneProvisioner
Resolution¶
- class Resolver(location_entity_groups=(), template_scope_groups=())[source]¶
Gather, rank, preview, and bind provisioning offers for frontier requirements.
Why¶
Provisioning is where runtime graph gaps become concrete providers. The resolver centralizes offer discovery and binding so story-layer code can define policy without reimplementing the selection mechanics.
Key Features¶
Reads candidate providers from ordered entity groups and template scopes.
Merges FIND, CREATE, TOKEN, inline-template, and synthesized UPDATE/CLONE offers into one ranked stream.
Supports preview mode through blocker diagnostics and optional stub linkage.
Writes selected providers and decision metadata back onto dependency requirements.
API¶
from_ctx()creates a resolver from a compatible vm context.gather_offers()assembles ranked candidates for one requirement.resolve_requirement()andresolve_dependency()bind concrete providers.resolve_frontier_node()resolves all open dependencies for one frontier node.preview_requirement()reports viability without mutating topology.
Selected methods¶
- classmethod Resolver.from_ctx(ctx)[source]¶
Build a resolver from the entity and template groups exposed by
ctx.
- Resolver.gather_offers(requirement, *, allow_stubs=False, preferred_offers=(), _ctx=None)[source]¶
Return ranked offers that are currently admissible for
requirement.Existing providers, template-driven candidates, token catalogs, inline templates, synthesized UPDATE or CLONE offers, and optional dispatch overrides all participate in this one ordered result set.
- Resolver.resolve_requirement(requirement, *, allow_stubs=False, preferred_offers=(), _ctx=None)[source]¶
Resolve and materialize one provider for
requirementif possible.
- Resolver.resolve_dependency(dependency, *, allow_stubs=False, _ctx=None)[source]¶
Resolve one dependency edge and bind its provider into the graph.