Skip to content

fix: reject an '@'-prefixed member name, and never reify an Attribute's type - #17

Merged
kzangeli merged 1 commit into
mainfrom
fix/at-prefixed-member-names
Sep 11, 2026
Merged

fix: reject an '@'-prefixed member name, and never reify an Attribute's type#17
kzangeli merged 1 commit into
mainfrom
fix/at-prefixed-member-names

Conversation

@kzangeli

Copy link
Copy Markdown
Collaborator

Two fixes for one bug — SEAMWARE/coraine#70. Depends on SEAMWARE/corJsonld#5; merge that first.

A Relationship carrying a sub-attribute named @referredType came back from a GET as

"@referredType": { "type":  { "type": "Property", "value": "Property" },
                   "value": { "type": "Property", "value": "Organization" } }

which is not an Attribute representation at all.

1. The 400 — ldKeywordCheck

Registered with the new corJsonld callback. Any @-prefixed member name that is not a JSON-LD keyword gets 400 BadRequestData.

JSON-LD 1.1 (Expansion Algorithm, step 13.1) drops such a member with a warning. Silently dropping a member of an Entity the client asked us to store is the worse of the two readings — the write returns 201 and the data is not there. TS 104-175 § 5.2.2.3 gives a name a grammar starting at a letter, so an @-prefixed name is not a legal Attribute name either. Neither reading is written down: spec-doubt #125.

Name positions only. Inside a value — a Property's value, a JsonProperty's json, a LanguageProperty's languageMap, where @none is the core context's own key for an unlabelled entry — member names are opaque JSON.

2. The guard — hasExplicitAttrType stamps what it recognizes

This is the real defect, and it is worth fixing independently of the 400.

hasExplicitAttrType() decided "that node is the Attribute's type" by name. The sub-attribute recursion three lines below decided "that node is a sub-attribute" by the KJF_ATTR_TERM bit. Two oracles for one node — and when they disagreed, the Attribute's own type was wrapped into a sub-Property.

They disagreed whenever expansion had not visited the subtree, since that is where the bit is set. Stamping at the point of recognition — exactly as addTypeField stamps the node it creates — makes recognition and marking one act, and closes this off whatever route the object took to get here.

No strcmp chain was re-introduced into the recursion: that list is what the KJF_ATTR_TERM bit replaced, and it had already drifted once (it omitted valueType). The stamp rides on the strcmp hasExplicitAttrType was already doing.

Verification

  • Reproduced against the unfixed broker, exactly as reported.
  • Each fix verified alone. With the expander fix reverted, the stamp on its own restores "type": "Property" as a plain string (value stays reified — that half is what the 400 removes).
  • Full functest suite: 642/642, mongoc.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Mo7DQD14mrErQD4N2v99d2

…'s type

Two fixes for one bug. A Relationship carrying a sub-attribute named
"@referredType" (TS 104-175 § 5.2.2.3 gives a name a grammar starting at a
letter, so this is not a legal name) came back from a GET as

  "@referredType": { "type":  { "type": "Property", "value": "Property" },
                     "value": { "type": "Property", "value": "Organization" } }

which is not an Attribute representation at all.

ldKeywordCheck - registered with the new corJsonld callback - answers 400
BadRequestData for any '@'-prefixed member name that is not a JSON-LD keyword.
JSON-LD 1.1 drops such a member with a warning; silently dropping a member of
an Entity the client asked us to store is the worse of the two readings, since
the write then returns 201 with the data absent. Neither reading is written
down - spec-doubt #125. The rule is about name positions only: inside a value
(a Property's value, a JsonProperty's json, a LanguageProperty's languageMap,
where "@none" is the core context's own key) member names are opaque JSON.

hasExplicitAttrType now STAMPS the node it recognizes, exactly as addTypeField
stamps the one it creates. That is the real defect: the function decided "this
node is the Attribute's type" by name, while the sub-attribute recursion
decided "this node is a sub-attribute" by the KJF_ATTR_TERM bit - two oracles
for one node, and when they disagreed the Attribute's own type was wrapped
into a sub-Property. They disagreed whenever expansion had not visited the
subtree. Stamping at the point of recognition closes that off whatever route
the object took to get here, independently of the 400.

Verified separately: with the expander fix reverted, the stamp alone restores
"type": "Property" as a string.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mo7DQD14mrErQD4N2v99d2
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.

1 participant