Files
nana-story/docs/context-checkpoint-design.md
T

8.1 KiB

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:

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:

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:

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:

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.