Skip to content

EPBDS-16211: fix the bugs the modernization found, and the docs that drifted - #139

Merged
AlexSamBY merged 1 commit into
masterfrom
fix-found-bugs-and-docs
Oct 1, 2026
Merged

AlexSamBY merged 1 commit into
masterfrom
fix-found-bugs-and-docs

Conversation

@AlexSamBY

Copy link
Copy Markdown
Member

What changes

This PR covers the bugs found during the modernization that were recorded and left open, and the documentation that had drifted. Every behaviour change has a test that fails on the previous code. I checked each one by running its test against master's version of the file; the two deletions have nothing to fail.

Bugs

  1. validate: 'maxLength' failed every value.

    • FIELD.VALIDATION registered the length factory as the validator. The draft row registered the same factory (EPBDS-16211 E2: the five components #132 converted, as TypeScript #133 recorded it there).
    • So the field's validator returned a function, which counts as an error. A form field declaring it could never be submitted, and a draft row could never be added.
    • Both now register maxLength(), the validator at the factory's default of 100 characters.
    • Tests: UIRender.form-flows.test.js and LocalDraftTableRow.append-validation.test.js.
  2. The per-form registries lasted one render.

    • react-final-form 6.5.9 hands its render prop a new {...form, reset} on every render. The registries in state/formRegistry (touched fields, errors, baseline) were keyed by that object.
    • That defeated the touched registry, which exists to remember a field that unmounted. Measured: on a pristine form, touch a required field so that "Required" shows, switch tabs and come back. The error had vanished.
    • The wrapper now keeps one object per final-form instance, so the registries and the subscription outlive a render. All those objects share the instance's methods.
    • Why the instance is told apart by its methods. My first version kept the very first object seen. examples.strict-mode.test.js failed on nestedDataKind, because StrictMode's discarded first render builds an instance of its own. The document was then bound to that discarded instance, and an edit did not show.
    • The corpus measured identical, commits included.
  3. A popup item bound by name did not show its row. Popup content renders with relativeData: false, so the item's data is never resolved by name. The mapper's Text/Title view rendered whatever context it had:

    • nothing, in a popup declared inside a nested row document, where _data is unset and the row is in data;
    • the whole row object, which React rejects, when the popup resolved its row into _data.

    It now reads the field it names from that row, as config.md promises. Test: rules.popup-content.test.js.

  4. Two keys leaked to the DOM. Both are in ENGINE_PROPS now.

    • meta: every popup item carried it as meta="[object Object]".
    • @class: OpenL's serializer puts this tag on every meta node, and React reported it as an invalid attribute name.

    The per-component DOM-boundary tests pick both up from the list.

  5. StandaloneTabs rendered a {text} tab without an icon as the object itself. Its propTypes accept such a tab, and React rejects rendering it. It now renders the text. The component is demo-only.

  6. The demo's percent slider showed "5,000 %" for 50.

    • The Percent renderer takes a fraction and multiplies it by 100, while the example's marks treat the values as percents.
    • The example now uses unit: '%' and shows "50%". The renderer is unchanged, since other views rely on its fraction semantics.
    • The DOM snapshot changed by exactly that tooltip.
  7. The corpus logged five warnings, and now logs none.

    • Two metas put buttoned, a Tabs prop, on a VerticalLayout.
    • InputNumber's propTypes rejected the error={false} every field is handed before the user interacts with it.
    • The form layer marked formProps and instance as required. A nested Data document does not pass them, because it shares its parent's form, which the layer's own form getter already supports.
    • @class reached a <span> (item 4).

    A new contract test, examples.console-clean.test.js, renders every example under StrictMode and expects no console output. With one stray buttoned restored, it fails.

  8. Dead code removed.

    • popupScope's search for a row in the form values' keys could never succeed, because final-form nests a bracketed name into a real array. Doing what it meant, reading a row from field names, would be the guess §2.6-16 removed, so only its live half is kept: the values.
    • components/utils/layouts.js, imported by nothing, is deleted, and so is utils/SizeMe.js, imported only by it.

Documentation

  • docs/UPGRADE-PLAN.md:
    • roadmap row 4-S is marked done (H3, H4 and H5 all landed 2026-09-23), and row 4 records H1 as done;
    • risk R14 is retired after a re-check. Every global it names is closed or was measured not to leak, and it is pinned by the two-instance suites;
    • the §9.3 and E2 findings above are marked fixed.
  • CLAUDE.md no longer says the source is still JavaScript.
  • TooltipPop.tsx's note that a ref cannot reach those components now says that this held on React 16–18. On 19 a ref is an ordinary prop and reaches the element; this was measured in EPBDS-16211 E2: the leaf components the first batch still cast, as TypeScript #134.
  • changelog.md records the consumer-visible fixes under Unreleased → Fixes.
  • docs/SUPPORTED-PROPS.md is regenerated: the boundary lists and one line count.

Measured

  • The corpus is identical to master except the slider example. That example's DOM changed by its tooltip, and it makes one fewer translate call, because the Percent renderer's "%" text is gone: 1013 → 1012 in total.
  • Commits are unchanged: 107 at mount and 27 on an edit.

Gates

All exited 0:

  • lint:js, lint:css, typecheck, typecheck:contract;
  • docs:props:check, docs:views:check, css:fixture:check;
  • test:env-flags, build;
  • test:coverage, thresholds included;
  • test:pack, test:pack:peers, test:types;
  • test:react16, test:react17, test:react19, 2914 tests each, with no worker crash;
  • test:e2e, 41 tests;
  • the manifest contract.

In the demo on the dev server:

  • Slider example: its five tooltips read 35%, 120$, 760$, 500 and 50%.
  • Console: no error in the three examples that used to log one, dropdownExperience, ratingDetails and tableForm.

🤖 Generated with Claude Code

…drifted

Every fix has a test that fails on the previous code.

- validate: 'maxLength' registered the length FACTORY as the validator,
  in FIELD.VALIDATION and in the draft row, so every value failed; both
  register maxLength() now, the 100-character default.
- The per-form registries were keyed by react-final-form's per-render
  {...form, reset}, so a remembered touch lasted one render and a touched
  field remounted by a tab switch lost its error. The wrapper keeps one
  object per final-form instance, told apart by its methods, because
  StrictMode's discarded first render builds an instance of its own.
- A popup Text bound by name renders its row's field: it rendered nothing
  (nested row document) or the whole row object (resolved row scope).
- `meta` and OpenL's `@class` join ENGINE_PROPS, so neither reaches the
  DOM; popup items carried meta="[object Object]".
- StandaloneTabs renders a `{text}` tab without an icon as its text.
- The demo's percent slider shows "50%", not "5,000 %": the Percent
  renderer takes a fraction, and the example's values are percents.
- The corpus logged five warnings, now none, and a contract test holds
  it at zero: two metas put buttoned on a layout, InputNumber rejected
  error={false}, a nested document's formProps/instance were marked
  required, and @Class reached a span.
- popupScope's search for a row in the values' keys could never
  succeed, and is gone; utils/layouts.js and utils/SizeMe.js, imported
  by nothing, are deleted.

Docs: roadmap rows 4 and 4-S and risk R14 are brought up to date, the
plan's findings are marked fixed, CLAUDE.md no longer calls the source
JavaScript, TooltipPop's note about refs covers React 19, and the
changelog records the consumer-visible fixes.

Measured: the 38-example corpus is identical to master except the
slider example's tooltip (and one fewer translate call, 1013 -> 1012);
commits are unchanged, 107 at mount and 27 on an edit.
@AlexSamBY
AlexSamBY merged commit 165f8b6 into master Oct 1, 2026
5 checks passed
@AlexSamBY
AlexSamBY deleted the fix-found-bugs-and-docs branch October 1, 2026 10:50
AlexSamBY added a commit that referenced this pull request Oct 1, 2026
**Stacked on #139.** It is based on that PR's branch, so this diff shows
only its own change. After #139 merges, I rebase it onto master and
retarget it.

## What changes

**`src/core/components` has no JavaScript left outside its tests.** This
converts:
- `Dropdown`, `Listbox`, `Slider`, `PieChart` and `JsonView`;
- the modules they share: `renders`, `types`, `styles`, `files`,
`charts/utils`, `charts/constants` and `JsonView/themes`;
- the two barrels.

Each component exports its props type. `propTypes` stay until E5, as in
the earlier batches.

### Dead code, deleted rather than typed

Each piece was checked for importers first, counting `jest.mock`,
`require` and dynamic `import`. The library's only export is `UIRender`,
so nothing outside the repo can reach these.
- **Four helper modules:** `utils/img`, `utils/react`,
`utils/components` and `utils/interactions`. Their ten helpers were
imported by nothing but their own tests. `utils/index` now re-exports
`timers` alone. `isFileSrc` in `src/core/utils/string.ts` goes too: its
only caller was `cssBgImageFrom`.
- **Five of `renders`' exports had no caller:** `colorDropdownOptions`,
`languageDropdownOptions`, `colorDropdownChoice`, `renderCurrency` and
`renderFloatShort`. `ColorSwatch` goes with them, because only they
rendered it. Their CSS rules stay, for the stylesheet's own cleanup.
- **`charts/utils`' `chartTooltip`**, a recharts leftover.
- **`inputs/translations.js`**, imported by nothing in the library.
`engine/translations.js` registers all twelve of its phrases verbatim,
and every document loads that file. The one test that loaded the deleted
file now loads the engine's.

### What the conversion found

- **A `Dropdown` is never `done`, and this PR leaves that alone.**
- Since May 2023 the wrapper destructures `value` as `valueFromParent`.
Its fallback `done = !error && (!!props.value || props.value === 0)`
therefore reads a `props.value` that is always `undefined`. `Input` and
`InputNumber` compute the same class from their value.
- The visible effect is narrow. `.input--wrapper.done` is what floats a
`float` dropdown's label, so with a value and no focus that label stays
at rest. No tracked meta puts `float` on a dropdown.
- The fix would add `done` to every dropdown wrapper that has a value.
That is a DOM change, so it should be its own PR.
- **`static/images/flags/` is now unreferenced.**
`languageDropdownOptions` was the only thing that read it, and it was
already tree-shaken out of `dist` (`flags/` occurs 0 times in either
bundle). The folder still ships, because a host that copies `static/`
might link a flag from its own markup. Whether to stop shipping it is an
open decision gate in the plan's §10.
- **The E1 contract question about `renders`' `round(value, decimals)`
needed nothing.** #61 had already widened the rounding helpers to
`number | string`. The plan's note is marked resolved.

### Casts and probes

- `Counter`'s cast of `renderFloat` is deleted.
- `InputNative` casts the keyup event it hands `toTextHeight`. React
types `target` as any `EventTarget`, and a keyup's target is the field
itself.
- `types.ts` is `Record<string, any>`, deliberately. It hands out
validators and validator factories side by side, and E5 deletes it.
- `styles.ts` types the four role aliases it assigns after the palette
with one commented cast.
- **Every remaining new cast was proven necessary.** Each was removed
alone and the checker re-run. Two turned out to be unnecessary and were
dropped, and one more became a parameter annotation.
- **A probe of 14 wrong call sites fails on all 14.** It covered every
new props type and helper signature, and was deleted afterwards.

### Renames

Every converted file is a git rename except two:
- **`renders.tsx`** shows as a delete and an add. The five deleted
renderers and their imports were 52% of the old file, so no version of
it can clear git's 50% similarity bar. `git log --follow -M40%` still
follows it.
- **`utils/index.ts`**, a one-line barrel.

### Docs and comments

- Mentions of the renamed files now say `.tsx`, in comments, in the prop
reference's generator and curation, and in a test's notes.
`public/static/ui-render.built.css` is rebuilt for two LESS comments,
and `docs/SUPPORTED-PROPS.md` is regenerated.
- `docs/UPGRADE-PLAN.md` records the seventh batch, marks the E1
question resolved, and adds the flags decision gate.
- `webpack.library.config.mjs`'s comment on `flags/` is updated.
- `CLAUDE.md` says which packages are fully TypeScript.

## Measured

| | base (#139's head) | this PR |
|---|---|---|
| corpus, 38 examples: commits at mount / `translate` calls | 107 / 1012
| 107 / 1012 |
| on an edit: commits / `translate` calls | 27 / 64 | 27 / 64 |
| DOM after mount and after an edit | | identical, all 38 |
| `dist/index.js` | 327,359 bytes | 327,232 bytes |
| `src/core` + `src/library`, TS | 71 files, 10,817 lines | 84 files,
13,078 lines |
| `src/core` + `src/library`, JS | 84 files, 9,339 lines | 65 files,
6,977 lines |
| TypeScript share of the lines | 53.7% | 65.2% |

The bundle loses 127 bytes because `ColorSwatch`'s `propTypes` calls had
survived tree-shaking.

## Gates

All exited 0, run on this branch:
- `lint:js`, `lint:css`, `typecheck`, `typecheck:contract`;
- `docs:props:check`, `docs:views:check`, `css:fixture:check`;
- `test:env-flags`, `build`;
- `test:coverage`, thresholds included;
- `test:pack`, `test:pack:peers`, `test:types`;
- `test:react16`, `test:react17`, `test:react19`, 2870 tests each, with
no worker crash;
- `test:e2e`, 41 tests;
- the manifest contract.

The suite went from 2914 to 2870 tests. All 44 removed tests covered the
deleted code.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
AlexSamBY added a commit that referenced this pull request Oct 1, 2026
**Stacked on #140, which is stacked on #139.** It is based on #140's
branch, so this diff shows only its own change. As the PRs below it
merge, I rebase it onto master and retarget it.

## What changes

**Everything outside the engine is TypeScript now.** That covers
`src/core/modules` except `form/utils.js`, plus `contexts`, `providers`,
`common`, `services` and `src/library`. What is left in JavaScript is
the engine, 25 files, and `modules/form/utils.js`, which shares a cycle
with it.

### Dead code, deleted rather than typed

Most of `modules/variables` was boilerplate from the upstream starter
kit. Every name was checked for importers, with barrels, `require` and
`jest.mock` followed. The library's only export is `UIRender`, so
nothing outside the repo can reach these.

| deleted | why it was dead |
|---|---|
| `variables/_envs.js` | `SERVICE`, `Active.SERVICE`, `Active.state` and
`Active.usersById` were read by nothing. For `Active.passwordCheck`, see
the findings below. |
| `variables/configs.js`, except `UI` | seven network and contact
constants, plus `CONFIG` and `SERVER`, with no importer |
| `variables/defaults.js`, `definitions.js`, `urls.js`, `validations.js`
| no importer. `variables/index` called `localise(definitions)` at load.
|
| `variables/routes.js`, except `ROUTE_HOME` |
`common/variables/routes.js` wrote into `ROUTE` and `ROUTES`, and
nothing read them. `ROUTE_BASE` and `goTo` stay, because the env-flags
gate and the demo read them. |
| most of `variables/files.js` | Five file-name helpers that only its
test called, the MIME tables, `UPLOAD.PATH`, and a copy of
`components/files`' `FILE`. What stays is what `Upload` and the demo
read: `FILE.EXT`, `FILE.TYPE`, `IMAGE.EXTENSIONS` and `UPLOAD.BY_ROUTE`.
|
| `FIELD.ID`, `DEF`, `MIN_MAX`, `FOR` | read by nothing, once
`form/constants` loses its `email` definition and `toSlider` |
| most of `form/constants` | Nine `= true` prop shorthands, `NAME`,
`FORM_ASYNC_VALIDATE`, `API_VALIDATE_FAIL_CODE`, `toSlider` and the
`email` field definition, which only tests read. It still registers
`FIELD.VALIDATE` and `FIELD.VALIDATION`. |
| `form/translations.js` | never imported |
| `form/inputs/UploadGridField.js`, `UploadGridsField.js` | never
imported, and they imported views that do not exist |
| `common/styles.js`, `common/utils/tests.js` | no importer |

Five `src/core/utils` exports lose their last caller: `optionsFrom`,
`enumFrom`, `localise`, `fileFormatNormalized` and `LANGUAGE_LEVEL`. I
left them for a sweep of `utils` of its own, which would find more.

### Findings, left for changes of their own

- **A server-side `validate: 'password'` has always thrown.**
- In a browser, `Active.passwordCheck` returns `window.zxcvbn` or an
accept-all fallback. On a server it returns the stored checker.
`_envs.js` stored `() => {}`, so `isGoodPassword` read `.score` of
`undefined`.
- Measured with the engine loaded in a Node environment: before,
`TypeError: Cannot read properties of undefined (reading 'score')`; now,
`TypeError: Active.passwordCheck is not a function`. Either way the
check throws.
- Fixing it means choosing a server fallback, which is a policy
decision.
- **`validationErrors` renders "Untranslated" for its header.**
- The `PLEASE_COMPLETE_` phrase lived in `form/translations.js`, which
nothing imported. Measured on the base: `_.PLEASE_COMPLETE_` and
`_.EMAIL` read "Untranslated", while `_.REQUIRED` reads "Required".
  - Only tests read `validationErrors`, so no product screen shows this.

### Fixed on the way

- **The view-reference generator's guard walked `.js` and `.jsx` only.**
It failed as soon as `fields.ts` existed. That is the
extension-keyed-gate hazard the plan has recorded seven times before,
and this time it announced itself. It walks TypeScript too now.
- **`asField`'s JSDoc described its options bag as a `Function`
parameter, and the checker believed it.** The JSDoc in the
still-JavaScript `form/utils.js` is corrected, and `DropdownField`
annotates its sanitiser.

### Casts

- `Upload` loses both of its casts. `AppContext` is typed now, and
`UPLOAD.BY_ROUTE` is read as `UploadRouteDefaults | undefined`.
- `ConfigContext` is created with an explicit `undefined`, which is what
`createContext()` gave it.
- **Each cast that remains was proven necessary by removing it alone:**
`FIELD`'s registries, `Active.Field` read at render, `AppWrapper`'s
config, and `AutoSave`'s latest props.
- **A probe of 13 wrong call sites fails on all 13.** It covered every
new props type and signature, and was deleted afterwards.

### Paths and docs

- The library entry is `src/library/index.ts`.
`webpack.library.config.mjs` was updated to match.
- `AppWrapper.tsx` is where the version is written, so these were
updated too: `npm version`'s `git add`, `scripts/sync-version.js` and
the library test's `VERSION_SITES`.
- The coverage thresholds follow the renames. So do the generator paths,
and the comments that named the files.
- `docs/SUPPORTED-VIEWS.md` and `docs/SUPPORTED-PROPS.md` are
regenerated, one path each.
- `CLAUDE.md` names the new entry, and `docs/UPGRADE-PLAN.md` records
the batch.

## Measured

| | base (#140's head) | this PR |
|---|---|---|
| corpus, 38 examples: commits at mount / `translate` calls | 107 / 1012
| 107 / 1012 |
| on an edit: commits / `translate` calls | 27 / 64 | 27 / 64 |
| DOM after mount and after an edit | | identical, all 38 |
| `dist/index.js` | 327,232 bytes | 322,888 bytes |
| `src/core` + `src/library`, TS | 84 files, 13,078 lines | 113 files,
13,982 lines |
| `src/core` + `src/library`, JS | 65 files, 6,977 lines | 26 files,
5,647 lines |
| TypeScript share of the lines | 65.2% | 71.2% |

The bundle is 4,344 bytes smaller. The deleted modules shipped, because
the barrel that loaded them ran code at load: `localise(definitions)`
and the `Active` assignments.

## Gates

All exited 0, run on this branch:
- `lint:js`, `lint:css`, `typecheck`, `typecheck:contract`;
- `docs:props:check`, `docs:views:check`, `css:fixture:check`;
- `test:env-flags`, which compiles the source with each real webpack
config, the new entry included;
- `build`;
- `test:coverage`, thresholds included;
- `test:pack`, `test:pack:peers`, `test:types`;
- `test:react16`, `test:react17`, `test:react19`, 2847 tests each, with
no worker crash;
- `test:e2e`, 41 tests;
- the manifest contract.

The suite went from 2870 to 2847 tests. 24 tests went with the code they
covered, and one was added, for `FILE.TYPE`.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
AlexSamBY added a commit that referenced this pull request Oct 1, 2026
## What changes

**E5: every `propTypes` declaration is gone, and so is `prop-types`.**
`rg "prop-types" src` returns nothing. The package is out of
`devDependencies`, and lint rejects an import of it.

### What is deleted

- **39 `propTypes` blocks in 38 files.** The E2 and E3 conversions kept
each block on purpose, so this is one deletion rather than forty.
- **The semantic proxy `components/types.ts`**, the barrel's `PropTypes`
re-export, and every `prop-types` and `type` import.
- **The host's and the form layer's handling of prop types.**
`documentHost.ts` copied the class's prop types onto the function
component, and `withFormSetup` merged them under its own. The four tests
that pinned both now pin the rest of what they covered.

### The descriptions survive, in the props types

- **They moved into the props types' JSDoc first**, wherever a type did
not carry them yet: `TableView`, `Tabs`, `Upload`, `ProgressSteps`,
`AutoSave`, `asField`, `asInputDateField` and `ToggleField`.
- **`UIRender`'s three undocumented props are documented in the
published `UIRender.UIRenderProps`**, where a host reads them:
`initialValues`, `form` and `embedded`. The form layer's props are
described in a comment where the layer reads them.
- **A script compared every commented prop with its TS declaration.**
What it still lists is documented by a type alias or by the published
type.
- **Comments that cited `propTypes` as a fact are reworded:** `Counter`,
`Listbox`, `StandaloneTabs`, `documentHost` and the form layer.

### Not done, deliberately: the vocabulary as TS aliases

The plan's E5 step 2 asked for the `type` proxy to be recreated as
aliases, such as `type Id = string` and `type Px = number`. I measured
first:
- **The proxy defined 41 names, and the converted files used 16.**
- **Twelve of the 16 restate PropTypes itself:** `type.String`,
`type.Method`, `type.Of`, and so on.
- **Four carry a meaning of their own:** `Id` (used twice), `Fraction`,
`UrlOrBase64OrPreview` and `NumberOrString`.
- **E2 and E3 already wrote that meaning into the props' JSDoc**, for
example "Fraction from 0 to 1" and "URL to link to".

An alias of a primitive checks nothing. The vocabulary would have been
the same documentation in a second place, and 25 of its names would
never have been used. The plan records this decision.

### No diagnostic a test relied on is lost

- React 16 to 18 warn in development on a failed prop type. React 19
checks none.
- **Two suites allowed prop-type warnings:** four entries in the
examples suite, and two in the nested-row suite.
- **None of the six fired.** I measured this on React 18, on master,
just before the deletion. They are removed, and the nested-row suite now
requires no warning at all.
- **The `formProps`/`instance` warnings that the plan's §8 flagged were
not taken as the contract being met.** The declaration itself was wrong.
A nested `Data` document shares its parent's form and is rendered
without either prop. #139 made both optional.

### Kept from coming back

- **`prop-types` is still installed**, as a dependency of
`eslint-plugin-react`, `react-markdown` and the React 16 fixture. An
import would therefore resolve and bundle it again.
- **`no-restricted-imports` now rejects it in all seven `src`
overrides.** I proved this with a probe file in core, in a test and in
the demo; each failed with the rule's message.
- **`CLAUDE.md` states the rule:** no `propTypes` block. A component's
props type, and its JSDoc, are the documentation.

### Also

- `README.md` no longer lists `prop-types` among the bundled libraries.
- `docs/SUPPORTED-PROPS.md` is regenerated. Only `Dropdown.tsx`'s line
count changed, from 381 to 364.
- The wrong `colGroup` propType that E3 recorded (`{styles}`) is gone
with the rest. The TS type says `style`.
- `docs/UPGRADE-PLAN.md` records E5 and closes its items: the §2 audit
line, the §8 row, the E-checks row and the Appendix C checklist. The
Appendix C command now looks for a dependency entry, since the lint rule
names the package seven times.

### Found, and left for a change of its own

On React 18, the examples suite's other five allowlist entries match
nothing either. Whether any of them still guards something on 16, 17 or
19 is for that change to measure.

## Measured

| | master | this PR |
|---|---|---|
| corpus, 38 examples: commits at mount / `translate` calls | 107 / 1012
| 107 / 1012 |
| on an edit: commits / `translate` calls | 27 / 64 | 27 / 64 |
| DOM after mount and after an edit | | identical, all 38 |
| `dist/index.js` | 322,915 bytes | 311,527 bytes (−11,388, −3.5%) |
| `dist/index.js`, gzipped | 107,110 bytes | 104,047 bytes |
| `isRequired` in `dist/index.js` | 49 | 0 |
| `src/core` + `src/library`, TS | 139 files, 20,203 lines | 138 files,
19,514 lines |

Both bundles were built from `git archive` copies in the same directory.
Built in the worktree, the same trees measure 322,919 and 311,529 bytes;
322,919 is the figure #144 recorded.

## Gates

All exited 0, run on this branch:
- `lint:js`, `lint:css`, `typecheck`, `typecheck:contract`;
- `docs:props:check`, `docs:views:check`, `css:fixture:check`;
- `test:env-flags`, `build`;
- `test:coverage`, thresholds included;
- `test:pack`, `test:pack:peers`, `test:types`;
- `test:react16`, `test:react17`, `test:react19`, 2842 tests each, with
no worker crash;
- `test:e2e`, 41 tests;
- the manifest contract.

The suite still has 2842 tests. Four tests, in three suites, pinned
prop-type forwarding and merging. Each now pins the rest of its subject:
the names, the class left as written, and the state shape.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant