On this page

Conduit categories as factories๏ƒ

๐ŸŸก Intermediate ยท Lesson 26

Conduit CATEGORIES are your factory layer. Instead of writing an abstract factory in front of your scopes, NAME conduits after the resolution ideas your app already has - "platform", "services", "workflows" - and late-bind the dependencies BETWEEN categories with SpellContract sockets. ORDER OF OPERATIONS IS THE LAW (owner ruling 2026-07-20). Per dependency edge, in this exact order: 1) conjure the PROVIDER conduit 2) conjure the CONSUMER conduit (the SpellContract side) 3) link() - only AFTER both conduits are built 4) the consumer pulls the provider spell into the contract 5) meld AFTER the fact - completing the late binding for that world's products Assemble the chain edge by edge, in dependency order. No factory objects exist anywhere - the conduit NAMES are the factory types. THE ARC: this is beginner lesson 25 one level UP. Spellframes categorize spells WITHIN one world; conduits categorize WORLDS - each category gains an OWNER, and permissions + contracts + links set the resolution conditions at the category boundary.

Before you run๏ƒ

Use the Intermediate guide for prerequisite concepts. Run from a checkout with Melder installed and Python 3.14 free-threading selected. The collection download includes the level's local helper modules.

Run the saved script๏ƒ

python UX_and_AIX_experiences/02_intermediate/26_conduit_categories_as_factories.py
py -3.14t UX_and_AIX_experiences/02_intermediate/26_conduit_categories_as_factories.py

Download this collection ยท Source on GitHub

Public surface๏ƒ

md.SpellContract, link, add_spell_to_contract, named category conduits

Code๏ƒ

  1"""
  2TIER: intermediate (26)
  3GOAL: Conduit CATEGORIES are your factory layer. Instead of writing an
  4      abstract factory in front of your scopes, NAME conduits after the
  5      resolution ideas your app already has - "platform", "services",
  6      "workflows" - and late-bind the dependencies BETWEEN categories
  7      with SpellContract sockets.
  8      ORDER OF OPERATIONS IS THE LAW (owner ruling 2026-07-20). Per
  9      dependency edge, in this exact order:
 10        1) conjure the PROVIDER conduit
 11        2) conjure the CONSUMER conduit (the SpellContract side)
 12        3) link() - only AFTER both conduits are built
 13        4) the consumer pulls the provider spell into the contract
 14        5) meld AFTER the fact - completing the late binding for that
 15           world's products
 16      Assemble the chain edge by edge, in dependency order. No factory
 17      objects exist anywhere - the conduit NAMES are the factory types.
 18      THE ARC: this is beginner lesson 25 one level UP. Spellframes
 19      categorize spells WITHIN one world; conduits categorize WORLDS -
 20      each category gains an OWNER, and permissions + contracts + links
 21      set the resolution conditions at the category boundary.
 22SURFACE EXERCISED: md.SpellContract, link, add_spell_to_contract,
 23                   named category conduits
 24"""
 25import sys
 26from pathlib import Path
 27from typing import Protocol
 28
 29sys.path.insert(0, str(Path(__file__).parent))  # local helper (see _dynamic_world)
 30from _dynamic_world import dynamic_spellbook
 31
 32import melder as md
 33
 34
 35class ConfigContract(Protocol):
 36    def get(self, key: str) -> str: ...
 37
 38
 39class ReportingContract(Protocol):
 40    def report(self) -> str: ...
 41
 42
 43class ConfigStore:
 44    """Owned by the "platform" category."""
 45
 46    def get(self, key: str) -> str:
 47        return f"{key}-from-platform"
 48
 49
 50class ReportService:
 51    """Owned by "services". Its config is a LATE-BOUND hole: the socket
 52    names the contract identity; the provider arrives across the link."""
 53
 54    def __init__(
 55        self,
 56        config: ConfigContract = md.SpellContract(
 57            spellframe=ConfigContract, binding_name="platform",
 58        ),
 59    ) -> None:
 60        self.config = config
 61
 62    def report(self) -> str:
 63        return f"report({self.config.get('region')})"
 64
 65
 66class ReportWorkflow:
 67    """Owned by "workflows". Same idea one level up: it wants whatever
 68    satisfies the reporting contract, wherever that conduit lives."""
 69
 70    def __init__(
 71        self,
 72        service: ReportingContract = md.SpellContract(
 73            spellframe=ReportingContract, binding_name="reporting",
 74        ),
 75    ) -> None:
 76        self.service = service
 77
 78    def run(self) -> str:
 79        return f"workflow -> {self.service.report()}"
 80
 81
 82def main() -> None:
 83    # One book per CATEGORY - each book is that category's recipe list.
 84    platform_book = dynamic_spellbook()
 85    config_id = platform_book.bind(
 86        spell=ConfigStore, existence="unique",
 87        spellframe=ConfigContract, binding_name="platform",
 88    )
 89    services_book = dynamic_spellbook()
 90    service_id = services_book.bind(
 91        spell=ReportService, existence="unique",
 92        spellframe=ReportingContract, binding_name="reporting",
 93    )
 94    workflows_book = dynamic_spellbook()
 95    workflow_id = workflows_book.bind(spell=ReportWorkflow, existence="unique")
 96
 97    # ---- EDGE 1: platform feeds services ----
 98    platform = platform_book.conjure(dynamic=True, name="platform")  # 1) provider
 99    services = services_book.conjure(dynamic=True, name="services")  # 2) consumer
100    platform.link(services)                                          # 3) link AFTER both
101    services.add_spell_to_contract(                                  # 4) pull
102        spell_id=config_id, conduit=platform, permissions="create",
103    )
104    service = services.meld(spell_id=service_id)                        # 5) meld after the fact
105
106    # ---- EDGE 2: services feeds workflows (same cycle, one level up) ----
107    workflows = workflows_book.conjure(dynamic=True, name="workflows")
108    services.link(workflows)
109    workflows.add_spell_to_contract(
110        spell_id=service_id, conduit=services, permissions="create",
111    )
112    workflow = workflows.meld(spell_id=workflow_id)
113
114    assert workflow.service is service  # the finished product crossed the edge
115    print("category chain resolved:", workflow.run())
116    print("factory types were just conduit names:",
117          platform.name, "->", services.name, "->", workflows.name)
118
119
120if __name__ == "__main__":
121    main()

Check the outcome๏ƒ

The script contains its own assertions or demonstrated refusal paths. Run it to evaluate those checks against your installed version. The code above is taken directly from the saved file; no run output is invented here.

More intermediate examples ยท Level guide

API contracts๏ƒ