Skip to content

QA checklist records-forms.action-location-matrix still asserts pre-objectui#3142 semantics — its "empty-locations means EVERY location" probe now grades correct behavior as a FAIL #7323

Description

@os-zhuang

Found while executing #6888 (retiring global_nav). Out of scope there — that card removes one vocabulary member; this is a different, still-live claim inside the same checklist item, so it is filed rather than fixed in PR #7322.

What

docs/qa/platform-checklist/areas/records-forms.json, item records-forms.action-location-matrix, asserts that an action with no locations renders at every location:

  • variant: "empty-locations semantics probe — a locations-less action lands on EVERY location including the toolbar (objectui action-bar.tsx documented behavior; the reason recalc_selection must declare record_more)"
  • acceptance clause: "empty/missing locations means EVERY location — the probe action appears on all surfaced slots including the list toolbar"
  • source line: "objectui: packages/.../action-bar.tsx (missing/empty locations → every location)"

That is no longer true, and the checklist item itself records the change that made it false. The same item cites objectui#3142 twice — and objectui#3142 is exactly the change that ended this behavior.

Evidence

The placement predicate is a single function, and it is a plain membership test — an undeclared or empty locations matches nothing:

objectui packages/types/src/ui-action.ts:86-99

export function actionRendersAt(
  action: { locations?: readonly string[] } | null | undefined,
  location: ActionLocation | undefined,
): boolean {
  if (!location) return true;
  const declared = action?.locations;
  return Array.isArray(declared) && declared.includes(location);
}

action-bar.tsx:134-140 is the consumer, and its comment states the change in the past tense:

Placement is actionRendersAt's call, not ours (objectui#3142): an action renders here only if it DECLARES this location. This bar used to show a locationless action at every location …

This repo already treats the new semantics as fact. packages/lint/src/validate-action-locations.ts is built on it — the whole action-no-placement rule exists because an action with no locations now renders nowhere, and its docblock says so: "objectui#3142 collapsed four disagreeing renderers onto one predicate — an action renders at a location only if it DECLARES that location. Before that, action:bar and the record header showed an undeclared action everywhere, which is what made this shape look alive; it is measurably inert as of objectui 17.1."

So two artifacts in this repo state opposite things about the same behavior.

Why it matters

The probe is manually runnable and will produce a false FAIL. A runner follows the step — "in a scratch/writable package author a copy of an api action with NO locations key; reload and record every surface it appears on (including the toolbar)" — observes it appearing on no surface, and reads the acceptance clause as broken product behavior. The item's own negative list makes that reading worse: "any action rendering at a location it did not declare … is a FAIL — placement is a contract, not a hint." The negative encodes the post-#3142 contract while the acceptance clause encodes the pre-#3142 one, so the item now contradicts itself and grades correct behavior as a regression.

The enumSource ratchet cannot catch this: it counts ACTION_LOCATIONS members and says nothing about semantics prose.

Suggested fix (not applied)

Rewrite the probe to pin the current contract rather than deleting it — the probe is still worth running, only its expected outcome inverted:

  • a locations-less action renders on no surface (the action-no-placement lint shape, observable end-to-end);
  • locations: [] likewise renders nowhere, and that is the deliberate headless declaration;
  • keep the recalc_selection note, but re-anchor it: it must declare record_more because placement is now explicit, not to opt out of an everywhere-default.

Also re-word the source line, and bump the item revision.

Scope note

Independent of #6888: it is true whether or not global_nav exists, and #6888's PR deliberately touches only the global_nav variant of this item.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions