You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(lint): an object declaring no fields is unjudgeable, not "has no such field" (#4383) (#4385)
`hook-body-write-unknown-field` and `action-body-write-unknown-field` reported
EVERY field write to an object that declares no `fields` — an external object,
or a datasource-introspected schema whose columns are resolved at runtime.
`indexObjectFields` returns an empty Set for such an object rather than
`undefined`, and both rules only asked "is this object in the stack?"
(`targetSets.every((s) => s !== undefined)`, `if (!known) continue`). An empty
Set is neither undefined nor falsy, so it became the answer to `has(field)` —
and that answer is always false.
The field map is not empty, it is UNKNOWN. Two other rules in the same family
already drew that distinction with their reasons written down
(validate-searchable-fields skip #2, and validate-flow-node-writes, which added
the guard in #4369 because it gates). Two of four had it: the drift shape #3583
and #4330 exist to remove.
Fixed once, not twice. The guard now lives in a shared
`judgeableFieldsOf(index, objectName)` returning the declared names only when
they are a sound basis for a "resolves to nothing" judgement, and `undefined`
for both unjudgeable cases. All three write-set rules route through it, so a
fourth cannot repeat the omission. Internal to the family — not re-exported from
the package barrel, same as `indexObjectFields` and `IMPLICIT_FIELDS`.
One semantic call worth naming: a multi-target hook where only SOME targets are
judgeable is now skipped entirely. The `ctx.input` finding fires only when a
field is missing from every target, and an unjudgeable target is one the field
might well exist on — judging the remainder would assert "missing everywhere" on
evidence that does not cover everywhere. Consistent with the rule's stated
asymmetry: prefer a missed finding to a false one.
No behaviour change for objects that declare fields; a test sits next to each
new skip so the guard cannot swallow the real finding.
Co-authored-by: Jack Zhuang <277994282+os-zhuang@users.noreply.github.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
0 commit comments