Skip to content

spec(i18n, Resizable, AST-103): factories take announcement and label options with a catalog default - #9395

Merged
cixzhang merged 4 commits into
mainfrom
spec/factory-announce-options
Nov 2, 2026
Merged

cixzhang merged 4 commits into
mainfrom
spec/factory-announce-options

Conversation

@cixzhang

@cixzhang cixzhang commented Nov 1, 2026 •

Copy link
Copy Markdown
Contributor

Maintainer impact

  • Screen-reader users of an app built on a non-React Astryx factory hear its announcements, and see its labels, in the app's language: the factory takes an option for each string it announces or shows, and without it uses the catalog message (translated under a provider, English without one).
  • Maintainers adding a factory with one such string add one flat optional option for it; a factory with more than one groups them under one optional labels object. No translator or catalog key becomes part of a factory's public contract.
  • createResizable and useResizable(handleRef, options) take collapsedLabel?: string, the Handle's aria-valuetext while collapsed.
  • createReorderable takes labels?: ReorderableLabels, holding its eleven announcements and nine shown labels (handle name and hint, move buttons, Done).

Exact decision needed

How a public non-React factory under architecture:public-component-api INV22 (create…(element, options)) lets callers localize the Astryx text it announces or shows when no provider is present.

Decision

  • 2026-11-01: the owner chose per-message options with a catalog default, with no translator option because translation belongs to the provider.
  • 2026-11-01: the owner chose labels grouping for a factory with more than one string, and that createReorderable's labels also holds the labels it shows.

Changed records

  • architecture:internationalization — new INV3a beside INV3: a public non-React factory (architecture:public-component-api INV22) that announces or shows Astryx text (a live-region announcement, an aria-* or title value, or a visible label) takes an option for each such string: a flat optional option when it has one string (such as createResizable's collapsedLabel), one optional labels object with optional keys when it has more. An absent option or key falls back to the catalog message, translated under a provider and English without one; a given string replaces that message, including over a provider's translation. No factory takes a translator. The external-runtime adapter (INV14) stays a separate, broader decision. Added to the accessibility, behavior and public-api review routes, with a verification row (evidence gap: no factory test covers a flat option or labels key yet).
  • architecture:public-component-api INV22 — one clause: a factory's announced and shown strings follow internationalization INV3a's options.
  • component:Resizable AR1 — CreateResizableOptions, which useResizable(handleRef, options) also takes, has collapsedLabel?: string, announced as the Handle's aria-valuetext while collapsed; absent, the catalog's "Collapsed". AR1 is the record clause that decides the new CreateResizableOptions.collapsedLabel?: string row (architecture:public-component-api INV25). Implementation gap: not built.
  • spec:AST-103 FR1 — createReorderable's options gain labels?: ReorderableLabels. Announcement keys: pickedUp, dropped, cancelled, place, placeAtTop, placeAtEnd, placeInGrid, refused, notMoved, modeDone, unnamedItem. Shown keys: handle, handleVerb, unnamedHandle, handleHint, moveUp, moveDown, moveLeft, moveRight, done. Every key is optional and falls back to the catalog message; a templated key takes the catalog's ICU template with the same arguments (such as position and count). Implementation gap: not built.
  • spec:AST-103 FR4b — attach takes each string from labels, an absent key falling back to the shipped English catalog, replacing its shipped-English-only strings. Implementation gap: not built.
  • spec:AST-103 verification — the FR1 row covers ReorderableLabels' keys and fails on a string no key replaces or a translator option; the FR4b row covers every key given and none, and a given key under a provider (evidence gap: not built).
  • spec:AST-103 DEC-6 — one labels object holds every string; rejected a translator option and one flat option per string.

Existing authority searched

Rejected alternatives

  • One translator-function option per factory: puts a translator into each factory's public contract; translation belongs to the provider.
  • One flat option per string on a multi-string factory: twenty top-level options on createReorderable.
  • No option, factories stay English outside a provider: a non-React app cannot localize the text at all.

Claim scope and non-goals

  • Only Astryx-owned announced or shown text from public non-React factories. Components, provider behavior, and the external-runtime adapter (INV14) are unchanged.
  • No implementation; collapsedLabel and labels land with each factory's implementation.

Evidence and implementation relationship

Writing rubric results

  • R1 narration: none; every addition is a present-tense statement about the system.
  • R2 research in the record: none; the option comparison stays out of the records except DEC-6's one-line rejection.
  • R3 evidence naming a change: none; the verification rows name test kinds and evidence gaps.
  • R4 rejected alternatives over one line or outside a decision: one line, inside AST-103 DEC-6.
  • R5 pull request or issue references remaining: none in the changed records (searched # digits, /pull/, /issues/ in the added lines).
  • R6 ruled open questions still listing options: none; no open question touched.

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.
  • 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; any ownership collision is resolved or called out for human decision.
  • 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 install --frozen-lockfile
  • pnpm check:knowledge — "Knowledge templates and records are aligned."
  • Prettier
  • git diff --check

@vercel

vercel Bot commented Nov 1, 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 Nov 2, 2026 12:12am UTC

Request Review

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

astracat-bot Bot commented Nov 1, 2026 •

Copy link
Copy Markdown

AI review status for this pull request.

Review status Updated
🟢 Reviewed (for maintainers only) Nov 2, 2026, 12:14 AM UTC

@github-actions github-actions Bot added the needs:spec-owner-review Current knowledge records await owner approval label Nov 1, 2026
@cixzhang

cixzhang commented Nov 1, 2026

Copy link
Copy Markdown
Contributor Author

/approve-spec a72e5e1

@github-actions github-actions Bot removed the needs:spec-owner-review Current knowledge records await owner approval label Nov 1, 2026

@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.

The per-message option rule is clear and owner-approved at this head, but two record fixes are needed so the current records agree.

  • architecture:internationalization INV3a lets a caller replace createReorderable's announcements, while spec:AST-103 FR1, FR4b and FR4b's verification row still allow only shipped-English strings and three options. Either amend AST-103 here, saying how an option replaces a message with arguments such as "position 3 of 5", or limit INV3a to INV22 factories.
  • component:Resizable AR1 describes collapsedLabel on CreateResizableOptions and useResizable(handleRef, options), which do not exist on main yet. Add an implementation gap and a Current-state impact bullet, as the record does for its other unbuilt clauses.

Optionally, word INV3a's scope as "writes or announces Astryx text (live-region announcements and aria-*/title values)" so it plainly covers aria-valuetext. After the next push, the new head needs a fresh /approve-spec.

[Automated review]

Comment on lines +195 to +201
- **INV3a — Factories take a per-message option for each announced string.** A
public non-React factory (`architecture:public-component-api` INV22) that
announces Astryx text takes an optional string option for each announced
message; given, it replaces that message; absent, the factory announces the
catalog message, translated when its React wrapper runs under a provider and
English without one. Per-message options are the factory mechanism; the
external-runtime adapter (INV14) stays a separate, broader decision.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

spec:AST-103 FR1 lists createReorderable's options as onReorder, isReorderable and positions. Its FR4b has attach use only shipped-English strings, and FR4b's verification row fails on "strings other than the shipped English catalog's". If INV3a covers that factory, as the description says, AST-103 needs the matching amendment in this PR. INV3a should also say how an option replaces a message with arguments, such as "Milk, position 3 of 5, after Eggs, before Bread": for example, an ICU message taking the catalog message's arguments. Otherwise, limit INV3a to the create…(element, options) factories of INV22.

`en`, direction `ltr`, and do not read the browser or host locale implicitly.
- **INV3a — Factories take a per-message option for each announced string.** A
public non-React factory (`architecture:public-component-api` INV22) that
announces Astryx text takes an optional string option for each announced

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Minor: INV1a separates "live-region announcements" from "aria-*/title values", but here the scope is only text a factory "announces", and Resizable AR1 applies it to aria-valuetext. Suggest: "that writes or announces Astryx text (live-region announcements and aria-*/title values)".

Comment on lines +201 to +204
`CreateResizableOptions`, which `useResizable(handleRef, options)` also
takes, has `collapsedLabel?: string`, announced as the Handle's
`aria-valuetext` while collapsed; absent, the catalog's "Collapsed"
(`architecture:internationalization` INV3a).

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Neither CreateResizableOptions nor useResizable(handleRef, options) exists on main: useResizable.ts exports only useResizable(config). This record's summary says "Implementation gaps are listed under Current-state impact", and its compatibility line says "No prop, option, or return member changes". Suggest appending "Implementation gap: no createResizable or ref-taking useResizable exists yet, so no caller can pass collapsedLabel (Current-state impact)" with the matching bullet.

@cixzhang

cixzhang commented Nov 1, 2026

Copy link
Copy Markdown
Contributor Author

/approve-spec cd28713

@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.

The three record fixes from the last review are in and the records now agree; one description edit remains. INV3a now covers only INV22 create…(element, options) factories and leaves spec:AST-103's shipped-English strings in place, but the description still says "INV3a covers it, and its implementation adopts the rule" about createReorderable, and that any non-React factory takes per-message options. Please narrow the Maintainer impact, Existing authority searched and implementation lines to INV22 factories, and note that adopting the rule for createReorderable also amends AST-103 FR1 and FR4b. A description edit makes no new commit, so the current /approve-spec still applies.

[Automated review]

Comment on lines +200 to +202
English without one. The rule covers INV22 factories; a gesture or
interaction spec that fixes its own announcement options keeps them until it
adopts this rule. Per-message options are the factory mechanism; the

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 sentence keeps createReorderable out of INV3a for now: createReorderable(options) is not an INV22 create…(element, options) factory, and spec:AST-103 FR4b keeps its shipped-English strings. The PR description still says "INV3a covers it, and its implementation adopts the rule" and speaks of any non-React factory; please narrow those lines to INV22 factories and note that adopting the rule there also amends AST-103 FR1 and FR4b.

@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.

The record changes are owner-approved at this head and agree with the current specs, and the description now matches INV3a's INV22-only scope, so this review has nothing further to ask. collapsedLabel and INV3a's factory tests land with the createResizable implementation.

[Automated review]

@github-actions

github-actions Bot commented Nov 1, 2026 •

Copy link
Copy Markdown
Contributor

PR Analysis Report

🔎 Preview · 4657870

⏳ Building… Until it's ready, Storybook · Sandbox open the branch's previous preview.

Current run: Heavy CI deferred: runs when marked ready and before merge. Lint, typecheck and any path-filtered checks ran on this push.


Generated by PR Enrichment workflow | View current CI run

@cixzhang cixzhang changed the title spec(i18n, Resizable): factories take per-message announcement options with a catalog default spec(i18n, Resizable, AST-103): factories take announcement and label options with a catalog default Nov 1, 2026
@github-actions github-actions Bot added the needs:spec-owner-review Current knowledge records await owner approval label Nov 1, 2026
@cixzhang

cixzhang commented Nov 1, 2026

Copy link
Copy Markdown
Contributor Author

/approve-spec a174e10

@github-actions github-actions Bot removed the needs:spec-owner-review Current knowledge records await owner approval label Nov 1, 2026

@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.

The record changes are owner-approved at this head, but two of them disagree with each other or with the current AST-103 text and need a record edit before merge.

  • INV3a cites createResizable's flat collapsedLabel as its one-string example, yet the Resizable handle also shows the catalog name "Resize handle", so by INV3a's own grouping rule and verification row it is a multi-string factory: either move Resizable to labels: {handle, collapsed}, or say in INV3a that an existing name option such as label stays flat and is not counted.
  • ReorderableLabels has no key for FR4's tree move announcement ("a tree adds the parent"), although FR1 says labels holds every string the object announces: add a tree key such as placeInTree, or state that tree announcements stay outside labels.

A new commit needs a fresh /approve-spec for its head.

[Automated review]

Comment on lines +199 to +201
factory with one string takes a flat optional string option for it, such as
`createResizable`'s `collapsedLabel`; a factory with more than one groups
them under one optional `labels` object, each key optional. An absent option

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The Resizable handle shows two Astryx strings: its name defaults to the catalog's "Resize handle" (ResizeHandle.tsx, @astryx.resizable.handle.label) beside "Collapsed". Under this sentence that makes createResizable a multi-string factory, and a flat collapsedLabel beside a flat label fails this record's INV3a verification row ("groups more than one string outside one labels object"). Either move Resizable to labels and change this example, or say that an existing accessible-name option such as label stays flat and is not counted.

Comment thread docs/specs/AST-103-reorderable/spec.md Outdated
Comment on lines +151 to +152
position), `place`, `placeAtTop`, `placeAtEnd`, and `placeInGrid` (FR4's
move announcements), `refused` (a move past a rejected row), `notMoved`

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

FR4 also announces a tree move with its parent ("a tree adds the parent"), and none of these four keys carries one, so a TreeList using this object would announce a string no labels key replaces, which FR1's verification row fails. Add a tree key (such as placeInTree, with the parent argument), or say tree move announcements stay outside labels.

@cixzhang

cixzhang commented Nov 2, 2026

Copy link
Copy Markdown
Contributor Author

/approve-spec 4657870

@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.

The record changes are owner-approved at this head, and both record fixes from the last review are in: INV3a now keeps an existing accessible-name option such as label flat and uncounted, so createResizable's flat collapsedLabel is its one-string case, and ReorderableLabels gains placeInTree for FR4's tree move announcement. Nothing further is needed from this review; collapsedLabel, labels and their factory tests land with each factory's implementation. One optional tidy-up: the description still counts eleven announcement keys where FR1 now lists twelve.

[Automated review]

@cixzhang cixzhang closed this Nov 2, 2026
@cixzhang cixzhang reopened this Nov 2, 2026
@cixzhang
cixzhang merged commit c5fbecb into main Nov 2, 2026
94 of 97 checks passed

This branch was successfully deployed

1 active deployment
Preview — 4657870f Deployed Nov 2, 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