Skip to content

Commit 75add24

Browse files
committed
chore(changeset): lint narrowing and objectql per-rule isolation
Claude-Session: https://claude.ai/code/session_01XPyxHgkHDoFuEza6RvCJtd Co-authored-by: Claude <noreply@anthropic.com>
1 parent 1b15a2e commit 75add24

2 files changed

Lines changed: 36 additions & 0 deletions

File tree

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
---
2+
'@objectstack/lint': minor
3+
---
4+
5+
fix(lint)!: a validation rule that reads, through a reference, a field the reference's target does not declare is refused where it is written
6+
7+
Clause-②: no (narrowing)
8+
9+
<!-- adr-0087: not-required (no-migration-prescription) No spec key, stored shape or authorable spelling is added, removed or renamed. The validation-rule pass now refuses one condition shape it accepted before: a one-hop read of a field the reference's target does not declare, which the runtime never judged (the rule had no verdict and refused every write it judged). Nothing stored changes, so there is nothing for `objectstack migrate meta` to rewrite. -->
10+
11+
**BREAKING** (an authoring narrowing), shipped as `minor` under the launch-window convention for breaking changes.
12+
13+
The validation-rule pass judges the field a rule's `condition` reads one hop through a reference against the target object's fields: the fields it declares, the system columns the platform adds to it, and `id`. It is the same check the field-formula pass makes for a formula. `os validate`, `os build` and the object save door (`PUT /api/v1/meta/object/:name`) run the same pass, under the existing `EXPRESSION_INVALID` rule. It covers a `script` or `cross_field` rule's `condition`, at the top level and inside a `conditional` rule's `then` / `otherwise`.
14+
15+
- FROM: `record.account.region == 'north'`, where `account` is a lookup to an object that declares no `region`, saved with a 200, and every write the rule judged was refused. TO: refused (`422 INVALID_METADATA` at the save door). The message names the field and the target: "unknown field `region` on `<target>`".
16+
- `record.account.status == 'closed'`, where the target declares `status`, passes as before.
17+
- A target the stack does not carry is not judged. At the save door the stack carries the live registry's objects in the written package's closure, so a target from a package it depends on is judged.
18+
- A reference read more than one hop deep (`record.account.owner.email`) keeps its own refusal and is not judged a second time.
19+
20+
What to do. Read a field the target declares, or declare the field on the target object. Do not declare it on the object that carries the rule. At `os build` and `os validate` this pass does not see a target field that an `objectExtensions` entry contributes, while the save door judges the merged object.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
---
2+
'@objectstack/objectql': patch
3+
---
4+
5+
fix(objectql): a validation rule reading a field its reference's target does not declare no longer refuses every write through the other rules reading the same reference
6+
7+
Clause-②: no
8+
9+
A write loads, once per page, every column the object's validation rules read through each reference. When one rule named a field the target does not declare, the whole reference was answered as undeclared. Every rule reading through it then had no verdict and refused the write, each naming the other rule's field.
10+
11+
- The undeclared fields are left out of that shared read and judged for each rule on its own.
12+
- A rule that names one has no verdict and refuses the write, naming only its own undeclared fields.
13+
- A rule that reads only declared fields through the same reference gives the verdict it gives alone: it admits what it admits alone, and refuses with its own message.
14+
- The related read keeps its authority and its bound; an undeclared field never enters it.
15+
16+
What to do. Nothing. To find the rule at fault, re-save the object: the save door refuses the misspelt read and names the field.

0 commit comments

Comments
 (0)