Skip to content

Runtime validation#3333

Open
Takeno wants to merge 64 commits intomainfrom
feat/runtime-validation-write
Open

Runtime validation#3333
Takeno wants to merge 64 commits intomainfrom
feat/runtime-validation-write

Conversation

@Takeno
Copy link
Contributor

@Takeno Takeno commented Jan 6, 2026

Description

Cursor's summary is almost complete. Although the scope is clear and documented on Linear, here are the known weird behaviours:

  • Validations are applied only to writes: invalid data may still exist and be loaded from cojson. Once loaded, the schema validation is applied again to any mutation.
  • Inputs can be transformed by validators
  • As validations are not applied on loading, it might happen to set a non-validated comap as a reference inside another CoValue. E.g.
const Box = co.map({x: z.number()});
const Boxes = co.list(Box);

const invalidBox = Box.create({}, {validation: "loose"});

const list = Boxes.create([invalidBox])); // This will not throw
Boxes.create([co.map({}).create({})); // This doesn't either, only the type is checked (CoMap) and uses the reference.

Check this conversation too.

  • Until the moment we change the default validation mode to "strict", default validation is set to "warn" and an additional console.warn reminds users that the default will be "strict" in the next major release.
  • z.default() now works as expected on writes. They don't work on reads. This is a nice feature, but it can be misunderstood.

Still missing

  • Docs

Note

High Risk
Touches core CoValue mutation paths and schema runtime internals; behavior changes (validation, new defaults/warnings, descriptor resolution) can break apps or tests and may surface new runtime errors during writes.

Overview
Introduces runtime schema validation on writes for schema-based CoValues (CoMap, CoList, CoFeed, plus related built-ins), with a new global setDefaultValidationMode() and per-mutation validation option to enforce strict vs loose behavior (global default is currently warn, logging instead of throwing).

CoValue implementations are refactored to source descriptors/validation schemas from attached coValueSchema objects (initialized for built-ins), adding validation plumbing across create/set/push/splice/applyDiff and updating tests/docs/examples to opt into strict validation. Legacy schema exports coField and Encoders are removed, completing the migration to co/zod-based schema descriptors; better-auth adapter creation paths were adjusted to satisfy the new schema expectations (e.g., initializing _deleted and sessions fields).

Written by Cursor Bugbot for commit 507f325. This will update automatically on new commits. Configure here.

@vercel
Copy link

vercel bot commented Jan 6, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
clerk-demo Ready Ready Preview, Comment Feb 13, 2026 1:55pm
design-system Error Error Feb 13, 2026 1:55pm
file-upload-demo Ready Ready Preview, Comment Feb 13, 2026 1:55pm
form-demo Ready Ready Preview, Comment Feb 13, 2026 1:55pm
gcmp-homepage Ready Ready Preview, Comment Feb 13, 2026 1:55pm
image-upload-demo Ready Ready Preview, Comment Feb 13, 2026 1:55pm
jazz-chat Ready Ready Preview, Comment Feb 13, 2026 1:55pm
jazz-chat-1 Ready Ready Preview, Comment Feb 13, 2026 1:55pm
jazz-chat-2 Ready Ready Preview, Comment Feb 13, 2026 1:55pm
jazz-filestream Ready Ready Preview, Comment Feb 13, 2026 1:55pm
jazz-image-upload Ready Ready Preview, Comment Feb 13, 2026 1:55pm
jazz-inspector Ready Ready Preview, Comment Feb 13, 2026 1:55pm
jazz-multi-cursors Ready Ready Preview, Comment Feb 13, 2026 1:55pm
jazz-nextjs Ready Ready Preview, Comment Feb 13, 2026 1:55pm
jazz-organization Ready Ready Preview, Comment Feb 13, 2026 1:55pm
jazz-paper-scissors Ready Ready Preview, Comment Feb 13, 2026 1:55pm
jazz-richtext Ready Ready Preview, Comment Feb 13, 2026 1:55pm
jazz-todo Ready Ready Preview, Comment Feb 13, 2026 1:55pm
jazz-vector-search Ready Ready Preview, Comment Feb 13, 2026 1:55pm
jazz-version-history Ready Ready Preview, Comment Feb 13, 2026 1:55pm
music-demo Ready Ready Preview, Comment Feb 13, 2026 1:55pm
passkey-demo Ready Ready Preview, Comment Feb 13, 2026 1:55pm
passphrase-auth-demo Ready Ready Preview, Comment Feb 13, 2026 1:55pm
quint-ui Ready Ready Preview, Comment Feb 13, 2026 1:55pm
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
jazz-homepage Ignored Ignored Preview Feb 13, 2026 1:55pm

Request Review

@blacksmith-sh

This comment has been minimized.

@blacksmith-sh

This comment has been minimized.

@blacksmith-sh

This comment has been minimized.

Copy link
Contributor

@nrainhart nrainhart left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work! I know this is still a draft, but I couldn't stop myself from leaving a bunch of comments 😅

Comment on lines 599 to 600
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are there any other zod constructs we should ignore? E.g. transforms & default values

@Takeno
Copy link
Contributor Author

Takeno commented Jan 20, 2026

Rebased with 0.19.22 for pre-release publish

cursor[bot]

This comment was marked as outdated.

cursor[bot]

This comment was marked as outdated.

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Union schema detection uses wrong property

High Severity

isUnionSchema checks schema.type === "union" instead of the runtime definition field used elsewhere (schema.def.type). This can make extractFieldShapeFromUnionSchema and extractFieldElementFromUnionSchema reject valid union schemas, which then either disables per-field validation in coMap mutations or throws non-validation errors in coList/coFeed mutations.

Additional Locations (2)

Fix in Cursor Fix in Web

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.


for (const [from, to, insert] of patches.reverse()) {
this.splice(from, to - from, ...insert);
this.spliceLoose(from, to - from, ...insert);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CoList diff updates skip validation

Medium Severity

CoList.$jazz.applyDiff now calls spliceLoose, which bypasses runtime schema checks. This makes a write path mutate lists without validation, even when global mode is strict. Invalid data can be written through applyDiff, diverging from the new validation behavior for normal mutators.

Fix in Cursor Fix in Web

return ResolvedClass.fromRaw(raw);
}
} as unknown as SchemaUnionConcreteSubclass<V>;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SchemaUnion public factory removed unexpectedly

High Severity

The commit removes SchemaUnion.Of from SchemaUnion and only keeps schemaUnionClassFromDiscriminator as a standalone helper. Existing consumers calling SchemaUnion.Of(...) lose the public API at runtime, which is a breaking behavior change not reflected in the PR’s stated migration scope.

Fix in Cursor Fix in Web

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

"jazz-tools": patch
---

Removed the legacy `coField` and `Encoders` exports and completed the runtime schema migration to the new schema descriptors. Apps still using the old schema APIs should migrate to the current `co`/zod based schemas.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Breaking release labeled as patch

Medium Severity

The changeset marks jazz-tools as patch while documenting removal of legacy exports (coField, Encoders). Removing public exports is a breaking API change, so this release metadata can publish incompatible behavior under a non-breaking version bump.

Fix in Cursor Fix in Web

return class CoListOf extends CoList<Item> {
[coField.items] = item;
};
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CoList.of guard was unintentionally removed

Low Severity

CoList no longer overrides static of, so CoList.of() now falls back to Array.of. That path bypasses the prior explicit safeguard and can construct non-initialized CoList instances (or throw cryptic constructor errors), re-exposing an API path that was intentionally blocked.

Fix in Cursor Fix in Web

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 3 potential issues.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

createCoreCoMapSchema(augmentedShape, optionDef.catchall),
);

return augmentedSchema.getCoValueClass() as typeof CoMap;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Union branch class identity lost

High Severity

When schemaUnionDiscriminatorFor needs dummy keys, it now builds a new class from createCoreCoMapSchema(...) instead of extending the matched branch class. Returned values are no longer instances of the original union option class, so branch-specific methods/prototype checks can silently break after co.discriminatedUnion(...) resolution.

Fix in Cursor Fix in Web

* class BaseWidget extends CoMap {
* type = coField.string;
* }
*
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SchemaUnion factory API removed unexpectedly

High Severity

SchemaUnion is still publicly exported, but SchemaUnion.Of(...) was removed and the remaining static methods throw Not implemented. Existing consumers using the exported union API can no longer construct usable union classes, causing runtime failures after upgrade.

Additional Locations (1)

Fix in Cursor Fix in Web

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

createCoreCoMapSchema(augmentedShape, optionDef.catchall),
);

return augmentedSchema.getCoValueClass() as typeof CoMap;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Union branch class metadata dropped

Medium Severity

When adding dummy fields for co.discriminatedUnion, the discriminator now returns a new class from createCoreCoMapSchema(...) instead of extending the matched option class. This drops option-specific schema metadata like permissions, resolveQuery, and class-level behavior for that branch.

Fix in Cursor Fix in Web

* chore: replaced union with superRefine in schema validation

* fixup! chore: replaced union with superRefine in schema validation
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

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.

3 participants

Comments