schema stamps: lazy v1 for chats + the graph family, honest refusal

Chat records gain version (CURRENT_CHAT_VERSION), stamped by a single
writeChat choke point in the store; absence reads as v1 — existing files
migrate on their next write, no mass rewrite. The graph family (four JSONL
ledgers, sources.json, render-settings.json) shares one lazy sidecar,
graph/format.json; positions stays unstamped (rebuildable) and jobs stay
unstamped (transient).

Downgrade scenario ruled honest-refusal: records stamped newer than the
running build read as absent (chats, logged) or throw (graph family) — a
read-modify-write store never rewrites what it doesn't understand.

Golden fixtures stay the unstamped legacy shape on purpose (lazy v1 is
current-valid by design); the stamped write path is pinned by
tests/schema-stamps.test.ts. Reads never write — the golden byte-identical
pin holds.
This commit is contained in:
amosblomqvist
2026-10-10 13:54:17 +03:00
parent bc09ec25e1
commit eda5491010
10 changed files with 245 additions and 10 deletions
+9
View File
@@ -52,8 +52,17 @@ export interface ChatRecord {
extractions?: ExtractionRunUsage[];
/** Per-chat model/thinking overrides for the conversation agents. */
settings?: ChatSettings;
/** SCHEMA STAMP (schema-versioning wave, owner 2026-10-10): LAZY v1 —
* existing records stay unstamped (absence reads as v1); every write
* stamps the current version. A record stamped NEWER than this build
* (the downgrade scenario) is REFUSED on read: a read-modify-write
* store must never rewrite what it doesn't understand. */
version?: number;
}
/** The chat record format this build writes and understands. */
export const CURRENT_CHAT_VERSION = 1;
/** The conversation agents' runtime model choice (model-control wave,
* 2026-09-12): a per-chat override of config.ts's pinned prober/teacher
* spec. Absent fields fall back to config; written by the model picker
+4
View File
@@ -120,6 +120,10 @@ export interface NamingRunStats {
appended: number;
}
/** The graph-family format version this build writes and understands
* (the format.json sidecar — src/store/graph-format.ts). */
export const CURRENT_GRAPH_FORMAT_VERSION = 1;
export interface GraphNode {
/** Opaque stable id, store-assigned: "n_" + nanoid-like. */