# Current-Branch Context Checkpoints Status: design frozen for the Wave 7 implementation slice. ## Purpose Long stories must stay inside the selected LAPP model's real context window without silently dropping the current input, triggered world-book entries, runtime facts, or recent committed scenes. A checkpoint is a disposable narrative cache. It is never an authoritative source for flags, relationships, promises, inventory, knowledge, checks, or branch structure. ## Prerequisites Checkpoint persistence starts only after these contracts are represented in code: 1. The selected LAPP model's `context_window` and `max_output_tokens` reach the Runtime provider. 2. The stable prompt prefix has a deterministic resource fingerprint. 3. The narrative source path has a canonical ordered hash that covers committed public story content, not only `RuntimeState`. 4. `Regenerate` excludes the replaced node from narrative history, constrains the replacement with the target node's committed post-state, creates a sibling on a new branch, and reuses existing hidden-check outcomes. ## Prompt budget The provider computes one explicit budget before every model request: ```text hard input budget = model context window - requested output tokens - system prompt and tool schema - message framing overhead - reserved hidden-check continuation overhead - safety margin ``` - Requested output is `min(model.max_output_tokens ?? 4096, 4096)`. - A missing context window uses a conservative 16,384-token V1 fallback, but the resulting `BudgetSource::Assumed` diagnostic must remain visible to the connection/settings layer. The fallback must not be silent. - Cross-provider V1 estimation treats every serialized UTF-8 byte as at most one token. This may compact early but must not optimistically overfill a model window. - Compression starts at 70% of the hard input budget and compacts back below a lower watermark. - The complete dynamic tail is budgeted first. If it does not fit by itself, the request fails with `DynamicTailTooLarge`. - At least one recent committed node remains verbatim. A single oversized node fails with `HistoryEntryTooLarge`; beat text is never truncated. - Every initial and hidden-check continuation `ChatInput` must remain within budget. ## Prompt layout Prompt schema v3 will replace the current v2 history array with one production checkpoint-aware encoder: ```text prompt_schema_version stable_prefix branch_context checkpoint? raw_tail[] dynamic_tail ``` `stable_prefix` remains byte-identical while the bound resources do not change. `dynamic_tail` always contains the current input and the complete safe state projection. A checkpoint replaces only a continuous oldest prefix of `raw_tail`. ## Checkpoint record SQLite schema v3 adds a cache table keyed by the immutable host node, not by branch: ```sql CREATE TABLE context_checkpoints ( story_id TEXT NOT NULL, at_node_id TEXT NOT NULL, covered_through_node_id TEXT NOT NULL, retained_from_node_id TEXT, checkpoint_schema_version INTEGER NOT NULL, prompt_schema_version INTEGER NOT NULL, stable_prefix_hash TEXT NOT NULL, summary_json TEXT NOT NULL, source_hash TEXT NOT NULL, PRIMARY KEY (story_id, at_node_id), FOREIGN KEY (story_id, at_node_id) REFERENCES nodes (story_id, node_id) ON DELETE CASCADE, FOREIGN KEY (story_id, covered_through_node_id) REFERENCES nodes (story_id, node_id) ON DELETE CASCADE, FOREIGN KEY (story_id, retained_from_node_id) REFERENCES nodes (story_id, node_id) ON DELETE CASCADE ); ``` - The nearest checkpoint is found only by walking the current node's `parent_id` chain. - Shared ancestors naturally share a checkpoint; sibling-only descendants are unreachable. - The summary is self-contained. A new checkpoint replaces the old summary instead of nesting a chain of summaries in the prompt. - Successful checkpoint generation may be persisted independently on the existing host node. Failure of the later story-generation call may leave this harmless cache in place. - Deleting every checkpoint must leave nodes, branch heads, materialized state, and `PlayerView` byte-identical. ## Source and resource hashes The model never supplies either hash. `stable_prefix_hash` covers the exact canonical stable-prefix encoding, including character, Persona, resource provenance, and prompt safety/version fields. `source_hash` covers: ```text checkpoint source schema version prompt schema version stable_prefix_hash story id ordered root-to-covered sequence of: node id parent id player input public scene public character visual state committed beats ``` Unselected suggestions, state delta, exact relationship values, checks, NPC private inventory, untriggered world-book content, provider responses, credentials, and chain-of-thought never enter the source manifest or compression request. ## Regenerate boundary `Regenerate` is a full alternative rendering of one committed player choice: - the replaced node is not included in the new prompt; - model history ends at the replaced node's parent, while the target node's authoritative post-state supplies only the already-committed facts and fixed qualitative check outcomes; - the replacement creates a sibling on a new runtime-generated branch; - hidden checks from the original action are supplied as qualitative fixed outcomes and are not rolled again; - a model cannot submit forged `RecordCheck` operations; - old nodes, descendants, and checkpoints remain immutable and become naturally unreachable from the new branch unless they are shared ancestors. The sibling keeps the original player action identity, authoritative delta, terminal state, and exact hidden-check records. Those immutable records intentionally retain their original source-node provenance; the new branch is an alternative presentation of that same committed action, not a new roll or a new state transition. ## Summary safety The summary may retain public causal order, actual player choices, public NPC actions, revealed facts with their certainty, unresolved conflicts, shared goals, and observable emotional residue. It may not become a trigger or rules input. The summary must not contain: - exact dice mechanics or relationship numbers; - private NPC knowledge, private inventory, or unrevealed item provenance; - hidden flags, clocks, event conditions, or untriggered world-book entries; - unselected suggestions, cancelled output, sibling-branch content, or inferred player thoughts; - credentials, request headers, raw provider bodies, or chain-of-thought. The current player inventory projection must not be fed to the summarizer until ownership and acquisition fields have their own player-knowledge visibility boundary. ## Failure semantics - No valid checkpoint and history above the high watermark returns `NeedsCompaction`; history is never silently shortened. - Invalid schema, source hash, stable-prefix hash, range, or summary size makes a checkpoint unusable and rebuildable. - Broken authoritative ancestry or state remains a hard store error and is not downgraded to a cache miss. - Cancelled, timed-out, rate-limited, or malformed compression produces no story node and moves no branch head. - A first load of a very long legacy branch uses bounded rolling chunks and keeps only the final self-contained summary. ## Required gates - Exact window boundary, one-token overflow, unknown-model-limit fallback, and smaller-model switch. - Every normal and hidden-check request stays within the computed budget. - 500-node first compaction and incremental compaction from an existing checkpoint. - v2-to-v3 migration, rollback, restart recovery, cache deletion, and corruption rejection. - Root, shared-ancestor, pre/post-checkpoint fork, regenerate, and sibling-canary isolation. - Stable-prefix cache identity and one cache break only when a checkpoint rotates. - Hidden canaries for checks, exact relationships, NPC facts/items, untriggered resources, unselected suggestions, credentials, and provider bodies.