Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/w3c-context/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ The package includes the following pre-cached contexts:
- `https://trustvc.io/context/render-method-context.json` - Render Methods
- `https://trustvc.io/context/attachments-context.json` - Attachments
- `https://trustvc.io/context/qrcode-context.json` - QR Code
- `https://trustvc.io/context/opencerts-context.json` - OpenCerts Certificate
- `https://trustvc.io/context/bill-of-lading.json` - Bill of Lading
- `https://trustvc.io/context/bill-of-lading-carrier.json` - Bill of Lading Carrier
- `https://trustvc.io/context/coo.json` - Certificate of Origin
Expand Down
81 changes: 81 additions & 0 deletions packages/w3c-context/src/context/opencerts-context.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
{
"@context": {
"@version": 1.1,
"@protected": true,
"OpenCertsCertificate": {
"@id": "https://trustvc.io/terms#OpenCertsCertificate",
"@type": "@id",
"@context": {
"@protected": true,
"name": {
"@id": "https://schema.org/name"
},
"description": {
"@id": "https://schema.org/description"
},
"issuedOn": {
"@id": "https://schema.org/dateIssued"
},
"admissionDate": {
"@id": "https://trustvc.io/terms#admissionDate"
},
"graduationDate": {
"@id": "https://trustvc.io/terms#graduationDate"
},
"recipient": {
"@id": "https://trustvc.io/terms#recipient"
},
"nric": {
"@id": "https://trustvc.io/terms#nric"
},
"course": {
"@id": "https://schema.org/course"
},
"transcript": {
"@id": "https://trustvc.io/terms#transcript"
},
"grade": {
"@id": "https://schema.org/gradeLevel"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

In JSON-LD 1.1, if a term in @contextis used as a property, can its@idbe a class IRI such ashttps://schema.org/Organization`? Also, what does Schema.org https://schema.org/gradeLevel represent, and is it intended for academic result values like "A", GPA, or "Distinction"?`

💡 Result:

  1. JSON-LD 1.1: can a property term’s @id be a class IRI (e.g., https://schema.org/Organization)?
    Yes syntactically: in JSON-LD 1.1 a term definition’s @id value may be any IRI/compact IRI/term/etc., and JSON-LD processors generally don’t enforce whether that IRI is “really” an RDF property. However, if you then use that term as a JSON property, the expanded IRI is used as the predicate, so mapping a property term to a class IRI is usually a modeling mistake (you’d typically use that class IRI with @type, not as a predicate). [1]

  2. What does Schema.org gradeLevel represent, and is it for “A”, GPA, “Distinction”, etc.?
    https://schema.org/gradeLevel is not a Schema.org term (the URL returns 404 Not Found). [2]

What people often mean instead is educationalLevel, which Schema.org defines as: “The level in terms of progression through an educational or training context” (e.g., beginner/intermediate/advanced, or formal level/grade schemes). [3] Schema.org’s examples show it being used with a “US Grade Levels” scheme (e.g., grade “2”). [4]

So it’s not intended for academic result values like letter grades (“A”), GPA, or honors (“Distinction”); it’s for the learner’s/credential’s/resource’s level in an education/training progression. [3][4]

Sources
[1] JSON-LD 1.1 spec (term definition @id value constraints) (w3.org)
[2] Schema.org gradeLevel URL (404) ()
[3] Schema.org educationalLevel definition (schema.org)
[4] Schema.org educationalLevel example using “US Grade Levels” (schema.org)

Citations:


🏁 Script executed:

fd "opencerts-context.json" -t f

Repository: TrustVC/w3c

Length of output: 110


🏁 Script executed:

cat -n packages/w3c-context/src/context/opencerts-context.json | head -100

Repository: TrustVC/w3c

Length of output: 2798


Use custom predicates from trustvc.io instead of Schema.org gradeLevel and Organization.

Line 37-38: gradeLevel at https://schema.org/gradeLevel does not exist in Schema.org and is semantically wrong for certificate result values like "A", GPA, or "Distinction".

Line 73-74: organisation uses https://schema.org/Organization, which is a class IRI, not a predicate—a modeling mistake in JSON-LD. Properties should map to predicates, not classes.

Both terms will be published as part of the VC context (via packages/w3c-context/src/lib/index.ts) and become locked into issued credentials, making future migrations difficult. Use custom predicates consistent with the existing trustvc.io terms already used throughout this file.

🔧 Suggested fix
         "grade": {
-          "@id": "https://schema.org/gradeLevel"
+          "@id": "https://trustvc.io/terms#grade"
         },
@@
         "organisation": {
-          "@id": "https://schema.org/Organization"
+          "@id": "https://trustvc.io/terms#organisation"
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/w3c-context/src/context/opencerts-context.json` around lines 37 -
38, The JSON-LD context incorrectly maps "grade" to the non-existent schema.org
predicate https://schema.org/gradeLevel and maps "organisation" to a class IRI
(https://schema.org/Organization) instead of a predicate; replace both with
stable trustvc.io predicate IRIs used elsewhere in this file (e.g., use
something like https://trustvc.io/terms/grade and
https://trustvc.io/terms/organisation) so that "grade" and "organisation" keys
point to predicate IRIs, and update the context publishing path in the context
builder (the code referenced by lib/index.ts that exports this context) to use
the corrected terms. Ensure the new IRIs follow the existing trustvc.io pattern
in this file and preserve any language/term definitions already present.

},
"courseCredit": {
"@id": "https://trustvc.io/terms#courseCredit"
},
"courseCode": {
"@id": "https://trustvc.io/terms#courseCode"
},
"examinationDate": {
"@id": "https://trustvc.io/terms#examinationDate"
},
"semester": {
"@id": "https://trustvc.io/terms#semester"
},
"additionalData": {
"@id": "https://trustvc.io/terms#additionalData"
},
"merit": {
"@id": "https://trustvc.io/terms#merit"
},
"studentId": {
"@id": "https://trustvc.io/terms#studentId"
},
"transcriptId": {
"@id": "https://trustvc.io/terms#transcriptId"
},
"certSignatories": {
"@id": "https://trustvc.io/terms#certSignatories"
},
"signature": {
"@id": "https://trustvc.io/terms#signature"
},
"position": {
"@id": "https://schema.org/jobTitle"
},
"organisation": {
"@id": "https://schema.org/Organization"
}
}
}
}
}


3 changes: 3 additions & 0 deletions packages/w3c-context/src/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import jwsV1 from '../context/jws-2020-v1.json';
import multikeyV1 from '../context/multikey-v1.json';
import promissoryNoteContext from '../context/promissory-note.json';
import qrCodeContext from '../context/qrcode-context.json';
import opencertsContext from '../context/opencerts-context.json';
import renderContext from '../context/render-method-context.json';
import renderContextV2 from '../context/render-method-context-v2.json';
import statusList2021V1 from '../context/status-list-2021-v1.json';
Expand All @@ -38,6 +39,7 @@ export const RENDER_CONTEXT_URL = 'https://trustvc.io/context/render-method-cont
export const RENDER_CONTEXT_V2_URL = 'https://trustvc.io/context/render-method-context-v2.json';
export const ATTACHMENTS_CONTEXT_URL = 'https://trustvc.io/context/attachments-context.json';
export const QRCODE_CONTEXT_URL = 'https://trustvc.io/context/qrcode-context.json';
export const OPENCERTS_CONTEXT_URL = 'https://trustvc.io/context/opencerts-context.json';

export const BOL_CONTEXT_URL = 'https://trustvc.io/context/bill-of-lading.json';
export const BOLC_CONTEXT_URL = 'https://trustvc.io/context/bill-of-lading-carrier.json';
Expand Down Expand Up @@ -85,6 +87,7 @@ export const templateContexts: { [key: string]: Document } = {
[INVOICE_CONTEXT_URL]: invoiceContext,
[PROMISSORY_NOTE_CONTEXT_URL]: promissoryNoteContext,
[WAREHOUSE_RECEIPT_CONTEXT_URL]: warehouseReceiptContext,
[OPENCERTS_CONTEXT_URL]: opencertsContext,
};

export const CredentialContextVersion = {
Expand Down