Skip to content

Validation events: ['delete'] is a silent no-op — trim it from the spec #3184

Description

@os-zhuang

Summary

BaseValidationSchema admits events: ['insert', 'update', 'delete'] (packages/spec/src/data/validation.zod.ts:88), but the rule evaluator's runtime Mode is 'insert' | 'update' (packages/objectql/src/validation/rule-validator.ts:72) and engine.delete never invokes evaluateValidationRules. The events filter (rule-validator.ts:526) can therefore never match 'delete' — a validation rule declaring events: ['delete'] silently never runs.

This is the declared ≠ enforced tail split out of #3106 / PR #3160 (which fixed the multi-row-update call-site gap and left this one explicitly for a follow-up). It was also independently flagged by the June liveness audit.

Evidence

  • packages/spec/src/data/validation.zod.ts:88 — events: z.array(z.enum(['insert', 'update', 'delete'])).default(['insert', 'update']).
  • packages/objectql/src/validation/rule-validator.ts:72 — type Mode = 'insert' | 'update'; :526 — const events = r.events ?? ['insert', 'update']; return events.includes(mode); (mode is never 'delete').
  • docs/audits/2026-06-validationschema-property-liveness.md:10-21 — "🔴 events: ['delete'] is a silent no-op … Remove delete from the events enum (dead)."
  • The published skill skills/objectstack-data/rules/validation.md:268 actively teaches events: ['delete'] ("Only on delete"), so AI-authored metadata following the skill gets a delete guard that never fires.

Blast radius

Zero in practice. No example app, seed, template, fixture, or test declares a validation rule with 'delete' in events — the only repo-wide occurrences are documentation/skill text. Any hypothetical off-spec metadata fails loudly (ZodError at registry.validate / os validate), never silently.

Decision: trim (not enforce)

Remove 'delete' from the events enum (contract-first, AGENTS.md PD #12). Delete-time guards belong in beforeDelete lifecycle hooks, which the skills already teach correctly (skills/objectstack-data/references/data-hooks.md:448-464). Enforcement (wiring the evaluator into engine.delete) was considered and rejected: only script/cross_field would be meaningful on delete, and hooks already cover that need.

Scope

  • Narrow the enum + its three hand-written mirrors (validation.zod.ts:226 type, rule-validator.ts:79 BaseRule, packages/metadata-protocol/src/protocol.ts:231-235 JSON-schema mirror).
  • Fix the skill line and the hand-written doc table (content/docs/data-modeling/validation.mdx:72); regenerate content/docs/references/data/validation.mdx.
  • Correct the doc comments that framed the delete gap as a known exclusion.
  • Changeset + a negative test asserting events: ['delete'] is now rejected.

🤖 Generated with Claude Code

Activity

  1. added 4 commits that reference this issue on Jul 18, 2026
    f16b492
    5e3301d
    a3823b2
    4b6fde8
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions