Skip to content

skills/objectstack-data: the validation rule-type table never says WHICH record each type judges — format / json_schema read the write payload, script / cross_field the merged record #15011

Description

@os-steve

Observation-class finding, recorded while landing PR #15010 (the tool-choice line in skills/objectstack-data). Not fixed there: it falls outside the two-file, two-section surface that flight was scoped to. No assignee — for triage.

What is unstated

skills/objectstack-data/rules/validation.md opens with the complete rule-type table (script, state_machine, format, cross_field, json_schema, conditional). Every row says what the type is for and when it fails. No row says which record the predicate is judged against, and the answer is not uniform across the six.

Measured on origin/main, packages/objectql/src/validation/rule-validator.ts, the evaluateRule dispatch:

  • script and cross_field are handed ctx.merged — prior row overlaid with the patch. They are invariants: a row that already violates one is refused on any edit until a repairing write lands.
  • format and json_schema are handed ctx.data — the write payload only. On an update that omits the field, there is nothing for them to judge, so a stored row that violates them is never revisited.
  • conditional evaluates its own when against ctx.merged, then dispatches the nested rule back through the same switch — so a nested format still reads the payload while the branch that selected it read the merged record.

Why it is worth a row

This is the same invariant-versus-gate confusion PR #15010 corrects for script versus requiredWhen, one rule type over and still unsaid. An author who reads "use a script rule for an invariant" and reasonably generalises it to "validations[] holds invariants" will reach for format to enforce a stored-data invariant and get a write gate instead — no error, no signal, and legacy rows never checked.

Shape of a fix, if triage wants one

Smallest form is one clause per row (or one extra column) in the existing table — no new section. rules/validation.md has 610 tokens of headroom against its ceiling after PR #15010, so the ratchet is not the constraint here. The engine behaviour is the source of truth; nothing in the spec needs to change for this.

Generated by Claude Code

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions