Skip to content

symfonic.platform.procedural_local

procedural_local

Opt-in procedural composition for ONE explicitly configured local worker.

Backend, audit and replay state die together. This is not durable audit or multi-worker admission: independently misconfigured processes are NOT detected. Clients must send the issued epoch; restart never promises safe replay. POST requires Idempotency-Key and X-Procedural-Epoch (binding.epoch supplied out of band by composition). Success includes epoch/operation_id/audit. An omitted-ID exact-owner dedup is legitimately 200; replay preserves status.

LocalProceduralAudit

LocalProceduralAudit()

Exact synchronous in-memory ACK; no user callbacks, await or reentrancy.

Records contain hashes/identifiers, never payload or idempotency keys. Capacity refusal occurs BEFORE a mutation; callers must rotate the whole local composition, not silently discard replay/audit evidence.

Source code in src/symfonic/platform/procedural_local_authority.py
def __init__(self):
    self._records = []
    self._recording = False
    self._epoch = None
    self._reserved = {}

terminal

terminal(operation)

Completion ACK is provisional; rollback supersedes it on exit fault.

Source code in src/symfonic/platform/procedural_local_authority.py
def terminal(self, operation):
    """Completion ACK is provisional; rollback supersedes it on exit fault."""
    for record in reversed(self._records):
        if record["operation_id"] == operation:
            outcome = record["outcome"]
            return outcome if outcome in {"completed", "rolled_back"} else "unknown"
    return "unknown"

LocalProceduralAuthority

LocalProceduralAuthority(owners)

Explicit server allowlist; possession of a header/grant is not authority.

Scope grants are exact canonical kind-aware owners, never ancestor wildcards. Revocation is synchronous and invalidates all outstanding grants.

Source code in src/symfonic/platform/procedural_local_authority.py
def __init__(self, owners):
    self._owners = {(principal, native_owner(scope).path) for principal, scope in owners}
    self._revision = 0
    self._issued = {}

LocalProceduralHost

LocalProceduralHost(provider, *, authority, sink, workers, include_drafts=False, observe_provider_call=None)

Bases: AgentHost

Host-issued binding; no arbitrary composer/service may substitute.

workers is the composition root's explicit deployment declaration, not global detection. Deployment MUST actually use one worker/event loop. Inherited PID/loop and foreign resource/binding use are refused.

Source code in src/symfonic/platform/procedural_local.py
def __init__(
    self,
    provider,
    *,
    authority,
    sink,
    workers,
    include_drafts=False,
    observe_provider_call=None,
):
    from symfonic.capabilities.memory import ProceduralCreateService, procedural_layer
    from symfonic.memory.backends import InMemoryGraphBackend
    from symfonic.platform.procedural_local_write import _Binding

    if type(self) is not LocalProceduralHost or type(workers) is not int or workers != 1:
        raise TypeError("local procedural admission requires exact host and workers=1")
    if (
        type(authority) is not LocalProceduralAuthority
        or type(sink) is not LocalProceduralAudit
    ):
        raise TypeError("local procedural admission requires explicit local authority and sink")
    if not callable(provider) or type(include_drafts) is not bool:
        raise TypeError("provider factory and explicit boolean preview are required")
    backend = InMemoryGraphBackend()
    layer = procedural_layer(backend, native_scopes=True)
    resources = _Resource(backend, layer, ProceduralCreateService(layer))
    super().__init__(
        composer=_Composer(resources, provider, observe_provider_call, include_drafts),
        resources=resources,
    )
    self._procedural = _Binding(self, resources, authority, sink)