Plan Store v1 to v2: Migration Guide
rocky plan writes each plan to .rocky/plans/<plan-id>.json for rocky apply to read back. For rocky compact and rocky archive plans, the typed-IR v2 envelope is now the only shape that loads. The legacy v1 inline-SQL envelope is retired, and the [plan_store] config block that chose between them has been removed.
What’s changed
Section titled “What’s changed”- A v1 plan no longer loads. Compact and archive plans written before engine-v1.35.0, the v1 default era, fail at
rocky apply <plan-id>. The error carries a migration message. Re-runrocky compactorrocky archiveto write a fresh v2 plan. - The
[plan_store]block has been removed. A project that still carries it fails to parserocky.tomlwith an “unknown field” error. That usually means a project pinned toformat = "v1"after the v1.35.0 default flip. Delete the block. Run/Replication/Promoteplans are untouched. They never used the inline-SQL envelope. They carry operational metadata (run and replication), or per-target SQL as a documented governance-audit exception (promote). Their on-disk shape is unchanged.
Stdout JSON is unchanged. rocky plan --output json, rocky compact --output json, and rocky archive --output json all still carry inline SQL for human and CI consumers. Only the persisted on-disk shape was simplified.
What each format holds
Section titled “What each format holds”The file path (.rocky/plans/<plan-id>.json) and the blake3 content-addressed plan-id are unchanged. Only the body shape changed:
- v1 (retired). The envelope carried inline SQL as the payload.
rocky applyread the SQL out of the plan and sent it to the warehouse verbatim. - v2 (the only loadable shape). The envelope carries the typed-IR payload:
CompactPlanIrforrocky compactplans,ArchivePlanIrforrocky archiveplans.rocky applyregenerates the SQL from that IR at execution time, through therocky_core::sql_gen::{compact_from_ir, archive_from_ir}helpers in therocky-corecrate. The IR types themselves live inrocky-ir.
Migration recipe
Section titled “Migration recipe”Follow this when rocky apply <plan-id> fails with a “plan is in format v1” error after an upgrade.
- Delete any
[plan_store]block from yourrocky.toml. The block no longer parses, sorocky.tomlfails on first load while it is still there. Its oldformatsetting is now a no-op, because v2 is the only shape. - Re-plan. Run
rocky plan, orrocky compact <model>, orrocky archive --older-than <age>. This writes a fresh v2 envelope under a newplan-id. The id is content-addressed, so the same intent against an unchanged source state yields the same id on any machine. - Apply the new plan. Run
rocky apply <new-plan-id>. The v2 reader regenerates SQL from the typed IR and produces the same warehouse outcome the retired v1 path would have.
There is no in-place upgrade. A stale v1 envelope is simply not parseable. Re-planning is the only path, and it is cheap: it reads the same rocky.toml and models/ you already have.
Timeline
Section titled “Timeline” engine-v1.33.0 engine-v1.35.0 this release ────────────── ────────────── ──────────── writer: v1 writer: v2 writer: v2 reader: v1 and v2 reader: v1 and v2 reader: v2 only v2 opt-in through v1 pinnable through [plan_store] block [plan_store] [plan_store] removed │ │ │ ▼ ▼ ▼ adopters could the legacy shape a v1 plan on disk validate v2 before stayed available no longer loads; the default flip on request re-plan to move onThe release notes that ship this change name the version it lands in.
Related
Section titled “Related”- Content-Addressed Materialization — another writer surface where blake3 content hashing keys the on-disk artefact.