Skip to content

feat(scripts): support bracket-quoted keys in the example-validator JSONPath subset - #774

Open
douglasborthwick-crypto wants to merge 1 commit into
Universal-Commerce-Protocol:mainfrom
douglasborthwick-crypto:fix/jsonpath-quoted-keys
Open

feat(scripts): support bracket-quoted keys in the example-validator JSONPath subset#774
douglasborthwick-crypto wants to merge 1 commit into
Universal-Commerce-Protocol:mainfrom
douglasborthwick-crypto:fix/jsonpath-quoted-keys

Conversation

@douglasborthwick-crypto

Copy link
Copy Markdown

Problem

extract= and target= navigate the displayed example with a small JSONPath subset. That subset splits the path on . and matches each segment against ^(\w+)(?:\[(\d+)\])?$, so a segment can only ever be a bare identifier.

UCP uses reverse-domain identifiers and scope tokens as object keys. Their dots are read as path separators and their colons match no segment, so those keys cannot be addressed at all:

<!-- ucp:example schema=common/identity_linking extract=$.config.providers.com.example.attestor[0] -->
ERR  repro.md:17  [schema=common/identity_linking extract=$.config.providers.com.example.attestor[0] op=read]
     extract path not found: $.config.providers.com.example.attestor[0]: 'com'

The same applies to $.capabilities.dev.ucp.common.identity_linking[0] (KeyError: 'dev') and to scope tokens such as dev.ucp.shopping.order:read. There is no escaping form today — ['...'] is not recognised either, so an example whose payload sits under a capability name, a provider key, or a scope token has no usable extract=/target= expression.

Change

Adds the standard bracket-quoted form alongside the existing spellings:

extract=$.config.providers['com.example.attestor'][0]
target=$.capabilities['dev.ucp.common.identity_linking'][0]

Single and double quotes are both accepted.

Path parsing moves into one split_path() helper shared by jsonpath_get, jsonpath_set, jsonpath_get_schema and jsonpath_to_pointer, so all four agree on the grammar. Previously each re-implemented the split inline. Unparsable segments still raise rather than silently mis-navigating.

Compatibility

Bare and indexed paths are unchanged. The doc corpus validates identically before and after — 343 passed, 0 failed, 0 errors, 50 skipped on both main and this branch.

Tests

Adds 10 unit tests to scripts/test_validate_examples.py (52 → 62 passing) covering:

  • bare / indexed / $ regression
  • dotted quoted keys and reverse-domain capability names
  • colon-bearing scope tokens
  • both quote styles
  • jsonpath_set writing through a quoted key
  • JSON Pointer conversion of a quoted key (elision-path reporting)
  • the unquoted-dotted-key error path still raising

Docs

Documents the subset in the validator's contract docstring and in docs/documentation/schema-authoring.md.

Verification

Run locally against ucp-schema 1.4.1:

main this branch
ucp-schema lint source/ ✓ 124 files ✓ 124 files
validate_examples.py 343 / 0 / 0 / 50 343 / 0 / 0 / 50
test_validate_examples.py 52 passed 62 passed
ruff check + ruff format --check clean clean

…SONPath subset

`extract=` and `target=` navigate the displayed example with a small
JSONPath subset. That subset split the path on `.` and matched each
segment against `^(\w+)(?:\[(\d+)\])?$`, so a segment could only ever be
a bare identifier.

UCP uses reverse-domain identifiers and scope tokens as object keys —
`dev.ucp.common.identity_linking`, `com.example.attestor`,
`dev.ucp.shopping.order:read`. Their dots are read as path separators
and their colons match no segment, so those keys could not be addressed
at all:

    extract=$.config.providers.com.example.attestor[0]
    -> extract path not found: ...: 'com'

An example whose payload sits under a capability name, a provider key or
a scope token therefore had no usable `extract=`/`target=` expression.

Adds the standard bracket-quoted form alongside the existing spellings:

    extract=$.config.providers['com.example.attestor'][0]
    target=$.capabilities['dev.ucp.common.identity_linking'][0]

Single and double quotes are both accepted. Path parsing moves into one
`split_path()` helper shared by `jsonpath_get`, `jsonpath_set`,
`jsonpath_get_schema` and `jsonpath_to_pointer`, so all four agree on
the grammar; unparsable segments still raise rather than silently
mis-navigating.

Bare and indexed paths are unchanged — the 343-block doc corpus
validates identically before and after. Adds 10 unit tests covering
bare/indexed regression, dotted and colon-bearing quoted keys, both
quote styles, `jsonpath_set` writes, JSON Pointer conversion, and the
unquoted-dotted-key error path. Documents the subset in the validator
contract and the schema-authoring guide.
@damaz91 damaz91 added the status:needs-triage Signal that the PR is ready for human triage label Aug 26, 2026
@carolinerg1 carolinerg1 added status:under-review and removed status:needs-triage Signal that the PR is ready for human triage labels Aug 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants