Skip to content

symfonic.platform.transport_scope_refusal

transport_scope_refusal

Bind a router's memory_identity and answer its version refusal (CORE-171).

The transport cannot see which identity a host's Agent composes: an adopter composer may keep kinds (v1) or convert to positional v0 from the very same typed scope. memory_identity is that declaration. Bound per request here, it lets wire.record_scope address the declared row and lets wire.memory_scope refuse, before any store call, a v0-only route whose declared identity is v1. That refusal is mapped to 501 once, here, so a route added later cannot forget to. A declaration the request cannot use -- it raises, returns no MemoryScope, or roots one at another tenant -- is a server misconfiguration: 500 with wire.MEMORY_IDENTITY_REFUSAL as the detail, before any store call. Undeclared routers keep positional v0.

Every route create_kernel_agent_router mounts is added to the router this class is bound to; it includes no sub-router, whose routes would keep their own class. test_core171_http_record_bridge pins both.

refusing_route_class

refusing_route_class(memory_identity: Any = None) -> Any

An APIRoute binding memory_identity; a version refusal is 501.

Source code in src/symfonic/platform/transport_scope_refusal.py
def refusing_route_class(memory_identity: Any = None) -> Any:
    """An ``APIRoute`` binding ``memory_identity``; a version refusal is 501."""
    from fastapi.responses import JSONResponse
    from fastapi.routing import APIRoute

    from symfonic.platform.wire import (
        MEMORY_IDENTITY_REFUSAL,
        MemoryIdentityRefused,
        NativeScopeRouteRefused,
        declared_identity,
    )

    if memory_identity is not None and not callable(memory_identity):
        raise TypeError("memory_identity must map a request scope to a MemoryScope")

    class _RefusingRoute(APIRoute):
        def get_route_handler(self) -> Any:
            handler = super().get_route_handler()

            async def route(request: Any) -> Any:
                try:
                    with declared_identity(memory_identity):
                        return await handler(request)
                except NativeScopeRouteRefused as refused:
                    return JSONResponse({"detail": str(refused)}, status_code=501)
                except MemoryIdentityRefused as refused:
                    cause = type(refused.__cause__).__name__ if refused.__cause__ else "result"
                    _log.error("memory_identity refused a request scope (%s)", cause)
                    return JSONResponse({"detail": MEMORY_IDENTITY_REFUSAL}, status_code=500)

            return route

    return _RefusingRoute