Files

2.7 KiB

Context must be ordered stable-to-volatile — the stable prefix (layers 1-7) gets cached, the volatile suffix (layers 8-12) never does

1. The 12-layer model (the stable-to-volatile ordering)

# Layer Stable across turns? Source SSDL
1 Role instructions (model + provider) yes _get_combined_system_prompt [I]
2 Function-calling schema yes per provider [I]
3 Discovered tool descriptions yes mcp_client.get_tool_schemas() [I]
4 System prompt preset yes app_state.ai_settings.system_prompt [I]
5 Persona profile yes app_state.active_persona [I]
6 Project context (per manual_slop.toml) yes NEW (Candidate 14) [I]
7 Knowledge digest (per knowledge/digest.md) yes (within a gc cycle) NEW (Candidate 8) [I]
8 Discussion metadata (name, role count) no (per turn) disc_entries[:1] or disc_meta ─── (data)
9 Active preset (FileItem set) no (per turn) self.context_files ─── (data)
10 Per-file details (history, slices, notes) no (per file) per FileItem ─── (data)
11 Tool-call results from prior turns no (per turn) per _reread_file_items ─── (data)
12 The user message no (per turn) the input ─── (data)

The cache boundary is at layer 7/8. Layers 1-7 are byte-identical across turns of the same discussion (and across discussions of the same mode). Layers 8-12 change per turn.


2. The byte-comparison test (the design contract)

The design rule "stable prefix is byte-identical" must be testable. The test:

# In tests/test_aggregate_caching.py (NEW)
def test_aggregate_stable_to_volatile_ordering():
    """The first N characters of the context should be identical across turns
    of the same conversation, when no stable-layer inputs change."""
    ctrl = mock_app_controller()
    ctrl.ai_settings.system_prompt = "Test system prompt"
    ctrl.active_persona = mock_persona()

    # Turn 1
    turn1 = aggregate.build_initial_context(ctrl, user_message="first prompt")

    # Turn 2 (same stable inputs, different user message)
    turn2 = aggregate.build_initial_context(ctrl, user_message="second prompt")

    # The first N characters should be identical (N = where the volatile layers start)
    N = aggregate.stable_prefix_length(ctrl)
    assert turn1[:N] == turn2[:N], f"Stable prefix mismatch: {turn1[:N]!r} != {turn2[:N]!r}"

The test is the contract. If a new layer is added in the middle of the stack, this test fails; the agent must either move the layer to the stable position or update the test (with written justification).