Skip to content

feat(dart/a2ui_core): complete v1.0 conformance, module layout, and 0.3.0 release - #3192

Merged
gspencergoog merged 11 commits into
mainfrom
dart_core_post_c1
Oct 14, 2026
Merged

gspencergoog merged 11 commits into
mainfrom
dart_core_post_c1

Conversation

@gspencergoog

@gspencergoog gspencergoog commented Oct 14, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Completes v0.9 and v1.0 conformance and module layout alignment for dart/a2ui_core. Synchronizes reserved @-prefix function rules across TypeScript, Python, and Dart. Resolves parameter $ref schemas in TypeScript web_core and bumps a2ui_core to 0.3.0.

Reviewer Focus

  • In typescript/core/web_core/src/catalog/schema_loader.ts, parameter schemas resolve local $ref pointers and unwrap allOf compositions. Unresolvable schemas fall back to permissive validation.
  • In TypeScript and Python, uax31 modules enforce UAX 31 without stripping leading @ characters. This reserves @ for system functions like @index.
  • schema_loader.ts and catalog.py reject @-prefixed function names. They also guard shorthand parameter detection against JSON Schema keywords and combiners.
  • DataContext and ComponentContext move to lib/src/resolution/, keeping createSurfaceDataContext internal.
  • Shared conformance files and spec examples update to satisfy UAX 31 identifier rules and required component properties.

Changes

Cross-SDK Function and Identifier Validation

  • Added an optional allowLeadingAt flag (default false) to isValidUax31Identifier in TypeScript and is_valid_uax31_identifier in Python.
  • Updated Catalog.fromJson in TypeScript and Catalog.from_json in Python to reject @-prefixed function names with A2uiCatalogError.
  • Updated shorthand parameter detection in TypeScript and Python to ignore definitions that use $ref, allOf, oneOf, anyOf, or not.
  • Extended convertFunctionArgsJsonSchemaToZod in web_core to recursively resolve local #/$defs/ pointers and unwrap allOf compositions. Validation falls back to passthrough() for open combiners.
  • Updated PayloadValidator in TypeScript and Python to permit @index system function calls while checking user function names against UAX 31.

Conformance and Example Fixtures

  • Renamed identifier content-grid to content_grid in catalogs/basic/v1/examples/31_incremental-dashboard.json.
  • Added required properties to Button components in message_processor_v1_0.yaml test cases, updating IDs to text1 and text_child for text tests.
  • Updated test_v10_catalog_from_json_uax31_validation in catalog.yaml. Added cases verifying rejection of @-prefixed function names in catalog.yaml and reserved_keys.yaml.
  • Cleared remaining expected-failure entries in dart/a2ui_core/test/conformance/. All non-v0.8 suites pass.

Dart Core Module Layout and Exports

  • Moved lib/src/processing/expressions.dart to lib/src/expressions/expression_parser.dart.
  • Moved lib/src/rendering/binder.dart to lib/src/resolution/generic_binder.dart and removed lib/src/rendering/.
  • Split lib/src/core/contexts.dart into lib/src/resolution/data_context.dart and lib/src/resolution/component_context.dart.
  • Moved FormatStringFunction to lib/src/basic_catalog/basic_catalog.dart and removed lib/src/processing/basic_functions.dart.
  • Exported GenericBinder, Behavior, BehaviorNode, ExpressionParser, FormatStringFunction, resolveSchemaRefs, and inlineLocalRefs from lib/a2ui_core.dart.

Documentation, Blueprints, and Versioning

  • Added blueprints/codebases/dart/a2ui_core/codebase.blueprint.md tracking compliance against the core module blueprint.
  • Rewrote dart/a2ui_core/README.md with updated examples for v1.0 syntax, signal subscriptions, and renderer event patterns.
  • Bumped dart/a2ui_core to 0.3.0 and updated dependent packages (a2ui_agent, a2ui_cli, and a2ui_flutter) to depend on ^0.3.0.

Impact & Risks

  • Breaking change in TypeScript and Python: isValidUax31Identifier and is_valid_uax31_identifier reject leading @ characters unless explicitly allowed. Catalog.fromJson and Catalog.from_json reject @-prefixed function names.
  • Breaking change in TypeScript: Function argument validation now enforces parameter schemas defined via local $ref pointers. Calls omitting required fields or supplying unexpected properties in strict mode fail validation.
  • Breaking change in Dart a2ui_core 0.3.0: Internal lib/src/ file paths were reorganized. All supported public APIs are exported from package:a2ui_core/a2ui_core.dart.

Testing

  1. Run Dart analysis, tests, doc link validation, and dry-run publishing:

    cd dart/a2ui_core
    dart analyze --fatal-infos
    dart test
    dart doc --validate-links
    dart pub publish --dry-run
  2. Run dependent Dart package tests:

    cd dart/a2ui_agent && dart analyze --fatal-infos && dart test
    cd ../a2ui_cli && dart analyze --fatal-infos && dart test
    cd ../a2ui_flutter && flutter test
  3. Run TypeScript @a2ui/web_core build, unit tests, and conformance suite:

    yarn workspace @a2ui/web_core build
    yarn workspace @a2ui/web_core test
    node typescript/core/web_core/tests/conformance/conformance_test.mjs
  4. Run Python a2ui_core unit and conformance tests:

    uv run pytest python/a2ui_core -q

🤖 Agent-generated

@gspencergoog gspencergoog changed the title dart core post c1 feat(dart/a2ui_core): complete v1.0 conformance, module layout, and 0.3.0 release Oct 14, 2026
gemini-code-assist[bot]

This comment was marked as resolved.

@gspencergoog
gspencergoog added this pull request to stack #3195 October 14, 2026 00:19
@gspencergoog
gspencergoog force-pushed the dart_core_post_c1 branch 4 times, most recently from 4a547a5 to 9cf856b Compare October 14, 2026 19:02
Base automatically changed from dart_core_c1_api_alignment to main October 14, 2026 19:30
@gspencergoog
gspencergoog marked this pull request as ready for review October 14, 2026 19:32
@gspencergoog
gspencergoog requested a review from nan-yu October 14, 2026 19:40
Comment thread dart/a2ui_core/README.md Resolved
Comment thread dart/a2ui_core/README.md Resolved
Comment thread dart/a2ui_core/CHANGELOG.md Resolved

@nan-yu nan-yu left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks for addressing all the comments. Approving, with two minor follow-ups (one inline):

@-prefixed parameter names now differ between SDKs. Because isValidUax31Identifier / is_valid_uax31_identifier no longer strip a leading @, TypeScript and Python reject a catalog function parameter such as '@offset' (Invalid UAX #31 argument identifier: '@offset' in function 'f'). Dart still checks argument names with allowLeadingAt: true (dart/a2ui_core/lib/src/core/catalog.dart:760-765), so the same catalog loads in Dart. Function names already agree, since Dart rejects @ names separately. Rejecting looks consistent with @ being reserved for system functions. If we go that way, we'd drop allowLeadingAt: true for arguments in Dart and add a shared case to conformance/core/catalog.yaml, e.g. a function with an @offset parameter → CatalogError.

- Collect function argument subschemas recursively, resolving local document references (`#/`) and recursing into `allOf`.
- Merge required fields and property shapes across all collected subschemas.
- Fall back to passthrough validation if a referenced schema cannot be resolved or contains open combiners (`anyOf`, `oneOf`).
- Check UAX #31 parameter names across referenced definitions under `rootDoc`.
- Add test coverage in schema_loader.test.ts and payload-validator.test.ts.
…se URL

- Update a2ui_core dependency constraint to ^0.3.0.
- Update a2ui_flutter tests to use A2uiRendererAction, A2uiRendererError, EventSource.subscribe, and MessageProcessor.model.
- Change Apache 2.0 license URLs in dart/a2ui_flutter/LICENSE to http to pass license checks.
# Conflicts:
#	dart/a2ui_flutter/test/a2ui_surface_test.dart
#	dart/a2ui_flutter/test/node_view_test.dart
#	dart/a2ui_flutter/test/support/surface_harness.dart
# Conflicts:
#	dart/a2ui_agent/CHANGELOG.md
@gspencergoog
gspencergoog merged commit bf10897 into main Oct 14, 2026
42 of 43 checks passed
@gspencergoog
gspencergoog deleted the dart_core_post_c1 branch October 14, 2026 23:31
@github-project-automation github-project-automation Bot moved this from Todo to Done in A2UI Oct 14, 2026
andrewkolos added a commit that referenced this pull request Oct 15, 2026
…r-basic-catalog

Brings in #3223 (the merged renames and LICENSE fix) and #3192
(a2ui_core 0.3.0). The README conflict is the basic catalog's Material
note next to lines #3223 left unchanged. Keep the note.

⚠️ Agent-generated
andrewkolos added a commit that referenced this pull request Oct 15, 2026
…bspec

The package now depends on a2ui_core ^0.3.0 (#3192), but the install
sample still showed ^0.2.2.

⚠️ Agent-generated
andrewkolos added a commit that referenced this pull request Oct 15, 2026
* feat(a2ui_flutter): add the framework adapter core

A2uiSurface renders a SurfaceModel through a NodeResolver, and NodeView
renders each ComponentNode through its catalog entry, rebuilding when the
node's props change. ComponentImplementation pairs a component schema with
a widget builder, WidgetCatalog is a catalog of them, and ComponentProps
reads a node's resolved properties, bindings and actions. A component
that has not arrived shows a small progress indicator.

* feat(a2ui_core): expose the v0.9 basic catalog's API

BasicCatalog.v0_9Api() returns the published v0.9 basic catalog document
parsed with Catalog.fromJson: its components, function signatures and theme
schema, so a framework adapter can read the component schemas without
embedding its own copy of the document.

* feat(a2ui_flutter): add the v0.9 basic catalog

package:a2ui_flutter/basic_catalog.dart implements the 18 components of the
v0.9 basic catalog with Material widgets, with their schemas from
a2ui_core's BasicCatalog.v0_9Api() and the functions of
BasicCatalog.v0_9(). basicCatalog() builds the whole catalog under the
basic catalog's id; BasicComponents holds each component for a catalog of
the app's own. The components apply the surface theme's primaryColor as
the primary color, and every specification example renders in a test.

* fix(a2ui_flutter): key a node's subtree by its implementation

A component whose catalogId changes is recreated with the same instance
id, like one whose type changes. Keying the subtree by the type name kept
the old implementation's state when only the catalog changed. Keying by
the resolved implementation resets it in both cases.

* test(a2ui_flutter): cover A2uiSurface.of and maybeOf

* fix(a2ui_flutter): forward the basic catalog's protocol version and instructions

* refactor(a2ui_flutter): rename WidgetCatalog to CatalogImplementation

Pairs it with CatalogApi in a2ui_core, as ComponentImplementation and
FunctionImplementation pair with ComponentApi and FunctionApi.

🤖 Agent-generated

* refactor(a2ui_flutter): use CatalogImplementation in the basic catalog

🤖 Agent-generated

* feat(a2ui_flutter): apply a component's accessibility label and description

NodeView wraps every resolved component in a Semantics that carries the
component's accessibility label as its label and its description as its
hint, so basic and custom components both get them. Without either
attribute the Semantics adds no node, and it stays in the tree so that
adding one later keeps the component's state.

🤖 Agent-generated

* fix(a2ui_flutter): adopt a2ui_core's renderer renames

#3194 renamed A2uiClientAction and A2uiClientError to A2uiRendererAction
and A2uiRendererError, MessageProcessor.groupModel to model and
getClientDataModel to getRendererDataModel, and replaced
EventSource.addListener with subscribe. The adapter's tests and README
still used the old names, so the package's tests no longer compiled on
main.

⚠️ Agent-generated

* fix(a2ui_flutter): use the http Apache license URL

#3205 standardized LICENSE files on http://www.apache.org/licenses/ and
made the license check enforce it. a2ui_flutter's LICENSE, added in
#3084, used https, so the static-checks job fails on main.

⚠️ Agent-generated

* docs(a2ui_flutter): match the README's a2ui_core constraint to the pubspec

The package now depends on a2ui_core ^0.3.0 (#3192), but the install
sample still showed ^0.2.2.

⚠️ Agent-generated

* docs(a2ui_flutter): drop accessibility from the README's unsupported list

NodeView applies a component's accessibility label and description, the
two attributes v0.9 defines, since effca52.

⚠️ Agent-generated
gspencergoog added a commit to gspencergoog/A2UI that referenced this pull request Oct 16, 2026
Prepares the first publish of a2ui_core since 0.2.2 and of a2ui_agent
since 0.0.1-wip004. Neither 0.3.0 nor 0.0.1-wip005 reached pub.dev when
their pubspecs were bumped (a2ui-project#3192, a2ui-project#2890), so this folds each package's
`## Unreleased` section into that version's section instead of opening a
third one.

While folding, the entries were checked against lib/ and corrected:

- a2ui_core: `PayloadValidator.protocolVersion`, `commonTypesSchema`,
  `checkVersion`, `forVersion` and `MessageProcessor.commonTypesSchema`
  were described as removed but still exist. `DataContext.isV10`,
  `A2uiCompileError`, `Catalog.protocolVersion` as a `String?` and the
  flattened `ComponentApi.schema` were never in a published version, so
  they are described in their final form rather than as renames or
  removals. `DataContext.dispose` does not exist. The new `intl` and
  `logging` dependencies are listed. Notes about tests and tooling are
  dropped and overlong lines are wrapped.
- a2ui_agent: payload checks go through `MessageProcessor.forAgent`, not
  `Catalog.withFunctions`. Entries that revised unpublished wip005
  entries are merged into them, including the v1.0 entries from a2ui-project#3242.

No code changes. The versions in pubspec.yaml were already set.
gspencergoog added a commit that referenced this pull request Oct 19, 2026
## Why

`a2ui_core` is `0.3.0` on `main`, but pub.dev still has `0.2.2`: the version bump in #3192 was never followed by a publish, and later PRs stacked a new `## Unreleased` section on top. This PR is the release PR described in [docs/contributing/release.md](https://github.com/a2ui-project/a2ui/blob/main/docs/contributing/release.md#pubdev-publishing-steps): it folds `## Unreleased` into `## 0.3.0`, the version that will actually ship, so the changelog has one section per published version.

Relative to the published 0.2.2, 0.3.0 is a minor bump that covers the breaking renames (`A2uiClientAction` to `A2uiRendererAction`, `EventListenable.addListener` to `EventSource.subscribe`, `MessageProcessor.groupModel` to `model`, `DataPath` and `MinimalCatalog` removed, and so on).

`a2ui_agent` is not part of this release: its `-wip` versions are published only by exception, when someone needs to try the package outside the repo, so its changelog is left as it is on `main`.

## What changed

While folding, each entry was checked against `lib/`, and the ones that did not match were corrected:

- `PayloadValidator.protocolVersion`, `commonTypesSchema`, `checkVersion`, `PayloadValidator.forVersion`, `MessageProcessor.commonTypesSchema` and the `version` parameter of `validatorFor` were described as removed. They all still exist; the entry now lists only `A2uiValidationError.details` and `MinimalCatalog` as removed, and mentions `PayloadValidator.commonTypesFor`.
- `DataContext.isV10`, `A2uiCompileError`, `Catalog.protocolVersion` as a `String?`, `ComponentNode.props` before `ResolvedBinding`, and the flattened `ComponentApi.schema` were never in a published version. They are described once, in their final form, instead of as renames, removals or breaking changes; two entries that contradicted each other (`isV10` to `usesDirectives` vs. `atLeastV10`; `allOf` flattened vs. kept as written; `dispatchAction` emitting only `event` vs. `event` and `name`) are resolved in favor of what the code does.
- `DataContext.dispose` does not exist and is no longer mentioned; `resolveListenableWithPending` was not in 0.2.2, so `resolveSignalWithPending` is listed as added.
- The new `package:intl` and `package:logging` dependencies get an entry.
- Three duplicate additions of `Catalog.protocolVersion` are merged into one.
- Notes about tests, conformance runners, a private `_subscribe` helper and `tool/generate_basic_catalogs.dart` are dropped, and single-line bullets of up to 1689 characters are wrapped.

No code changes. The version in `pubspec.yaml` was already set.

## Testing

- `dart pub publish --dry-run` in `dart/a2ui_core`: 0 warnings.
- `yarn dlx [email protected] --config .prettierrc --check dart/a2ui_core/CHANGELOG.md` passes.
- Every symbol named in the corrected entries was located in `dart/a2ui_core/lib`.
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.

2 participants