Skip to content

Ship the renderer-independent Components 4 foundation - #177

Merged
woksin merged 317 commits into
mainfrom
feat/react-aria-foundation
Aug 30, 2026
Merged

Ship the renderer-independent Components 4 foundation#177
woksin merged 317 commits into
mainfrom
feat/react-aria-foundation

Conversation

@woksin

@woksin woksin commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Summary

Components 4 replaces the PrimeReact-backed Components 3 foundation with Cratis-owned React APIs, semantic markup, typed parts, state attributes, and design tokens while preserving the established component catalog.

React Aria supplies selected interaction primitives internally; it is not part of the public prop, DOM, styling, provider, or type contract. Native semantic HTML and Components-owned implementations remain the default where they are simpler.

This is a major release. Applications should follow the Components 3 to 4 migration guide.

Added

  • Add Components-owned typed parts, stable data-cratis-part values, canonical state attributes, provider messages, strict public declarations, and standalone Common controls. (Complete TSDoc coverage for intentional public exports #173)
  • Add semantic Button variant, tone, and shape props and value-first ChangeHandler<T> callbacks.
  • Add the stable nine-slot stable-presentation/v1 renderer profile for Button, IconButton, TextInput, TextArea, Checkbox, Radio, Switch, ProgressBar, and Surface.
  • Add @cratis/components.mui, @cratis/components.primereact, and @cratis/components.primereact10 as optional presentation adapters. (Library Agnostic components #191, Support MUI #192)
  • Add @cratis/components.conformance, a development-only verification harness for renderer adapter authors covering behavior, parts, state, SSR, and accessibility. Ordinary applications do not install it.
  • Add @cratis/components.migrator, an optional development CLI for upgrading Components 3 source imports, Button appearance props, and value-first callbacks. It uses syntax-aware codemods internally and is not an application runtime dependency.
  • Add a Components ESLint configuration that prevents deprecated root imports and protects renderer-independent boundaries.
  • Add a generated Components 3/4 compatibility manifest used by migration tooling and release validation.
  • Add the explicit @cratis/components/Chat subpath with sidebar, topic, conversation, message-body, action, mention, emoji, and observable-query surfaces.
  • Add Canvas region auto-membership, optional Arc messenger notifications, Canvas controls, and Canvas minimap support.
  • Add ItemAddedToRegion, ItemRemovedFromRegion, NoteTextChanged, and ChatMessageAdded messaging contracts.
  • Add renderer coexistence, primitive adaptation, custom composition, licensing, migration, capability-profile, Chat, and Canvas messaging documentation.

Changed

Fixed

Removed

  • Remove PrimeReact, PrimeIcons, PrimeUI, and Prime theme dependencies and peers from @cratis/components.
  • Remove renderer-specific styled, compatibility, and primereact-v10-palette exports.
  • Remove root component-family namespace exports in favor of explicit subpaths.
  • Remove accidental implementation exports that were not intended public contracts.
  • Remove unused renderer-specific prop-extension declarations that no component implemented.

@woksin

woksin commented Aug 23, 2026

Copy link
Copy Markdown
Contributor Author

@woksin @einari — this comment records why this major takes this direction, why now, what was proven, and what we are deliberately not claiming yet.

Why this is not merely a renderer swap

Components 3 placed Cratis application behavior behind PrimeReact runtime, provider configuration, public types, pass-through slots, theme variables, DOM assumptions, and licensing. PrimeUI's published terms explicitly say that an internal wrapper/design system does not remove developer-seat requirements, and SDK/framework-style redistribution is OEM territory requiring separate clarification.

That meant the commercial renderer was not actually an implementation detail. It was an invisible condition of using Arc-bound dialogs, fields, tables, pages, and notifications.

The technical cost matched the licensing cost:

  • renderer types leaked into every product provider and pt contract;
  • products translated their tokens through Prime presets/variables before Components could use them;
  • exact renderer DOM and slot changes made deep consumer customization brittle;
  • accessibility improvements depended on another product's composition/release decisions;
  • consumers with their own design system still installed and licensed a UI kit they were replacing.

We shipped Components 3 stabilization first (#169, #171, #172 → v3.5.0) so correctness and accessibility were not held hostage by this major migration.

The long-lived boundary

Components 4 now owns:

  • React props, events, markup, and product behavior;
  • semantic --cratis-* tokens;
  • typed pt parts;
  • stable data-cratis-part and state attributes;
  • accessibility composition and regression specs;
  • a maintained baseline appearance and Storybook.

React Aria remains internal for focus, overlays, collections, keyboard behavior, and internationalized dates. It is Apache-2.0 and style-free, but its types/classes/DOM are not the consumer contract. Native HTML is used when simpler.

Arc and @cratis/arc.react continue to own command/query state and generated bindings. Components owns visual policy. This avoids moving UI choices into Arc and preserves the right future seam.

Why no TanStack or compatibility package now

TanStack Table is a good headless engine, but current Components tables do not yet need enough grouping/pinning/faceting complexity to justify another abstraction. #109 should extract query/table state into Arc React only after a second renderer or real consumer proves the contract.

A Prime compatibility package is not published without written licensing/OEM clarity. Components 3 is the compatibility line while consumers migrate.

Baseline appearance and styling

The default UI is intentionally familiar to Components 2/3 users rather than looking like an unrelated redesign:

  • Lara-adjacent blue actions and neutral surfaces;
  • familiar 6px radii, control density, overlays, tables, and light/dark depth;
  • default Button remains the expected primary action.

We intentionally differ where exact Lara reproduction would retain weaker contrast or semantics. Actions/statuses, focus rings, control boundaries, disabled state, forced colors, and reduced motion are stronger.

The stylesheet contract is now real rather than aspirational:

  • tokens — semantic seam with conservative light defaults;
  • styles — prefixed internal utilities and layered structure, with no Tailwind Preflight/reset or token duplication;
  • theme — optional explicit/automatic dark/light, forced colors, and subtree behavior.

Products can override unlayered CSS without specificity wars. Mixed Prime products receive explicit Cratis z-index controls while configuring Prime independently.

Consumer evidence

Custom-token design system

A representative custom-token design system maps its canonical tokens directly to --cratis-*, including actions, controls, statuses, elevation, and focus. Strict provider typing caught a stale attempted migration that still passed Prime-era global pt/unstyled/ripple; correcting it produced a passing representative compile.

Its locale-aware Prime InputNumber remains an honest bounded Prime island until #175 supplies proven parity. We do not claim this archetype is fully migrated.

Deeply customized canvas/compositor host

Representative Dialog, CommandDialog, Stepper, Toolbar, and stable-part usage compiles. Stable parts, state attributes, and product-owned compositor markers preserve deep customization without making product vocabulary part of the Components contract.

Broad direct Prime and local canvas usage make this a staged migration, with existing obligations retained while those surfaces remain.

Components 2/PrimeReact 10 application

This archetype can move directly to Components 4 while retaining PrimeReact 10 as a bounded direct-use island. It does not need an intermediate PrimeReact 11 migration.

Components 3/PrimeReact 11 multi-entry application with an advanced table adapter

This archetype can start baseline-first with Components light/dark while retaining its separate PrimeReact 11 provider and application-owned advanced table adapter. Components does not force canvas-specific Toolbar composition onto ordinary page actions or claim that its default table implements advanced server state.

Verification

The exact candidate has:

  • 262 test files / 795 tests passing;
  • 25/25 export subpaths loading;
  • Prime-free emitted JS/declarations;
  • valid source maps and extension-complete ESM;
  • prefixed/no-Preflight CSS gates;
  • complete MIT/OFL notices and asset verification;
  • Storybook production build plus a11y addon and representative light/dark/product/mobile visual review;
  • automated axe foundation scan;
  • npm Arc 20.3.1 / 21.19.4 / 22.1.0, pnpm, and Yarn PnP exact-artifact validation;
  • representative compile evidence for the custom-token design system and deeply customized canvas/compositor host;
  • 404 KB tarball, SHA-256 1d769e97283d4f57ce70aa2a9ce85952d9e96c182d3d045026b2cfe8e0d71fe2.

What remains deliberately open

A future Vue/Svelte frontend should use Arc transport/generated-client contracts and framework-native state/components. We should extract cross-framework contracts only after another implementation proves them, not pre-abstract React details today.

Requested review focus

  1. Public API ergonomics and named behavior versus pt precedence.
  2. Keyboard/focus/SSR/hydration behavior.
  3. Baseline light/dark familiarity and accessibility.
  4. Custom-token ownership and deeply customized canvas/compositor seams.
  5. Arc/Arc React versus Components ownership.
  6. Migration honesty around direct Prime and advanced tables.
  7. Storybook usefulness as the maintained visual contract.

Please treat renderer leakage, inaccessible behavior, undocumented migration edits, misleading compatibility, or a custom-design-system dead end as blockers. This PR should remain unmerged until you are both comfortable with the major and the RC pilot plan.

Comment thread Documentation/verify-local-links.mjs Fixed
Comment thread Documentation/verify-local-links.mjs Fixed
@woksin

woksin commented Aug 24, 2026

Copy link
Copy Markdown
Contributor Author

Final review update: all latest checks on 3d340d6 are green, including aggregate CodeQL, JavaScript build, 25 exports, Arc 20/21/22, pnpm, Yarn PnP, semver label, Markdown, and the truthful local-link gate (101 docs files / 107 local links / 0 broken). The two earlier CodeQL threads are outdated and resolved after replacing the vulnerable regex/sanitizer with deterministic parsing and adversarial self-tests. No human review has arrived. This major remains intentionally unmerged for @woksin and @einari plus RC-pilot review.

@woksin

woksin commented Aug 24, 2026

Copy link
Copy Markdown
Contributor Author

Additional licensing research — independent verification of the PrimeReact 11 consumer impact

We have done additional research to be certain about what PrimeReact 11 means for Components 3 consumers, prompted by downstream reports that apps on Components 3 show a license notice. Everything below was verified against primary sources: the published @primereact/core@11.1.0 and @primeui/license-manager@1.0.0 npm artifacts (code inspected directly), PrimeReact 11's bundled LICENSE.md, and the primeui.dev license/pricing pages.

Verified findings

  1. The downstream reports are accurate. PrimeReactProvider verifies a license key in a useEffect on mount with no condition on unstyled, theme, or NODE_ENV. Without a valid key it emits a console warning and calls showInvalidLicenseBanner() — a fixed-position, bottom-right, z-index: 2147483647, closed shadow DOM red badge reading "Invalid PrimeUI License", in development and production. Every Components 3 app reaches this through CratisComponentsProvider, on every styling path — including fully unstyled and including the MIT @cratis/components/theme CSS. (This matches what Correct the licensing documentation for PrimeReact 11 #140 documented; we re-verified it against the shipped artifact rather than trusting our own docs.)
  2. A key must be obtained from a PrimeUI account in all cases. The free Community tier is eligibility-limited (org: <$1M revenue and <5 developers and <10 employees and <$3M outside funding; individuals/students/non-profits/non-commercial OSS also qualify), supports up to 4 developers, and requires annual renewal. The license-manager code enforces key expiry with a 30-day grace period for community keys, after which the banner returns. Commercial keys are per-developer, perpetual, with the key checked against the installed version's embedded releaseDate (2026-08-05 for 11.1.0).
  3. Verification is offline — an ed25519 signature check against an embedded public key, no telemetry, no remote connection. Confirmed in the code; matches LICENSE.md.
  4. The upstream primefaces/primereact repository is archived. All future PrimeReact development happens under the PrimeUI commercial model. Existing MIT versions (≤10) stay MIT.
  5. The OEM exposure is real and priced: PrimeStore lists OEM licensing as a flat-annual-fee add-on for "redistributing PrimeUI to your customers", and the license restrictions clause requires it for redistribution as a component library or development tool. This validates the PR's position of publishing no Prime compatibility package without written PrimeTek clarification.

What this means

  • Components 3.x is a transitional line, not a steady state. Every 3.x consumer either holds and annually renews a PrimeUI key (paid for any org above the small-team thresholds) or ships with a permanent red banner in production. Components 2.x (PrimeReact 10, MIT) is the only fully MIT-safe prior line.
  • This PR is the escape hatch, and the research hardens the case for it. We verified the packed Components 4 artifact is Prime-free in runtime deps, peers, emitted JS, and declarations, and that React Aria (Apache-2.0, Adobe-maintained, actively released) does not leak into the public API — so the foundation swap is real, not cosmetic.

Recommended path forward

  1. Proceed with Components 4 as designed — renderer independence is the correct long-term posture for both the product and the library; no architectural change requested.
  2. Publish an explicit Components 3.x support-horizon statement (in migration.md and the release notes): what class of fixes 3.x receives and for how long after 4.0 stable. "Temporary compatibility line" is currently undated, and the license-renewal treadmill makes parking on 3.x costlier than it looks.
  3. Docs: state the cost of staying on 3 inside the 3→4 guide. Documentation/migration.md says Components 3 "remains the compatibility line" but the banner/key/renewal facts live only in migration-from-2.md. Add a short "What staying on Components 3 means" note (key required on every styling path, banner without one, community-key annual renewal + 30-day grace) so a reader of only the 3→4 guide understands the ongoing obligation.
  4. Docs: strengthen ui-foundation.md § "Why PrimeReact is no longer the default" with the two objective facts it currently omits: runtime license enforcement on all styling paths (verified in the shipped artifact), and the archived upstream repository. Both are verifiable and make the rationale self-evident.
  5. Docs (minor, migration-from-2.md): add that keys are obtained from a PrimeUI account, note the 30-day community grace period and the releaseDate coverage check, and — a genuinely positive fact for consumers' compliance reviews — that verification is offline with no telemetry.

None of this blocks the PR; items 2–5 are documentation-scoped and could land as a follow-up commit on this branch or a fast-follow. The standing disclaimer applies: this summarizes public terms and shipped code behavior for architectural transparency; it is not legal advice.

woksin added a commit that referenced this pull request Aug 24, 2026
 pre-stable subset)

Implements the pre-stable subset of #174 for PR #177: fixes confirmed bypass
defects, wires six new provider message groups (prop -> provider -> English
fallback), and adds regression/precedence/sentinel specs. Framework/library
profile change; every existing public prop and its precedence is preserved.

Bypass fixes (Fix 1):
- FilterPanel.tsx: header clear-button "title" hardcoded "Clear filter" /
  "Clear range" next to a correctly-resolved aria-label from the same prop;
  title now mirrors the same value. A searchable filter group with no own
  searchPlaceholder now falls back to the panel-level searchPlaceholder
  prop instead of a second hardcoded "Search..." literal.
- SchemaEditor.tsx: the back-navigation Tooltip's content hardcoded
  "Navigate back" while the same button's aria-label correctly resolved
  labels.navigateBack; both now come from the same source.
- RangeHistogramFilter.tsx: the bar tooltip's unit word ("...42 items") was a
  hardcoded, unoverridable English literal; added itemsLabel (default
  "items").

Dropdown (Fix 2): "Show options" (2 sites) and "Clear selection" (4 sites)
now resolve pt override -> CratisComponentsProvider messages.dropdown ->
English fallback across all six render paths (native/filtered x
single/multiple), preserving per-instance pt overrides.

New provider message groups (Fix 3), each documented with TSDoc and wired
prop -> provider -> English fallback:
- dialog (ok/cancel/yes/no/close) - resolved once in Dialog.tsx, so
  CommandDialog and StepperCommandDialog (which forward these props straight
  through) share the same precedence without duplicating it.
- stepper (next/previous/submit) - CommandStepperContent (shared by
  CommandStepper and StepperCommandDialog) and StepperCommandDialog's own
  Cancel button (which reuses dialog.cancel).
- notifications (dismiss/region) - Toaster.
- dataTable (selectRow/search/searchAriaLabel) - DataTableCore.
- columnFilter (filterTriggerAriaLabel/valueAriaLabel/matchModeAriaLabel/
  matchModeLabel/clear/apply/true/false) - ColumnFilterMenu, added as a
  provider tier between its existing labels prop and English defaults.
- datePicker.label - the orphaned "Date" aria-label fallback in
  DatePickerInput used when neither an explicit aria-label nor a placeholder
  is given.

Docs (Fix 4): English and nb-NO CratisComponentsProvider examples for every
group in Documentation/Common/cratis-components-provider.md, plus precedence
notes in Dialog/Dropdown/Notifications/CommandStepper/StepperCommandDialog/
DataTables docs. No React Aria locale data copied into messages.

Specs (Fix 5): regression specs for every bypass fix; a dedicated
precedence spec per new provider group (English fallback -> provider
message -> prop override, in that order); and a sentinel-provider spec
(Source/Common/for_CratisComponentsProvider/when_every_owned_label_is_overridden.tsx)
that renders every audited surface under one provider with distinct
sentinel messages and asserts none render their English default.

No new ESLint rule: documented in ESLint/README.md why a hardcoded-label
rule would need semantic judgment an AST visitor can't make reliably,
producing either high noise or an allowlist that stops catching new
bypasses; the sentinel-provider spec is the reliable gate instead.

Explicitly out of scope, unless a bypass surfaces there later: PivotViewer,
ObjectContentEditor, SchemaEditor's own generated cell/header copy,
TimeMachine's relative/plural text, and identifier-derived
formatTitle/formatPropertyName. #174 is not fully closed by this change.

Verification: tsc -b (Source/tsconfig.json) clean; eslint clean;
vitest run 275 files / 846 tests passed.
woksin added 13 commits August 25, 2026 12:55
- package.json: add 'Codemods' to the root workspaces array (yarn install
  now symlinks node_modules/@cratis/components-codemods -> Codemods,
  and 'yarn workspace @cratis/components-codemods <script>' / 'cd
  Codemods && yarn <script>' resolve). No new dependency was declared -
  Codemods only uses the already-installed 'typescript' devDependency -
  and yarn.lock is gitignored in this repo, so there is no lockfile diff
  to commit.
- README.md: a short 'Codemods' section pointing at Codemods/README.md
  and the ESLint rule, with the exact invocation
  'node Codemods/scripts/remove-root-namespace-imports.js <paths...>'.

Verified after registering the workspace:
- 'cd Codemods && yarn test' -> 36/36 passing (previously only reachable
  by invoking vitest directly, since yarn refused to run an unregistered
  workspace's scripts).
- 'cd ESLint && yarn test' -> 75/75 passing.
- 'yarn lint' (root) -> exits 0 (Source lints clean; ESLint and Codemods
  are both skipped by run-task-on-workspaces.js - no 'lint' script and
  private:true respectively - which is pre-existing behavior for the
  ESLint workspace, unchanged by this commit).
Running the repo's own eslint config directly against Codemods/ (as part
of verifying the root lint gate for the new workspace) flagged both
'unsupported-require' fixtures: the disable comment named the old
'@typescript-eslint/no-var-requires' id, but this repo's config also has
'@typescript-eslint/no-require-imports' enabled (from the typescript-eslint
recommended preset) and that is the rule id that actually fires on a bare
require() call - no-var-requires fires too, from this repo's own explicit
rule entry, once the first is silenced. Disabling only the stale id left
the fixture failing lint. Both ids are now listed on the
eslint-disable-next-line comment, in both input.ts and expected.ts (they
must stay byte-identical - this is the 'leave completely untouched'
fixture pair).

Verified: 'eslint Codemods' exits 0, and Codemods' 36/36 tests still
pass.
woksin added 4 commits August 30, 2026 13:32
Build and pack Core plus each selected adapter once, then reuse those immutable archives across every peer-boundary and package-manager profile. This matches release semantics and removes shared-dist races.
…ation

# Conflicts:
#	Source/package.json
#	package.json
@woksin

woksin commented Aug 30, 2026

Copy link
Copy Markdown
Contributor Author

Owner review summary — Components 4 final candidate

Candidate: febb5665dd9c5e9870fed889b4723b7d0254fd91

The PR body is intentionally limited to consumer-facing release notes. This comment is the short owner/reviewer entry point; the detailed certification record is in #177 (comment).

What Components 4 changes

  • Replaces mandatory PrimeReact-backed Core with Cratis-owned public contracts and a zero-configuration built-in renderer.
  • Keeps React Aria internal; Cratis owns props, events, semantic markup, accessibility, stable parts/state attributes, and tokens.
  • Makes the package root setup-only; components are imported from explicit subpaths.
  • Adds the stable nine-slot stable-presentation/v1 renderer profile while keeping interaction-heavy/atomic composition unstable.
  • Ships optional MUI, PrimeReact 11, and PrimeReact 10 adapters without making any adapter a Core dependency.
  • Adds Conformance, the Components Migrator, an ESLint migration ratchet, isolated renderer Storybook, and fail-closed release evidence.

Shared release scope

All seven public packages use the repository/GitHub release version 4.0.0:

  1. @cratis/components
  2. @cratis/eslint-plugin-components
  3. @cratis/components.migrator
  4. @cratis/components.conformance
  5. @cratis/components.mui
  6. @cratis/components.primereact
  7. @cratis/components.primereact10

Renderer ABI major 1 is a separate protocol version, not an independent npm version. Plain DOM and Storybook are private evidence and are never published.

Stable renderer boundary

The stable profile contains exactly:

button, iconButton, textInput, textArea, checkbox, radio, switch, progress, and surface.

Dialogs, Dropdown, DatePicker, Tooltip, paginator, atomic behavior, mixed-renderer islands, discovery, and lazy preload remain Core-owned and/or explicitly unstable.

Important migration decisions

  • Components 3 root namespaces move to explicit subpaths.
  • Prime-shaped Button props move to variant / tone / shape with compatibility shims and the optional Migrator CLI.
  • Components-owned callbacks become value-first.
  • CratisComponentsConfig is no longer Partial<PrimeReactProps>.
  • Product CSS should target Cratis tokens, typed pt parts, and stable data-cratis-* state—not renderer internals.
  • Adapters provide primitive presentation, not full vendor-catalog replacement.

Final verification

  • 43/43 hosted checks green on exact candidate
  • Source: 386 files / 1,374 tests
  • Storybook: 4 renderers × 277 stories × 2 appearances = 2,216 interaction/axe cases, zero exclusions
  • Adapter matrix: 18/18 minimum/current × npm/strict-pnpm/Yarn-PnP profiles, using pack-once immutable artifacts
  • Strict TypeScript 6: all 24 public JS subpaths
  • Arc consumer matrix: 20.3.1, 21.19.4, and 22.6.2
  • Production dependency audit: no suggestions
  • Tracked-source secret scan: zero findings
  • Seven 4.0.0 archives + seven CycloneDX SBOMs independently regenerated byte-identically
  • Independent GPT package-documentation and documentation-completeness audits approved
  • All seven npm packages published at 4.0.0 with SLSA provenance and verified registry integrity

What reviewers should decide

Please focus review on:

  1. The seven-package shared-version release scope.
  2. The Cratis-owned/React-Aria-internal architecture.
  3. The stable nine-slot renderer boundary.
  4. The documented Components 3→4 breaking changes and migration path.
  5. Acceptance of the explicitly tracked post-GA limits (cross-browser/manual AT, mixed renderer islands, discovery/preload, theme bridges, slim distribution, API snapshots/evidence inventories, and performance budgets).
  6. The fail-closed release policy in release.md.

A line-by-line review of the entire 317-commit branch should not be necessary; this review summary, the technical certification comment, the migration guide, release policy, and ADRs are the decision record.

Current stop point

Components 4.0.0 is merged and published. All seven public packages use latest: 4.0.0, carry npm provenance attestations, and are represented by Release v4.0.0. Publication issue #207 is closed.

@woksin

woksin commented Aug 30, 2026

Copy link
Copy Markdown
Contributor Author

Technical certification record — Components 4 final candidate

This comment retains implementation, evidence, limitations, and merge/publication details that do not belong in the consumer-facing release note.

Exact source state

Repository-wide package version

All public packages are 4.0.0; compatibility generation rejects any mismatch or cratisIndependentVersion opt-out:

  • @cratis/components
  • @cratis/eslint-plugin-components
  • @cratis/components.migrator
  • @cratis/components.conformance
  • @cratis/components.mui
  • @cratis/components.primereact
  • @cratis/components.primereact10

Renderer ABI major 1 and stable-presentation/v1 are separate protocol identifiers. Plain DOM and Storybook remain private and unpublished.

Verification evidence

  • Immutable integrated CI: Source 386 files / 1,374 tests; ESLint 120; Migrator 103; Conformance 20; PrimeReact 10 11; PrimeReact 11 9; MUI 8; Storybook preflight 9; zero warnings.
  • Storybook on Arc 22.6.2: 4 renderers × 277 stories × 2 appearances = 2,216 interaction/axe cases, zero story/renderer exclusions.
  • Adapter matrix: 18/18 minimum/current × npm/strict-pnpm/Yarn-PnP profiles.
  • Matrix artifacts are pack-once: one immutable Core archive and one archive per selected adapter are reused by every profile.
  • Arc consumer matrix: 20.3.1, 21.19.4, and 22.6.2.
  • Strict TypeScript 6: all 24 public JavaScript subpaths under Bundler and NodeNext; exact upstream exceptions fail stale.
  • Package graph: 24 subpaths / 34 React- and DOM-free kernel modules; Prime absent from Core; Pixi reachable only from Canvas/PivotViewer.
  • Production dependency audit: no suggestions.
  • Tracked-source gitleaks: zero findings.
  • Markdown and repository-local links: zero issues.
  • Independent GPT package-documentation and completeness audits: approved after source-backed corrections.
  • Code, performance, and security reviews found no introduced release blocker.

Reproducible release evidence

All seven registry tarballs were downloaded after publication, matched their npm integrity metadata and package identities, and carry SLSA provenance attestations. Prepublication archives, CycloneDX 1.6 SBOMs, and checksum manifests remain retained as release evidence.

Core archive:

  • 513,313 compressed bytes
  • 2,284,728 unpacked bytes
  • 1,028 files
  • SHA-256 84a7f1418a9d52de2c7d9552d4974c2e5de2ecd9d625e5188f160a64c0527a1c
  • SHA-512 75d9316414588fe93316191bbc37daad9cbe97b7a33f4614b3c00f9a17009e1739066c9923e4206e3518a7a0e405544f5441b3fde8fd3904b590c5c0cb79e721

Other archive SHA-256 values:

  • ESLint 98ebf014d2cb115b47f6497f3d381284cfdc1a41f9df338b38c281f3bc8f281c
  • Migrator 0369d3378092ce7717fa718548fae7edfb95aff490e8a76ece51881a2a8927ea
  • Conformance e1eca97654a1224de29f037b4189e2375a47f8be70d83cdd51837fed6037814c
  • MUI 7875121138c757ac077b3cb77695f6bca4d89b731d74a3ae021069fec98bf554
  • PrimeReact 11 e3c04fc72c92cac3907b57ce8f275c03c7566d573f5f2563b3ee1a157b06ba06
  • PrimeReact 10 b1b210e834dfd96041d4a7c4de623fe11c71440f1d32361b25a33d9962774275
  • Root lockfile 9fe6721ed3cbe3ab4dbd6009ec67a7f7f96873600678db88855ec615df406347

Decision records to review

  • DOM/React contract: Documentation/decisions/0001-dom-coupled-contract.md
  • Component classification: Documentation/decisions/0002-component-classification.md
  • Kernel boundary: Documentation/decisions/0003-kernel-boundary.md
  • Stable presentation profile: Documentation/decisions/0004-stable-presentation-renderer-profile.md
  • Migration: Documentation/Migration/3-to-4.md
  • Release controls: release.md
  • Generated compatibility contract: compat-manifest.json

Explicitly tracked limitations

Issue auto-close plan

GitHub permits at most ten manually linked closing issues per pull request. PR #177 is manually linked to #130, #159, #162, #163, #170, #173, #174, #191, #192, and #195; those will close automatically when the PR is merged into the default branch.

The authorized real merge commit body must carry these remaining closing references:

Closes #196
Closes #198
Closes #199
Closes #200
Closes #220

After merge, all fifteen issue states must be re-read and verified closed. Merely closing the PR without merging closes none of them.

Merge and publication controls

woksin added 6 commits August 30, 2026 16:07
Publish the Components 3-to-4 tool as @cratis/components.migrator and rename its workspace accordingly. Keep codemod as the internal implementation term while documenting Migrator and Conformance by audience and purpose.
Time out dynamic package imports and explicitly exit after flushing a successful one-shot probe so Pixi background handles cannot consume the hosted job timeout.
Prevent consumers from depending on internal transform modules while preserving the documented executables and package metadata contract.
Make installation status, package audiences, public helper APIs, and interaction limits explicit so consumers and adapter authors can evaluate the major release without inferring behavior from source.
Avoid formatter-sensitive nested list indentation and link package guidance to immutable source evidence until the Components 4 documentation is deployed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment