Skip to content

CORE-135: two history windows, two names

This page records the configuration migration only. It does not edit or sign the shared FP-5 contract, matrix, inventory or dossier.

Decision (owner, Plane CORE-135 comments 1e2b6cad and 0f5ed8a9)

Setting Counts Meaning of N Status
Agent/Kernel working_memory_recent_turns utterances N utterances Unchanged.
Generated app CONVERSATION_HISTORY_EXCHANGES exchanges N exchanges = up to 2N saved rows New, explicit name.
Generated app WORKING_MEMORY_RECENT_TURNS exchanges N exchanges = up to 2N saved rows Deprecated alias; behaviour unchanged.

The two meanings are not interchangeable. The generated app's setting always counted exchanges; only its name matched the framework's utterance count.

Compatibility rules

  • Neither variable set: 5 exchanges (10 rows). Existing default is unchanged.
  • Only the new name set: it selects N exchanges.
  • Only the deprecated name set: same N exchanges, plus a FutureWarning (shown by default, unlike DeprecationWarning).
  • Both set to the same value: accepted, with the warning.
  • Both set to different values: rejected at startup. There is no precedence between them, so there is no silent winner.
  • Negative values are rejected. 0 disables replay, not ownership checks or persistence.

Agent window is conditional (APPROVE CHANGE, not a defect)

With HMS prompting off the legacy route sends the bare query. The Agent's explicit native window stays on. This is documented as an approved change; the Agent is not degraded to match legacy. The differential tests pin this conditional behaviour. They do not assert whole-prompt parity and do not claim native stream_typed coverage.

Data flow

flowchart TD
    ENV[".env / environment"] --> S["Settings"]
    S -->|"CONVERSATION_HISTORY_EXCHANGES"| R["history_exchanges"]
    S -->|"WORKING_MEMORY_RECENT_TURNS (deprecated)"| R
    S -->|"both set and different"| X["ValidationError at startup"]
    R --> P["ChatConversationPort(exchanges)"]
    H["POST /api/v1/chat"] --> P
    P --> O{"session owned by principal user and tenant?"}
    O -->|no| N["404, provider not called"]
    O -->|yes| Q["last 2N saved rows of that session"]
    Q --> A["Agent history"]
    W["Framework working_memory_recent_turns (N utterances)"] -.->|"separate, unchanged"| A

Evidence

  • tests/retirement/test_core135_history_exchanges_setting.py: public generated-app turns; unset default is 10 rows, the new name selects N exchanges, the alias warns, conflicts and negatives are rejected, other sessions and other tenants never reach the provider.
  • tests/retirement/test_core135_window_prompt_and_scaffold.py: 2N rows and owner/tenant refusal at the port.
  • One-time local mutation run, not a recorded artifact: limit not doubled, app reading the alias, property ignoring the new name, conflict allowed and session filter dropped each turned the new file red; a dropped tenant filter was caught only by the port-level refusal test in the second file.