Skip to content

symfonic.capabilities.memory.stage_descriptors

stage_descriptors

The stage descriptors this capability contributes, one per seam.

Their own module because they are declarations rather than behaviour, and because bridge.stages() already carried a set that drifted from what the capability actually folds: the write descriptor there was left at the default COMPILATION kind while declaring effects, which nothing caught for as long as nothing folded it. Keeping the folded descriptors in one readable place is what makes that kind of drift visible.

consolidation_stage

consolidation_stage() -> StageDescriptor

Extract durable facts after the final model round, before baseline writes.

Source code in src/symfonic/capabilities/memory/stage_descriptors.py
def consolidation_stage() -> StageDescriptor:
    """Extract durable facts after the final model round, before baseline writes."""
    return StageDescriptor(
        stage_id=CONSOLIDATION_STAGE,
        phase=Phase.POST_MODEL,
        capability=HMS_CAPABILITY,
        priority=50,
        effects=frozenset({"memory-write"}),
        kind=StageKind.RESOLUTION,
        emits=frozenset({"memory.consolidated"}),
    )

lifecycle_stage

lifecycle_stage() -> StageDescriptor

The FINALIZE descriptor: the last rung a capability may reach.

Source code in src/symfonic/capabilities/memory/stage_descriptors.py
def lifecycle_stage() -> StageDescriptor:
    """The FINALIZE descriptor: the last rung a capability may reach."""
    return StageDescriptor(
        stage_id=LIFECYCLE_STAGE,
        phase=Phase.FINALIZE,
        capability=HMS_CAPABILITY,
        priority=900,
        effects=frozenset({"memory-flush"}),
        kind=StageKind.RESOLUTION,
        emits=frozenset({"memory.flushed"}),
    )

nap_stage

nap_stage() -> StageDescriptor

The nap, after the flush published what the turn staged.

Priority above lifecycle_stage's 900 and in the same phase, so the order is the one legacy had: the engine scheduled quick_nap once the turn was done, and a roster that ran before the flush would consolidate a store missing the very memories this turn produced.

Not Phase.TEARDOWN, which would read as the more natural home: teardown is kernel-owned and closed to capabilities, and FINALIZE is the last rung one may reach. The answer is still not held for it -- the handler hands the cycle to the run's background registry unless the deployment asked to wait.

Source code in src/symfonic/capabilities/memory/stage_descriptors.py
def nap_stage() -> StageDescriptor:
    """The nap, after the flush published what the turn staged.

    Priority above ``lifecycle_stage``'s 900 and in the same phase, so the
    order is the one legacy had: the engine scheduled ``quick_nap`` once the
    turn was done, and a roster that ran before the flush would consolidate a
    store missing the very memories this turn produced.

    Not ``Phase.TEARDOWN``, which would read as the more natural home: teardown
    is kernel-owned and closed to capabilities, and ``FINALIZE`` is the last
    rung one may reach. The answer is still not held for it -- the handler
    hands the cycle to the run's background registry unless the deployment
    asked to wait.
    """
    return StageDescriptor(
        stage_id=NAP_STAGE,
        phase=Phase.FINALIZE,
        capability=HMS_CAPABILITY,
        priority=950,
        # Optional, not hard: a deployment can record without publishing
        # in the same turn, and a hard edge would refuse to compile that
        # ladder rather than order the two stages it does have.
        optional_after=(LIFECYCLE_STAGE,),
        effects=frozenset({"memory-consolidate"}),
        kind=StageKind.RESOLUTION,
        emits=frozenset({"memory.napped"}),
    )

retrieval_stage

retrieval_stage() -> StageDescriptor

Recall, resolved before the prompt compiler reads what it left.

Source code in src/symfonic/capabilities/memory/stage_descriptors.py
def retrieval_stage() -> StageDescriptor:
    """Recall, resolved before the prompt compiler reads what it left."""
    return StageDescriptor(
        stage_id=RETRIEVAL_STAGE,
        phase=Phase.PROMPT_ASSEMBLY,
        capability=HMS_CAPABILITY,
        priority=_RETRIEVAL_PRIORITY,
        optional_before=(PROMPT_COMPILER_STAGE,),
        effects=frozenset({"memory-read"}),
        kind=StageKind.RESOLUTION,
    )

write_stage

write_stage() -> StageDescriptor

The POST_MODEL descriptor, declared where the handler is.

bridge.stages() has carried a memory.write descriptor since T3.2.3, but with the default kind -- compilation -- which may not declare effects. It was never folded, so nothing checked it. Declared here as the RESOLUTION it is: it reaches the store, once, under a grant.

Source code in src/symfonic/capabilities/memory/stage_descriptors.py
def write_stage() -> StageDescriptor:
    """The POST_MODEL descriptor, declared where the handler is.

    ``bridge.stages()`` has carried a ``memory.write`` descriptor since T3.2.3,
    but with the default ``kind`` -- compilation -- which may not declare
    effects. It was never folded, so nothing checked it. Declared here as the
    RESOLUTION it is: it reaches the store, once, under a grant.
    """
    return StageDescriptor(
        stage_id=WRITE_STAGE,
        phase=Phase.POST_MODEL,
        capability=HMS_CAPABILITY,
        priority=100,
        effects=frozenset({"memory-write"}),
        kind=StageKind.RESOLUTION,
        emits=frozenset({"memory.written"}),
    )