feat: derive and set a document's schema_version - #41
Merged
Conversation
An authoring tool should not make the author think about the format's version number. `requiredSchemaVersion` reports the lowest version that can carry a document's components; `setSchemaVersion` restates the declared one through the CST, so comments and key order survive. Together they let an editor keep a draft at the lowest version that can run it — which is also the widest, since an engine only runs versions it knows. Adding a `book` step raises the document on its own; removing it lowers it again. This does not migrate stored documents. The format's promise that a v1 flow keeps working is unchanged, and the comment on KIND_MIN_SCHEMA_VERSION now says which of the two it is talking about. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AFE4mZNdkfPUBbTTwW4e7A
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
The format grew a second version when
bookarrived, and the number leaked into the authoring surface: an editor that adds abookstep to a v1 draft getsnode "book" is a book step, which needs schema_version 2 (this document declares 1). The author placed a step; the answer named a number they have no way to know about.Nothing here decides policy — these are the two primitives an authoring tool needs so it can keep the declared version in step with the components actually placed.
What
requiredSchemaVersion(flow)(model.ts, next toKIND_MIN_SCHEMA_VERSION) — the lowest version that can carry a document's components. Floor of 1, becauseMath.max()of nothing is-Infinityand a new draft has no steps yet.setSchemaVersion(source, version)(mutate.ts, next tostampIdentity) — restates the declared version throughwithDoc, so comments, key order, and theuiblock survive. Lowers as readily as it raises.required_schema_version(flow)— the Rust twin, invalidate.rsbesidekind_min_schema_version.setSchemaVersiongets none:mutate.rsdoesn't exist because the daemon never edits documents, which that file already states.Paired, they let an editor hold a draft at the lowest version that can run it — which is also the widest, since an engine only runs versions it knows. A document that needs nothing newer stays at 1 and stays runnable everywhere.
Not a migration
KIND_MIN_SCHEMA_VERSION's comment said "Documents are never rewritten", which reads as a contradiction sitting next to a function whose job is to rewrite the version. It isn't one — that promise is about stored documents, and it still holds. The comment now says so explicitly rather than leaving the next reader to work it out.Tests
test/model.test.ts: v1-only → 1,book→ 2, falls back when the component is removed, emptynodes→ 1.test/mutate.test.ts: sets the version leaving comments anduialone, lowers as well as raises,parse_failedon unparseable text.validate.rs: the three twin cases.Both languages green —
pnpm --filter @wavekat/flow-schema test(137) andcargo test -p wavekat-flow(53 + 3 conformance).cargo fmt --checkandclippy --all-targetsclean. Corpus untouched: this adds no schema change and no case.🤖 Generated with Claude Code
https://claude.ai/code/session_01AFE4mZNdkfPUBbTTwW4e7A