Skip to content

fix: annotate resolved schemas with dialect-aware id keyword#912

Merged
DannyvdSluijs merged 3 commits into
jsonrainbow:mainfrom
penyaskito:fix/911-uri-retriever-dialect-aware-id
Jun 3, 2026
Merged

fix: annotate resolved schemas with dialect-aware id keyword#912
DannyvdSluijs merged 3 commits into
jsonrainbow:mainfrom
penyaskito:fix/911-uri-retriever-dialect-aware-id

Conversation

@penyaskito

Copy link
Copy Markdown
Contributor

Summary

  • UriRetriever::retrieve() now reads the root schema's $schema keyword to determine whether to annotate with id (Draft-3/4) or $id (Draft-6+)
  • Schemas without a $schema keyword default to $id, matching the library's Draft-6 default dialect
  • Updated testRetrieveSchemaFromPackage to assert structure instead of a brittle md5 hash

Context

UriRetriever::retrieve() unconditionally stamped $jsonSchema->id = $resolvedUri on every resolved schema. Draft-6 renamed id to $id, but the annotation was never updated. This leaks a Draft-4 keyword into schemas resolved under Draft-6/7, causing errors in strict validators (e.g. Ajv: NOT SUPPORTED: keyword "id", use "$id" for schema ID).

The dialect is detected from the root schema before pointer resolution, so sub-schemas inherit the correct keyword from their parent document.

Internally safe — SchemaStorage::findSchemaIdInObject() already reads both id and $id.

Test plan

  • Full test suite passes (6928 tests, 0 failures)
  • Verified Draft-04 meta-schema → id, Draft-07 → $id, no $schema$id

Fixes #911

Comment on lines -342 to +343
$this->assertEquals('454f423bd7edddf0bc77af4130ed9161', md5(json_encode($schema)));
$this->assertEquals('object', $schema->type);
$this->assertObjectHasAttribute('$id', $schema);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

⚠️ I'm not sure why an md5 was used here. Maybe it should just update this to the new md5 now that it uses $id instead of id?

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.

This was from a 9 years ago commit by a maintainer which is no longer active. I belief this to be a quick way to check for the expected result. These test now no longer confirm the id or $id value which would be even better. Could you add that an assertion for that?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good point — added value assertions ("id" or "$id" based on the active Draft) in 85bfc72.

Copilot AI 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.

Pull request overview

Fixes UriRetriever::retrieve() unconditionally stamping the Draft-4 id keyword onto every URI-resolved schema. It now inspects the loaded root schema's $schema keyword and uses id only for Draft-3/4, defaulting to $id otherwise (matching the library's Draft-6 default dialect). The corresponding test no longer relies on a brittle md5 of the serialized schema.

Changes:

  • Import DraftIdentifiers in UriRetriever and detect the dialect from the root schema before pointer resolution.
  • Stamp the resolved URI onto either id (Draft-3/4) or $id (everything else) in UriRetriever::retrieve().
  • Replace the md5-of-JSON assertion in testRetrieveSchemaFromPackage with structural assertions on type and the presence of $id.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
src/JsonSchema/Uri/UriRetriever.php Detect dialect from root schema's $schema and annotate with id for Draft-3/4, $id otherwise.
tests/Uri/UriRetrieverTest.php Switch the package-retrieval test from a brittle md5 hash to structural assertions reflecting the new $id annotation.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/JsonSchema/Uri/UriRetriever.php Outdated

@DannyvdSluijs DannyvdSluijs 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.

Thanx for the issue report and the PR. I think it would be best to improve the tests ever so slightly.

Comment on lines -342 to +343
$this->assertEquals('454f423bd7edddf0bc77af4130ed9161', md5(json_encode($schema)));
$this->assertEquals('object', $schema->type);
$this->assertObjectHasAttribute('$id', $schema);

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.

This was from a 9 years ago commit by a maintainer which is no longer active. I belief this to be a quick way to check for the expected result. These test now no longer confirm the id or $id value which would be even better. Could you add that an assertion for that?

penyaskito and others added 3 commits June 3, 2026 21:38
UriRetriever::retrieve() unconditionally stamped resolved schemas with
the draft-04 "id" keyword. Draft-6 renamed this to "$id", but the
annotation was never updated.

Detect the dialect from the root schema's $schema keyword before pointer
resolution. Draft-3/4 schemas get "id"; Draft-6+ and schemas without an
explicit $schema keyword get "$id" (matching the library's default).

Internally safe because SchemaStorage::findSchemaIdInObject() already
reads both keywords. Fixes the issue for external consumers of resolved
schemas (e.g. strict Draft-7 validators like Ajv that reject the
unknown "id" keyword).

Fixes jsonrainbow#911

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…word

The dialect comparison now strips the trailing # from the $schema value
and compares against withoutFragment() constants, so schemas declaring
e.g. "http://json-schema.org/draft-04/schema" (without #) correctly
get `id` instead of falling through to `$id`.

Adds 5 tests covering Draft-04 and Draft-07 with/without fragment, plus
the no-$schema default.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Per review feedback, the retriever tests confirmed only the presence of
the id/$id attribute, not its value. Add an assertion for the stamped
resolved URI to each affected test.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@DannyvdSluijs DannyvdSluijs force-pushed the fix/911-uri-retriever-dialect-aware-id branch from 85bfc72 to 25ec63d Compare June 3, 2026 19:38
@DannyvdSluijs DannyvdSluijs merged commit a10f275 into jsonrainbow:main Jun 3, 2026
18 checks passed
DannyvdSluijs added a commit that referenced this pull request Jun 3, 2026
@penyaskito

Copy link
Copy Markdown
Contributor Author

🚀 thanks!

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

UriRetriever annotates resolved $refs with draft-04 "id" even when configured for Draft-6+

3 participants