Surfaced after #416 fixed the JSON-LD → Turtle conversion to actually emit nested verificationMethod resources. Now that the VM block IS in the Turtle output, the bug in how the type is authored becomes visible.
Symptom
The on-disk profile (e.g. test.solid.social/profile/card.jsonld) declares the verificationMethod's class as a bare "Multikey" string:
"verificationMethod": [{
"id": ".../card.jsonld#nostr-key-1",
"type": "Multikey",
"controller": ".../card.jsonld#me",
"publicKeyMultibase": "fe70102de7ec..."
}]
The profile's @context defines verificationMethod, publicKeyMultibase, controller, etc. as terms — but NOT Multikey. So the converter (src/rdf/turtle.js) can't expand "Multikey" to a full IRI; it emits a relative IRI:
<.../card.jsonld#nostr-key-1> a <Multikey>;
cid:controller <.../card.jsonld#me>;
cid:publicKeyMultibase "fe70102de7ec...".
Resolution
Per RFC 3986, a Turtle parser with no @base directive uses the document's request URL as the base. <Multikey> relative to https://test.solid.social/profile/card.jsonld resolves to:
https://test.solid.social/profile/Multikey
(verified: new URL('Multikey', 'https://test.solid.social/profile/card.jsonld').href)
Intended IRI: https://www.w3.org/ns/cid/v1#Multikey.
Consequences
- Type queries miss: VC validators / SPARQL endpoints querying
?s a cid:Multikey will not find this key. The triple is <#nostr-key-1> rdf:type <https://test.solid.social/profile/Multikey> — a fictional class on the pod's own host.
- Cross-pod inconsistency: the same key on
alice.example.com vs bob.example.com would emit different "class" IRIs (alice.example.com/profile/Multikey vs bob.example.com/profile/Multikey) — same key, two classes, no interop.
- Surface noise: a generic crawler dereferencing the
Multikey IRI hits the pod's /profile/Multikey (404, but logged).
- Spec non-compliance: W3C CID v1 + LWS 1.0 (FPWDs 2026-04-23) require the type be the canonical
https://www.w3.org/ns/cid/v1#Multikey. Same gap for JsonWebKey if/when those VMs ship.
Cause
The profile emitter (probably src/webid/profile.js and the seed code in src/handlers/container.js / src/server.js) writes type: "Multikey" as a bare term, expecting context expansion that the context doesn't provide.
Fix options
A. Emit pre-prefixed CURIE in the JSON-LD source:
Smallest change. Works because the @context already maps cid: https://www.w3.org/ns/cid/v1#. Equally readable to humans.
B. Add Multikey (and JsonWebKey) as terms in the @context:
"@context": {
...,
"Multikey": "cid:Multikey",
"JsonWebKey": "cid:JsonWebKey"
}
Lets future profile-writers keep using the bare class names. More verbose context.
C. Both — emit CURIE AND map the term, so any consumer (RDF parser via Turtle, JSON-LD processor) sees a clean class IRI regardless of which path it takes.
(A) is the cheapest correct fix. (C) is the most defensive.
Acceptance test
After the fix:
curl -s -H 'Accept: text/turtle' https://test.solid.social/profile/card.jsonld
must contain:
<.../card.jsonld#nostr-key-1> a cid:Multikey;
...
— with cid: (or full <https://www.w3.org/ns/cid/v1#Multikey>) — never a bare <Multikey>.
Refs
Surfaced after #416 fixed the JSON-LD → Turtle conversion to actually emit nested verificationMethod resources. Now that the VM block IS in the Turtle output, the bug in how the type is authored becomes visible.
Symptom
The on-disk profile (e.g.
test.solid.social/profile/card.jsonld) declares the verificationMethod's class as a bare"Multikey"string:The profile's
@contextdefinesverificationMethod,publicKeyMultibase,controller, etc. as terms — but NOTMultikey. So the converter (src/rdf/turtle.js) can't expand"Multikey"to a full IRI; it emits a relative IRI:Resolution
Per RFC 3986, a Turtle parser with no
@basedirective uses the document's request URL as the base.<Multikey>relative tohttps://test.solid.social/profile/card.jsonldresolves to:(verified:
new URL('Multikey', 'https://test.solid.social/profile/card.jsonld').href)Intended IRI:
https://www.w3.org/ns/cid/v1#Multikey.Consequences
?s a cid:Multikeywill not find this key. The triple is<#nostr-key-1> rdf:type <https://test.solid.social/profile/Multikey>— a fictional class on the pod's own host.alice.example.comvsbob.example.comwould emit different "class" IRIs (alice.example.com/profile/Multikeyvsbob.example.com/profile/Multikey) — same key, two classes, no interop.MultikeyIRI hits the pod's/profile/Multikey(404, but logged).https://www.w3.org/ns/cid/v1#Multikey. Same gap forJsonWebKeyif/when those VMs ship.Cause
The profile emitter (probably
src/webid/profile.jsand the seed code insrc/handlers/container.js/src/server.js) writestype: "Multikey"as a bare term, expecting context expansion that the context doesn't provide.Fix options
A. Emit pre-prefixed CURIE in the JSON-LD source:
Smallest change. Works because the @context already maps
cid: https://www.w3.org/ns/cid/v1#. Equally readable to humans.B. Add
Multikey(andJsonWebKey) as terms in the @context:Lets future profile-writers keep using the bare class names. More verbose context.
C. Both — emit CURIE AND map the term, so any consumer (RDF parser via Turtle, JSON-LD processor) sees a clean class IRI regardless of which path it takes.
(A) is the cheapest correct fix. (C) is the most defensive.
Acceptance test
After the fix:
curl -s -H 'Accept: text/turtle' https://test.solid.social/profile/card.jsonldmust contain:
— with
cid:(or full<https://www.w3.org/ns/cid/v1#Multikey>) — never a bare<Multikey>.Refs
https://www.w3.org/ns/cid/v1,Multikeyclasssrc/webid/profile.js,src/handlers/container.js