Skip to content

fix(spec): admit Child, DataBinding and FunctionCall as external $ref targets, and check rule 3 in the harness - #2708

Open
uny wants to merge 1 commit into
a2ui-project:mainfrom
uny:spec/ref-targets-allowlist
Open

uny wants to merge 1 commit into
a2ui-project:mainfrom
uny:spec/ref-targets-allowlist

Conversation

@uny

@uny uny commented Sep 20, 2026

Copy link
Copy Markdown

Description

Rule 3 of the catalog schema rules ("Restricted $ref Targets", docs/a2ui_protocol.md 565–579) enumerates the common_types.json schemas an external $ref may target. catalogs/basic/v1/catalog.json references three schemas that are not on that list:

schema occurrences where
Child 5 Card.child, Tabs.tabs[].child, Modal.trigger, Modal.content, Button.child
DataBinding 2 Icon.name, openUrl.args.url
FunctionCall 1 openUrl.args.url

The list was written in #1629 when the catalog used ComponentId; DataBinding/FunctionCall arrived with #1944 and #2070, and Child replaced ComponentId in #2056, without the list being updated. An implementer who enforces rule 3 as written cannot load the reference catalog; one who loads it is not enforcing rule 3. Child resolves to ComponentId, which is listed, but rule 3 enumerates $ref targets, so a validator checks the target name, not what it resolves to — and the SDKs' inference formats match on the name Child as well.

This PR:

  1. adds Child, DataBinding and FunctionCall to the rule 3 list;
  2. adds validate_catalogs_ref_targets to test/run_tests.py, which enforces rule 3 over the two catalogs the harness already checks (catalogs/basic/v1/catalog.json and test/testing_catalog.json): every $ref under components, functions and $defs is collected, skipping annotation and literal-data keys (metadata, examples, const, default, enum, description) while a declared property named metadata stays in scope; a local target must name a component or function the catalog declares, and an external target must be one of the listed common_types.json#/$defs/* schemas.

Fixes #2706.

Reproduction

No workflow runs run_tests.py, so:

cd specification/v1_0/test && yarn install && python3 run_tests.py
  • main: 167 passed.
  • With the new check but the list as it stood (drop Child from ALLOWED_EXTERNAL_REF_TARGETS): catalogs/basic/v1/catalog.json fails on exactly its five Child references.
  • This branch: 169 passed (167 + the two catalogs).

Pre-launch Checklist

One time:

For this PR:

  • I have updated the relevant CHANGELOG.md file. — none under specification/
  • I updated/added relevant documentation.
  • My code changes (if any) have tests. — the new check runs over the basic and testing catalogs
  • If my branch is on a fork, I have verified that scripts/e2e_test.sh passes. — N/A, specification/v1_0 only; python3 run_tests.py, pyink --check and prettier --check pass

🤖 Generated with Claude Code

@google-cla

google-cla Bot commented Sep 20, 2026

Copy link
Copy Markdown

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@github-actions github-actions Bot added the status: needs-triage auto-managed: https://github.com/a2ui-project/a2ui/blob/main/scripts/triage.mjs label Sep 20, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request updates the A2UI protocol documentation to allow 'Child', 'DataBinding', and 'FunctionCall' as external $ref targets, and significantly enhances the test suite in 'run_tests.py' by implementing robust, recursive validation for JSON Schema subschemas. Specifically, it adds recursive walks to validate property names (ensuring they are valid UAX #31 identifiers) and $ref targets (ensuring they conform to the protocol's restricted target rules), backed by comprehensive synthetic test cases. Feedback on the changes suggests defensively validating that the loaded catalog is a JSON dictionary in 'validate_catalogs_ref_targets' to prevent potential AttributeError crashes if a malformed catalog parses as a list or primitive.

Comment thread specification/v1_0/test/run_tests.py Outdated
@Varun-S10

Copy link
Copy Markdown
Collaborator

Hi @uny, I have reviewed and verified the changes. Thank you for your contribution.

Hi @gspencergoog, I would like to escalate this PR. Could you please take a look?

@Varun-S10 Varun-S10 added status: needs review and removed status: needs-triage auto-managed: https://github.com/a2ui-project/a2ui/blob/main/scripts/triage.mjs labels Sep 22, 2026
@gspencergoog

Copy link
Copy Markdown
Collaborator

Thanks for fixing this!

Please separate this from #2707 for easier review. Since we're not inclined to include the entire ad-hoc JSON Schema AST traverser from the other change, this change can be reduced to just looking through $refs (skipping metadata, of course).

@uny
uny force-pushed the spec/ref-targets-allowlist branch 2 times, most recently from d73d0d8 to cd013f4 Compare September 22, 2026 22:50
… targets

Rule 3 of the catalog schema rules ("Restricted `$ref` Targets") enumerates
the common_types.json schemas an external `$ref` may target. The reference
catalog at catalogs/basic/v1/catalog.json targets three schemas that are not
on that list: `Child` (5 occurrences), `DataBinding` (2) and `FunctionCall`
(1). The list was written when the catalog used `ComponentId`; the three
names arrived later without the list being updated, so an implementer who
enforces rule 3 as written cannot load the reference catalog.

Add the three names to the list, and add `validate_catalogs_ref_targets` to
the test harness so the document and the shipped catalogs cannot drift apart
again: every `$ref` under `components`, `functions` and `$defs` is collected
(skipping annotation and literal-data keys, while a declared property named
`metadata` stays in scope), a local target must name a component or function
the catalog declares, and an external target must be one of the listed
schemas.

Fixes a2ui-project#2706.
@uny
uny force-pushed the spec/ref-targets-allowlist branch from cd013f4 to d6ba12e Compare September 22, 2026 23:17
@uny

uny commented Sep 22, 2026

Copy link
Copy Markdown
Author

Thanks for the review. I've separated this from #2707 and rebased it onto main as a single commit.

  • Added Child, DataBinding and FunctionCall to the rule 3 list in a2ui_protocol.md.
  • Reduced validate_catalogs_ref_targets to collecting and checking $ref targets, skipping metadata and literal data. The general schema traverser and the synthetic test suite are gone.

run_tests.py now reports 169 passed, up from 167. Removing Child from the allowed set makes the basic catalog fail on exactly its five Child references.

I'll rework #2707 separately along the lines of your check_schema_properties sketch.

@github-actions github-actions Bot added the status: needs-triage auto-managed: https://github.com/a2ui-project/a2ui/blob/main/scripts/triage.mjs label Sep 22, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

status: needs review status: needs-triage auto-managed: https://github.com/a2ui-project/a2ui/blob/main/scripts/triage.mjs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[DOCS]: Rule 3's external $ref allow-list does not admit three schemas catalogs/basic/catalog.json uses

3 participants