Skip to content

feat(schema): make adding a key a compatible change - #201

Merged
willkg merged 3 commits into
mainfrom
open-json-schema
Sep 25, 2026
Merged

willkg merged 3 commits into
mainfrom
open-json-schema

Conversation

@willkg

@willkg willkg commented Sep 25, 2026

Copy link
Copy Markdown
Member

Fixes #200. v0.1.0 has --json consumers, and the published schema closed every object with additionalProperties: false, so any new key was a breaking change in practice. #10 needs one (update's moved), so this comes first. Plan: _plans/054_open-json-schema.md.

The published schema is open. Every additionalProperties: false is gone. That only loosens the schema, so it is itself compatible and schema_version stays 1. docs/json-output.md has a new Compatibility section with the rule:

  • Compatible: a new key, a looser constraint, a new command, or a new frontmatter field reported by diff. diff's field is now a plain string for that reason.
  • Breaking, so schema_version increases: a removed or renamed key, a changed type or meaning, a newly nullable key, or a new value in any other enum (code, a result's status...).

The drift guard is unchanged. internal/schematest validates against a copy closed in memory: additionalProperties: false goes back on every node declaring "type": "object" with properties. Closing the new file reproduces main's schema exactly, apart from the union change below. markfluence schema still prints the file byte for byte. New tests keep the file open, fail any node that lists properties without a type (which the guard would silently leave open), and pin that an unlisted key fails the closed copy and passes the published one.

Result-or-failure unions are anyOf. With open objects, a failed export row has every key singleOpFailure requires, so it matched both branches and oneOf refused it. All eight such unions changed; anyOf is looser, so this is compatible too.

Also: markfluence schema --help says the schema is open and what that asks of consumers, and a few code comments that described the schema as closed now name the closed test copy.

Plan for #200: make adding a key a compatible --json schema change.
v0.1.0 has --json consumers, and the published schema closed every
object with additionalProperties: false, so a consumer validating
against an older copy rejected any key added since. That made every new
field a breaking change in practice.

The published schema is now open, and docs/json-output.md says what is
compatible (a new key, a looser constraint) and what increases
schema_version (a removed, renamed or retyped key, a newly nullable key,
a new enum value). Opening the schema only loosens it, so this is itself
compatible and schema_version stays 1.

The drift guard is unchanged: schematest validates against Closed(schema),
which puts additionalProperties: false back on every object schema that
lists properties. Before the edit, Closed applied to the stripped schema
reproduced the old file exactly.

Opening the objects made three result-or-failure unions ambiguous: a
failed export row has every key singleOpFailure requires, so it matched
both branches and oneOf refused it. All eight such unions are now anyOf.

Fixes #200.
- Split the enums: a new command, or a new frontmatter field reported by
  diff, is a compatible change. diff's field is now a plain string for
  that reason, and command says why a new value breaks nobody. Every
  other enum stays closed, so a new value bumps schema_version.
- The schema's description points at docs/json-output.md instead of
  restating part of the rule; CLAUDE.md gains the nullable case.
- schema --help says the schema is open and what that asks of consumers.
- The closing is unexported (closeObjects) and shares one walker with the
  tests. The walker skips instance data (const, enum, default, examples)
  and steps through name-keyed maps: infoResult has a property named
  "properties", which the old walk read as a schema.
- TestEveryPropertiesNodeIsTyped fails a node listing properties without
  "type": "object", which the drift guard would otherwise leave open.
- TestPublishedSchemaIsOpen fails only additionalProperties: false.
- The open and closed schemas compile through one cached path.
@willkg
willkg merged commit 584bdb6 into main Sep 25, 2026
1 check passed
@willkg
willkg deleted the open-json-schema branch September 25, 2026 14:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

json-output: make adding a key a compatible schema change

1 participant