Skip to content

docs(spec): EmptyState records its shipped contract as current - #9127

Merged
cixzhang merged 1 commit into
mainfrom
spec-backfill/EmptyState
Oct 31, 2026
Merged

cixzhang merged 1 commit into
mainfrom
spec-backfill/EmptyState

Conversation

@cixzhang

Copy link
Copy Markdown
Contributor

Exact decision needed

Promote component:EmptyState from draft to current, recording EmptyState's shipped behavior on main today. No behavior, API, or output change.

Existing authority searched

Decision

packages/core/src/EmptyState/EmptyState.spec.md: authority: current, approved_by: cixzhang, approved_at: 2026-10-31, owners unchanged, template 7, behavioral table headed "Invariant | Basis". The spec:AST-029/FR3 process link is dropped and spec:AST-009 added for accessibility-tree evidence.

Rejected alternatives

None.

Claim scope and non-goals

Covers only EmptyState as shipped on main. Message copy, icon meaning, and actions stay with the caller; heading order stays with the page. No new behavior is decided.

Evidence and implementation relationship

  • FR1, FR3, FR4, AR2: slot, order, decorative-icon, empty-slot, and live-role tests; stable visual baseline core-emptystate--default.
  • FR2, AR1: heading tests.
  • AR3: EmptyState.announce.test.tsx.
  • FR5, ORD1: ref, data-testid, and root-composition tests.
  • FR6: compact and theming-target tests.

Writing rubric results

  • R1 narration: the draft's "observational", "runtime remediation", "Draft requirements identify their basis…", and "verify" review-state cells are rewritten in the present tense.
  • R2 research in the record: none.
  • R3 evidence naming a change: none.
  • R4 rejected alternatives over one line or outside a decision: none.
  • R5 pull request or issue references remaining: none (searched # + digits, /pull/, /issues/).
  • R6 ruled open questions still listing options: none; no open questions.

Scope

  • This PR contains specification records only.
  • It records observable behavior and preserves equivalent internal implementations.
  • Any named internal mechanism is intentionally public, names its dependent caller/system, and explains why an equivalent implementation would not satisfy the contract: none.
  • Verification states the evidence layer and failure signal without prescribing CI job/workflow topology.
  • It records one intentional durable decision, not a rescue for a separable tagalong.
  • The canonical knowledge owner, affected current claims, and overlapping open work are named; no ownership collision.
  • Adjacent API, visual, accessibility, composition, and implementation facts remain outside scope unless this exact decision depends on them.
  • Public text and artifacts contain no internal Meta context.

Validation

  • pnpm check:knowledge: aligned
  • Prettier: clean
  • git diff --check: clean

@vercel

vercel Bot commented Oct 31, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
astryx Ready Ready Preview Oct 31, 2026 12:14pm UTC

Request Review

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Meta Open Source bot. label Oct 31, 2026
@astracat-bot

astracat-bot Bot commented Oct 31, 2026 •

Copy link
Copy Markdown

AI review status for this pull request.

Review status Updated
❓ Needs maintainer input (for maintainers only) Oct 31, 2026, 12:21 PM UTC

@github-actions github-actions Bot added the needs:spec-owner-review Current knowledge records await owner approval label Oct 31, 2026
@cixzhang
cixzhang marked this pull request as ready for review October 31, 2026 11:07

@astracat-bot astracat-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This record matches EmptyState as it ships, but it can't become current until an engineering owner approves its content at this head: FR1–FR6, AR1–AR3, ORD1, PR1 and the verification map with its named gaps. An engineering owner records that by commenting /approve-spec <full head SHA> on this pull request, and the author may do so as an engineering owner. Please make the fix below first, because any later commit to the record needs a fresh approval.

  • The FR5/ORD1 verification row says the ref test catches a ref on another element, but forwards ref only checks for a div, so a ref placed on the text-group wrapper still passes it; name that gap in the row or assert that ref.current is the root.

[Automated review]

| FR1, FR3, FR4, AR2 | `EmptyState.test.tsx` slot, order, decorative-icon, empty-slot, and live-role tests; stable visual baseline `core-emptystate--default` | Title only; all slots; absent and shallow-empty slots | A wrapper for an absent or shallow-empty slot, a changed slot order, an icon not hidden from assistive technology, or a live role on the root fails; a changed default layout comes back changed for review. Gap: no accessibility-tree check proves the hidden icon or the heading (`spec:AST-009` FR3). | `audit:EmptyState/a11y` |
| FR2, AR1 | `EmptyState.test.tsx` heading tests | Default level 3; every level | A title that is not the selected heading element fails. | `audit:EmptyState/a11y` |
| AR3 | `EmptyState.announce.test.tsx` | Render with the page; appear later; iframe; inside a live container; message change; server render and hydration; hidden and revealed | An announcement during load or hydration, a missing or repeated announcement when it appears or changes later, hidden text in the message, or an announcement inside a live container fails. | `audit:EmptyState/a11y` |
| FR5, ORD1 | `EmptyState.test.tsx` ref, `data-testid`, and root-composition tests | DOM, data, event, style inputs; caller role; ref | A dropped input, a replaced caller role, or a ref on another element fails. | `audit:EmptyState/api` |

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This row credits the ref test with failing for "a ref on another element", but forwards ref only asserts that ref.current is an HTMLDivElement, and the text-group wrapper is a div too. Spreading the ref onto <AnnounceRenderedText> instead of the root type-checks and leaves all 23 EmptyState.test.tsx tests green; today only the announcement tests catch it, by side effect. Either add Gap: the ref test checks only that the ref is a div, not that it is the root. here, or tighten the test to expect(ref.current).toBe(container.firstElementChild).

@astracat-bot astracat-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This record matches EmptyState as it ships and now names the ref gap, but it can't become current until an engineering owner approves its content: FR1–FR6, AR1–AR3, ORD1, PR1 and the verification map with its named gaps. An engineering owner records that by commenting /approve-spec <full head SHA> on this pull request, and the author may do so as an engineering owner. Please make the fix below first, because any later edit to the record needs a fresh approval.

  • The FR5/ORD1 row credits the root-composition test for ORD1, but moving xstyle ahead of the component styles in EmptyState.tsx still passes every EmptyState test; add Gap: no test asserts that caller xstyle follows the component styles. to the row, or add a test with a conflicting caller xstyle.

[Automated review]

| FR1, FR3, FR4, AR2 | `EmptyState.test.tsx` slot, order, decorative-icon, empty-slot, and live-role tests; stable visual baseline `core-emptystate--default` | Title only; all slots; absent and shallow-empty slots | A wrapper for an absent or shallow-empty slot, a changed slot order, an icon not hidden from assistive technology, or a live role on the root fails; a changed default layout comes back changed for review. Gap: no accessibility-tree check proves the hidden icon or the heading (`spec:AST-009` FR3). | `audit:EmptyState/a11y` |
| FR2, AR1 | `EmptyState.test.tsx` heading tests | Default level 3; every level | A title that is not the selected heading element fails. | `audit:EmptyState/a11y` |
| AR3 | `EmptyState.announce.test.tsx` | Render with the page; appear later; iframe; inside a live container; message change; server render and hydration; hidden and revealed | An announcement during load or hydration, a missing or repeated announcement when it appears or changes later, hidden text in the message, or an announcement inside a live container fails. | `audit:EmptyState/a11y` |
| FR5, ORD1 | `EmptyState.test.tsx` ref, `data-testid`, and root-composition tests | DOM, data, event, style inputs; caller role; ref | A dropped input, a replaced caller role, or a ref that is not a `div` fails. Gap: the ref test checks only that the ref is a `div`, not that it is the root. | `audit:EmptyState/api` |

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This row also covers ORD1, but composes root props only checks that the caller's xstyle class is present. Moving xstyle ahead of styles.container in stylex.props (so a caller's gap or padding loses) keeps every EmptyState test green. Please add Gap: no test asserts that caller xstyle follows the component styles. here, or add a test with a conflicting caller xstyle.

@astracat-bot astracat-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This record matches EmptyState as it ships and now names the xstyle-order gap, but it can't become current until an engineering owner approves its content: FR1–FR6, AR1–AR3, ORD1, PR1 and the verification map with its named gaps. An engineering owner records that by commenting /approve-spec <full head SHA> on this pull request, and the author may do so as an engineering owner. Please make the fix below first, because any later edit to the record needs a fresh approval.

  • The FR2/AR1 and AR3 verification rows credit tests that stay green when the title's type style changes with its heading level or when EmptyState moves focus to its heading; add Gap: no check that the title keeps one type style at every heading level. and Gap: no test asserts that focus stays where it was when EmptyState appears. to those rows, or add the tests.

[Automated review]

| Contract | Verification | Representative states | Mutation or failure expectation | Audit section |
| ------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------- |
| FR1, FR3, FR4, AR2 | `EmptyState.test.tsx` slot, order, decorative-icon, empty-slot, and live-role tests; stable visual baseline `core-emptystate--default` | Title only; all slots; absent and shallow-empty slots | A wrapper for an absent or shallow-empty slot, a changed slot order, an icon not hidden from assistive technology, or a live role on the root fails; a changed default layout comes back changed for review. Gap: no accessibility-tree check proves the hidden icon or the heading (`spec:AST-009` FR3). | `audit:EmptyState/a11y` |
| FR2, AR1 | `EmptyState.test.tsx` heading tests | Default level 3; every level | A title that is not the selected heading element fails. | `audit:EmptyState/a11y` |

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FR2 also promises the title keeps one visual type role at every heading level, but the heading tests only check the element, and the core-emptystate--default baseline renders level 3. Tying the title style to the level (for example (isCompact || headingLevel !== 3) && styles.titleCompact) leaves every EmptyState test green. Add Gap: no check that the title keeps one type style at every heading level., or a test that compares levels.

| ------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------- |
| FR1, FR3, FR4, AR2 | `EmptyState.test.tsx` slot, order, decorative-icon, empty-slot, and live-role tests; stable visual baseline `core-emptystate--default` | Title only; all slots; absent and shallow-empty slots | A wrapper for an absent or shallow-empty slot, a changed slot order, an icon not hidden from assistive technology, or a live role on the root fails; a changed default layout comes back changed for review. Gap: no accessibility-tree check proves the hidden icon or the heading (`spec:AST-009` FR3). | `audit:EmptyState/a11y` |
| FR2, AR1 | `EmptyState.test.tsx` heading tests | Default level 3; every level | A title that is not the selected heading element fails. | `audit:EmptyState/a11y` |
| AR3 | `EmptyState.announce.test.tsx` | Render with the page; appear later; iframe; inside a live container; message change; server render and hydration; hidden and revealed | An announcement during load or hydration, a missing or repeated announcement when it appears or changes later, hidden text in the message, or an announcement inside a live container fails. | `audit:EmptyState/a11y` |

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AR3 also says EmptyState does not move focus, and nothing here checks it: a heading that focuses itself on mount passes every EmptyState test. Add Gap: no test asserts that focus stays where it was when EmptyState appears., or a test that keeps focus on a field while EmptyState mounts.

@astracat-bot astracat-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This record matches EmptyState as it ships and now names every gap its tests leave, including the title's type style at every heading level and focus, so the record itself needs no further change. It can become current once an engineering owner approves its content at this head: FR1–FR6, AV1–AV2, AR1–AR3, ORD1, PR1, the theming anatomy and the verification map with its named gaps. An engineering owner records that by commenting /approve-spec <full head SHA> on this pull request, and the author may do so as an engineering owner; any later edit to the record needs a fresh approval.

[Automated review]

@cixzhang

Copy link
Copy Markdown
Contributor Author

/approve-spec 552abbb

@github-actions github-actions Bot removed the needs:spec-owner-review Current knowledge records await owner approval label Oct 31, 2026
@cixzhang
cixzhang merged commit b68f906 into main Oct 31, 2026
51 checks passed
@github-actions
github-actions Bot deleted the spec-backfill/EmptyState branch November 1, 2026 06:05

This branch was successfully deployed

1 active deployment
Preview — 552abbb5 Deployed Oct 31, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Meta Open Source bot.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant