Skip to content

Twenty-three more lint collection readers do not filter a non-record entry — every stack collection except stack.objects #15636

Description

@claude

Found while implementing #15552 (the stack.objects reader sweep); filed as a finding only, not claimed.

#15552 closes the class for ONE collection. stack.objects is now read everywhere in @objectstack/lint through the guarded recordsOf, and a family test pins that no AUTHORING_RULES entry throws or invents a finding on a non-record member of it. Every OTHER stack collection is still read through a hand-copied helper that does not filter.

Measured

On e7cede2ca (the #15552 branch, all sixteen stack.objects seams re-pointed), 23 files in packages/lint/src still carry the undefended body verbatim:

function asArray(v: unknown): AnyRec[] {
  if (Array.isArray(v)) return v as AnyRec[];   // unchecked
  if (v && typeof v === 'object') {
    return Object.entries(v as AnyRec).map(([name, def]) => ({ name, ...(def as AnyRec) }));
  }
  return [];
}

build-access-matrix.ts, lint-flow-patterns.ts, lint-liveness-properties.ts, validate-action-locations.ts, validate-action-name-refs.ts, validate-approval-approvers.ts, validate-capability-references.ts, validate-chart-bindings.ts, validate-component-props.ts, validate-component-types.ts, validate-dashboard-action-refs.ts, validate-dataset-references.ts, validate-flow-template-paths.ts, validate-flow-trigger-readiness.ts, validate-list-view-field-refs.ts, validate-nav-access.ts, validate-object-field-refs.ts, validate-readonly-flow-writes.ts, validate-readonly-hook-writes.ts, validate-responsive-styles.ts, validate-rls-predicate-enforceability.ts, validate-semantic-roles.ts, validate-translation-references.ts.

Between them they read flows, pages, dashboards, datasets, agents, apps, navigation, permissions, positions, books, data and the per-object sub-collections. A null member of any of those reaches the same dereference stack.objects did, for the same reason: the rules are pure (stack) = Finding[] and run on the RAW lint path, so nothing upstream has judged the entry's shape, and an empty YAML list item deserialises to null.

Not re-measured per collection here — #15552's sweep drives objects only, so the throw count for the other collections is unknown rather than zero. lint-liveness-properties.test.ts already pins translations: [null, …], agents: [null, …] and fields: [null, …] cases, which suggests some are guarded at the call site and some are not.

Suggested shape

The same edit #15552 made, widened: delete the remaining copies and re-point them onto recordsOf (packages/lint/src/object-graph.ts), whose docblock already carries the skip argument. Worth pairing with a source-text gate asserting the package holds exactly ONE such coercion, so the copy count cannot grow back — the copies are what made #15552 a fourteen-site repair instead of a one-line one.

The family test to widen alongside it is packages/lint/src/non-record-object-entry.test.ts: it sweeps AUTHORING_RULES over five non-record shapes for objects, and the same sweep parameterised by collection key would cover the rest.

Context


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

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions