Repository navigation
Conversation
A component property declared directly as an array of ComponentId refs was not recognized by analyze_child_ref_schema, because the items ref was resolved to its plain string type before the check. Such properties fell back to the v0.8 heuristic, so a strict config accepted an item naming a missing component, and error paths read 'name.[i]'. Adds shared validator conformance cases for v0.9 and v1.0. Signed-off-by: Nan Yu <nanyu@google.com>
Child references read from an array now carry the item index in their
field path ('slots[1]' rather than 'slots'), matching the other SDKs and
the new validator conformance cases.
Signed-off-by: Nan Yu <nanyu@google.com>
There was a problem hiding this comment.
Code Review
This pull request updates the validation behavior for component properties declared directly as an array of component IDs to ensure they are consistently read as a list of child references across all validation configurations. It updates the Python implementation in reference_map.py to identify these references before resolving schemas, and updates the Swift implementation in GraphTopologyValidator.swift to report index-based paths (e.g., name[i] instead of name.[i]). Conformance tests for both v0.9 and v1.0, along with language-specific unit tests and a changelog entry, have been added to verify these changes. I have no feedback to provide.
The legacy A2uiValidator reports an item of a list reference under the bare
field name ('slots'), not with its index ('slots[1]'), so the two new
dangling-reference cases fail on the message. They join the topology cases
the harness already skips for wording differences.
Signed-off-by: Nan Yu <nanyu@google.com>
Signed-off-by: Nan Yu <nanyu@google.com>
#3344 added a dangling reference case and a reachable child case for arrays of ComponentId to the v0.9 and v1.0 validator suites. Drop this branch's duplicates of those two and keep its partial dangling and circular reference cases. Python now passes main's dangling cases, so they leave its skip list, and Kotlin passes main's v0.9 dangling case, which checks only the missing id. Signed-off-by: Nan Yu <nanyu@google.com>
polina-c
left a comment
There was a problem hiding this comment.
This addresses #3326 (comment): the CHANGELOG line and the test_reference_map.py case are both here.
What I checked at 1f354a2:
- Python: with the base commit's
reference_map.py, the new unit test fails (slotsis missing fromlist_refs), and so do the four dangling and partial dangling conformance cases. With the fix, all eight ComponentId array cases pass. For the two sample catalogs in the description,Column.childrenis now a list reference; on the base commit it is missing. - Swift:
swift testpasses (575 tests). With the base commit'sGraphTopologyValidator.swift, the newPayloadValidatorTestscase and both validator conformance suites fail, so the index change is needed. - TypeScript
web_core, Darta2ui_coreand the Kotlin legacy SDK pass the new cases without changes.
One addition for the description: the Swift change also changes the UNALLOWED_CHILD detail path (root.children becomes root.children[0]) and the self-reference message, since both read reference.field in GraphTopologyValidator.swift. That matches the new paths, but it is a visible change, and the description only mentions dangling-reference messages.
Two small comments below on test readability.
🤖 Agent-generated
… test entry covers the fix - Move the partial-dangling and circular ComponentId array cases to just after #3344's dangling and child-reachable cases in validator_v0_9.yaml and validator_v1_0.yaml, so the four cases sit together. The cases are unchanged. - test_reference_map.py: say that `external` passed before the fix (only `#/` pointers are resolved) and that `slots` is the shape a loaded catalog has, which the fix covers. Signed-off-by: Nan Yu <nanyu@google.com>
Problem
In the Python core,
analyze_child_ref_schemadid not recognize a property declared directly as an array of component ids,{"type": "array", "items": {"$ref": ".../ComponentId"}}, as opposed to the sharedChildListtype. It resolved the items$refto its plain string type before checking it, so the property's reference spec came out empty and the reader fell back to the v0.8 heuristic, which only treats an item as a reference when it names a component the surface already holds. Under a strict config:rootwithslots: ["missing"]was accepted, with no dangling-reference error;slots.[1]instead ofslots[1].Two sample catalogs declare
Column.childrenthis way:samples/community/agent/adk/file_upload_summarizer/catalogs/0.9/file_upload_catalog.jsonandsamples/community/agent/adk/mcp_app_proxy/catalogs/0.9/mcp_app_catalog.json. An agent checking its tree at the end of a response would not catch aColumnnaming a child that does not exist.Changes
conformance/core/validator_v0_9.yamlandconformance/core/validator_v1_0.yaml, on an inline catalog with aStack.slotsproperty:test_v0X_topology_component_id_array_dangling_reference_error(one missing item, a dangling reference namingmissing_slot) andtest_v0X_topology_component_id_array_child_reachable(a held item is reachable). This PR adds two more to each suite:..._partial_dangling_reference_error(one held and one missing item, a dangling reference atslots[1]) and..._circular_reference_error(a cycle throughslotsis detected). Its own dangling and reachable cases, which duplicated test(conformance): cover reference reading and composition cost in the core suites #3344's, were dropped when merging main.SKIP_TEST_NAMES; this PR removes them, since the fix passes them, and keeps the v0.8 pair, which is a known Python difference (it reads a v0.8 string property as a reference when it names a held component). Kotlin'sA2uiValidatorreads these arrays as references but reports items under the bare field name, so its skip list keeps onlytest_v09_topology_component_id_array_partial_dangling_reference_error, which checksslots[1]; main's v0.9 dangling case checks only the missing id, which Kotlin passes (Kotlin conformance: 174 passed).a2ui_core):analyze_child_ref_schemachecks the array items for aComponentId/Child/ChildListref before resolving it. Newtest_reference_map.pycase.swift/core): it already read these arrays as references, but recorded every item under the bare property name (slots). It now records the index (slots[1]), as the other SDKs do, so the partial dangling case'sslots[1]check holds. test(conformance): cover reference reading and composition cost in the core suites #3344's cases check only the missing id or no error, so the path change does not affect them. This also applies toChildListarrays such aschildren. Every message that names a reference's field changes the same way, since they all readreference.fieldinGraphTopologyValidator.swift: the dangling-reference message, the self-reference message, and theUNALLOWED_CHILDdetail path (root.childrenbecomesroot.children[0]). NewPayloadValidatorTestscase.web_core) and Dart (a2ui_core) already pass all of these cases, so they are unchanged.Behavior changes (Python)
Such arrays are now read as lists of references under every config. A strict config reports an item naming a missing component as a dangling reference, and error paths read
name[i]. Recorded inpython/a2ui_core/CHANGELOG.md.Testing
pyink --check .,mypy ., andpytest(all packages) pass. Thetest_reference_map.pycase, the partial dangling cases and main's two dangling cases fail on main and pass with the fix (the ComponentId array conformance cases: 8 passed). Loading the two sample catalogs now givesColumn.childrenas a list reference.validator_conformance_test.dartpasses, new cases included.A2UICoreimports Combine and does not build on Linux. CI runs it on macOS.This came out of review on #3326 (#3326 (comment)), where the fix was taken out to keep that PR a pure performance change.