# ADR-0010: Every persisted shape carries `schemaVersion: 1`; loaders raise `UnknownSchemaVersionError` on mismatch

**Status:** Accepted (Phase 2; Anti-Pattern 9 mitigation)

## Context

Anti-Pattern 9 (Unversioned Schema) is the bug where today's persisted JSON
is silently re-interpreted under tomorrow's schema, producing zombie
objects with the wrong fields and no error. Workspace state, parked tabs,
viewport positions — all of these are persisted as opaque JSON in the
SQLite-backed server. Without a version stamp, a future schema change
either has to be backward-compatible forever or risk silent corruption.

## Decision

Every persisted shape (`WorkspaceState`, `ColumnLayout`, `TabState`,
`ParkedTab`, `Tweaks`, `ViewportPosition`, `ParkedContext`, `EngineEvent`)
includes `schemaVersion: z.literal(1)`. The shared constant
`SCHEMA_VERSION = 1 as const` lives in `packages/contracts/src/manual.ts`.
Loader functions (e.g., `parseWorkspaceState`) check the field FIRST and
throw `UnknownSchemaVersionError` (defined in `errors.ts`) when it doesn't
match a supported version. They do not best-effort parse.

## Consequences

A future schema bump (v2) will require a coordinated migration: bump the
literal, ship a migrator that reads v1 and emits v2, update every loader
to accept both. The error message tells JT exactly what shape, what
received version, and what's supported, so the failure mode is explicit
rather than silent. The cost: every persisted shape carries a 4-byte
sentinel field forever. Trivially worth it.
