Skip to content

lint: five hand-copied SYSTEM_FIELDS lists in packages/lint should derive from the spec's declarations #4330

Description

@os-zhuang

Noticed while adding searchable-field-unknown (#4328).

Five rules in packages/lint each carry their own copy of "registry-injected columns present on almost every object but absent from authored fields", and they have already drifted from one another:

file contents
validate-widget-bindings.ts:238 id, 4 audit, owner_id, organization_id, tenant_id, user_id, deleted_at
validate-page-field-bindings.ts:72 same list, comment says "Copied verbatim from validate-widget-bindings"
validate-translation-references.ts:173 same list
validate-react-page-props.ts:214 same list
validate-flow-template-paths.ts:93 different — adds name, owner, is_deleted, record_type; its comment says it "mirrors validateFormLayout's system-field set plus the audit/tenant columns from FIELD_GROUP_SYSTEM_FIELDS" — i.e. it names the canonical source and then hand-copies anyway

This is exactly the shape #3786 fixed for the audit-provenance family: a four-name list hand-copied four times across two repos, each under a comment asking to be kept in sync with one of the others. The spec now owns two declarations that between them cover the whole set:

  • FIELD_GROUP_SYSTEM_FIELDS (@objectstack/spec/data) — audit provenance + organization_id / tenant_id / is_deleted / deleted_at
  • SystemFieldName (@objectstack/spec/system) — id, created_at, updated_at, owner_id, tenant_id, user_id, deleted_at

validate-searchable-fields.ts (#4328) derives from both rather than adding a sixth copy:

const SYSTEM_FIELDS: ReadonlySet<string> = new Set<string>([
  ...FIELD_GROUP_SYSTEM_FIELDS,
  ...Object.values(SystemFieldName),
]);

Suggested fix: lift that into one module-local export in packages/lint (e.g. system-fields.ts) and point the five existing rules at it. Two judgement calls the conversion has to make deliberately rather than by accident:

  1. The derived union is a superset of the four identical copies (it adds is_deleted), which only makes those rules more permissive — safe, and the direction the comments already argue for ("deliberately generous: over-inclusion costs at worst a missed warning; under-inclusion costs a false one").
  2. validate-flow-template-paths additionally exempts name, owner and record_type, which are not system columns in the same sense — name in particular is an ordinary authored field on most objects. Whether those belong in the shared set or stay local to that rule needs a decision, not a mechanical merge.

Not folded into #4328 to keep a new gating rule's diff reviewable.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions