Provisioning Pipeline¶
Overview¶
Provisioning is the process the VM uses to satisfy :class:~tangl.core.requirement.Requirement
objects before the story advances. Each frontier node exposes requirements for actors,
locations, or resources. Provisioners compete to satisfy those requirements by producing
:class:~tangl.vm.provision.offer.Offer objects. The planner selects the best offer for each
requirement, applies it, and records a :class:~tangl.vm.provision.receipt.BuildReceipt for auditing.
Provisioner Sequence¶
GraphProvisioner – Finds already-instantiated nodes that satisfy the requirement.
TemplateProvisioner – Instantiates templates (see below) if the requirement references one.
Updating / Cloning Provisioners – Modify or duplicate existing entities when requested.
Provisioners may return zero or more offers. The planner picks the lowest-cost viable offer, so custom provisioners should surface clear cost semantics.
TemplateProvisioner Flow¶
Template provisioning is the most common path for casting roles and populating settings:
Requirement intake: Requirements coming from story scripts now include
template_refwhen aRoleScriptorSettingScriptreferences a template label. Inline templates are still supported via the legacytemplatedict.Template lookup: The provisioner pulls templates from
world.template_registry. Templates are :class:~tangl.ir.core_ir.base_script_model.BaseScriptIteminstances and already include a content-addressed hash (content_hash).Scope filtering: Before an offer is created,
_is_in_scopevalidates that the template’sscopeallows it to be used for the current source node. See :doc:../authoring/TEMPLATE_SCOPEfor examples of block, scene, and ancestor filtering.Offer creation: Offers embed the template, its registry label, and a short content identifier (
template.get_content_identifier()). No additional hashing is necessary because :class:~tangl.core.content_addressable.ContentAddressablehandles it.Build step: When selected, the offer is converted into a concrete entity. The provisioner resolves
kind, hydrates the payload from the template, applies requirement overrides, and writes a build receipt including the template reference and hash for provenance.
If any step fails—missing template, scope rejection, or unresolved class—the provisioner simply returns no offers and logs a debug/warning message, allowing other provisioners or policies to handle the requirement.
Scope Semantics¶
Template scope determines where a template can be used:
Global templates (
scope=None) can satisfy any role/setting.Scene templates (inferred
parent_label) are limited to blocks within that scene.Block templates (inferred
source_label) can only fill roles/settings in the block where the template was declared.Advanced selectors like
ancestor_labelsandancestor_tagsenforce ancestry constraints.
Because scope enforcement runs inside the TemplateProvisioner, authors get immediate feedback in
planning logs when a template reference is out of scope. Refer to :doc:../authoring/TEMPLATE_SCOPE
for author-facing guidance and YAML examples.
Debugging Provisioning¶
Enable debug logging for
tangl.vm.provisioners.template_provisionerto see why templates are rejected (missing source, parent mismatch, missing tags, etc.).Inspect build receipts in the ledger; each contains
template_refandtemplate_hashso you can trace exactly which template was instantiated.Use
world.template_registry.find_all(content_hash=...)to locate duplicate templates if you suspect multiple declarations share the same content.
Cost Model & Auditing¶
Offer selection is now deterministic and proximity-aware:
Base costs come from :class:
~tangl.vm.provision.offer.ProvisionCost(e.g.,DIRECT=10,CREATE=200).Graph proximity adds a modifier before the planner compares offers:
Scenario
Modifier
Same block
+0Same scene
+5Same episode
+10Elsewhere
+20Template offers use the fixed create cost (
200) so nearby existing providers almost always win unless the requirement policy isCREATE.
Every call to :func:~tangl.vm.provision.resolver._select_best_offer records audit metadata. The
final :class:~tangl.vm.provision.offer.PlanningReceipt includes selection_audit, a list of the
offers considered for each requirement plus the reason the winner was chosen. Developers can print
these decisions with :class:tangl.vm.debug.PlanningDebugger.
See :doc:COST_MODEL for an extended breakdown of the calculations and troubleshooting tips.