Skip to content

symfonic.capabilities.prompting.boundaries

boundaries

Scope isolation and inheritance — what travels, and what a key may collapse.

Two rules, both about content crossing a boundary it was not compiled for.

Isolation keys stored content by the full scope path, as a tuple. A joined string would let a contribution id containing the path separator forge a level boundary and read another scope's stored revision; a tuple cannot be forged that way, because the separator is structural rather than lexical.

Inheritance decides what a delegated child sees of its parent's standing context. The default is that a declared contribution travels — a child that lost its boundaries is the dangerous direction — and the contributions that must not travel say so explicitly.

inheritable

inheritable(contributions: Iterable[PromptContribution]) -> tuple[PromptContribution, ...]

The subset of contributions a delegated child may see.

Source code in src/symfonic/capabilities/prompting/boundaries.py
def inheritable(
    contributions: Iterable[PromptContribution],
) -> tuple[PromptContribution, ...]:
    """The subset of ``contributions`` a delegated child may see."""
    return tuple(c for c in contributions if c.inherit)

isolation_key

isolation_key(scope_path: str, contribution_id: str) -> tuple[str, str]

The canonical storage key for one contribution in one scope.

The scope half is the full root-first path verbatim, not a tenant id: keying on the tenant alone would collapse every brand and conversation under an organisation into one bucket, so two sibling scopes would share — and overwrite — one another's stored revisions.

Source code in src/symfonic/capabilities/prompting/boundaries.py
def isolation_key(scope_path: str, contribution_id: str) -> tuple[str, str]:
    """The canonical storage key for one contribution in one scope.

    The scope half is the full root-first path verbatim, not a tenant id:
    keying on the tenant alone would collapse every brand and conversation
    under an organisation into one bucket, so two sibling scopes would share —
    and overwrite — one another's stored revisions.
    """
    return (scope_path, contribution_id)