
JSON-LD namespace architecture
Source:vignettes/articles/namespace-architecture.Rmd
namespace-architecture.RmdThe core tension is that each framework uses its own vocabulary (work roles, tasks, competences, skills, levels, learning standards) while comparative analysis needs a framework-agnostic layer that lets SPARQL queries operate uniformly across them.
Design choices
The architecture uses a two-tier namespace structure: a base vocabulary that is cross-framework, and framework-specific vocabularies that subclass the base. Each tier has a distinct prefix.
The base vocabulary subsumes the conceptual common ground of all
in-scope frameworks: framework, organizing unit (the framework’s
top-level enumerated unit, whether a work role, skill, learning standard
cluster, knowledge area, or competence area), role element (task,
knowledge statement, skill statement, competence, learning standard),
sub-point, example, element text, source reference, and structural
metadata (jurisdiction, sector, specificity). Per-framework vocabularies
specialize these via subclassing, so a single SPARQL query targeting
cybed:OrganizingUnit returns parent units across every
framework in the corpus in one pass.
Schema.org (schema:) and SKOS (skos:)
provide the outermost vocabulary layer for generic properties such as
name, description, prefLabel, and altLabel.
cybed:OrganizingUnit itself is
subClassOf skos:Concept for downstream interoperability
with the wider linked-data ecosystem.
The project namespace URI is
https://w3id.org/cybed/ontology# (prefix
cybed). w3id.org provides stable, redirectable URIs for
vocabularies via a community-maintained GitHub repository, which means
the URI persists across changes to the maintainer’s personal
infrastructure. Resolving the URI follows the redirect maintained at the
cybed entry in the w3id.org configuration repo.
Why a custom URI rather than reusing existing ontologies
The natural semantic-web question is: why mint cybed:
rather than reuse an existing competency or skills ontology? Three
constraints made reuse insufficient.
Coverage. Existing competency ontologies (ESCO, O*NET, CEDEFOP qualifications taxonomies) cover labor-market competencies in general terms but do not represent the structural commitments of the specific frameworks this package handles. NICE work roles, SFIA skill levels, and ENISA ECSF role profiles each carry framework-specific structural metadata (TKS classifications, responsibility levels, cross-framework references) that an ESCO-based mapping would either lose or distort.
Pedagogical-frameworks gap. ESCO and the workforce-competency ontologies do not represent K-12 or higher-education curricular frameworks (Cyber.org K-12 standards, CSTA standards, CSEC2017 guidelines, DigComp). The package’s design commitment is to make workforce frameworks and pedagogical frameworks queryable through the same schema. That requires a base vocabulary that subsumes both, which existing competency ontologies do not.
Comparison-layer purpose. The cybed:
schema is designed specifically for cross-framework comparison: a single
SPARQL query targeting cybed:OrganizingUnit returns parent
units across every framework in one pass, regardless of whether that
unit is a NICE work role, an SFIA skill, a Cyber.org K-12 grade-band x
sub-concept cell, or a DigComp competence area. Existing ontologies are
not built to subsume this heterogeneity at the comparison layer.
Where existing vocabulary fits cleanly, the schema reuses it:
Schema.org (schema:) for generic properties (name,
description, version, publisher, datePublished, license) and SKOS
(skos:) for prefLabel and altLabel. Tier 1
cybed: types specialize these where framework structure
requires it. Tier 2 framework prefixes specialize cybed:
types where framework vocabulary requires it.
The two-tier shape
The cross-framework abstract is cybed:OrganizingUnit,
which every framework’s parent type subclasses. Workforce frameworks
where the unit is genuinely a work role or work profile additionally
subclass cybed:Role (itself
subClassOf cybed:OrganizingUnit); non-workforce frameworks
subclass cybed:OrganizingUnit directly.
flowchart TD
OU["cybed:OrganizingUnit<br>(subClassOf skos:Concept)"]
ROLE["cybed:Role<br>(workforce-only)"]
OU --> ROLE
ROLE --> NICE_R["nice:WorkRole"]
ROLE --> DCWF_R["dcwf:WorkRole"]
ROLE --> ECSF_R["ecsf:RoleProfile"]
ROLE --> CYQ_R["cyqual:WorkRole"]
ROLE --> CCS_R["ccssf:WorkRole<br>ccssf:AdjacentRole"]
ROLE --> OTC_R["otccf:JobRole"]
OU --> SFIA_S["sfia:Skill"]
OU --> CYB_SG["cyberorg:StandardGroup"]
OU --> CSTA_SG["csta:StandardGroup"]
OU --> CSEC_KA["csec:KnowledgeArea"]
OU --> DIG_CA["digcomp:CompetenceArea"]
OU --> CYQ_C["cyqual:Competency"]
OU --> OTC_S["otccf:TechnicalSkillCompetency<br>otccf:CriticalCoreSkill"]
classDef abs fill:#0F172A,stroke:#38BDF8,color:#E0F2FE,stroke-width:2px
classDef wfr fill:#1E293B,stroke:#7DD3FC,color:#E0F2FE
classDef sub fill:#1E293B,stroke:#7DD3FC,color:#E0F2FE
class OU abs
class ROLE wfr
class NICE_R,DCWF_R,ECSF_R,CYQ_R,CCS_R,OTC_R,SFIA_S,CYB_SG,CSTA_SG,CSEC_KA,DIG_CA,CYQ_C,OTC_S sub
Atomic content elements have their own parallel hierarchy under
cybed:RoleElement, with two specialized child types for
parsed sub-content (cybed:Subpoint for
framework-as-specified enumerations and cybed:Example for
pedagogical-scaffolding fragments).
flowchart TD
RE["cybed:RoleElement"]
RE --> NICE_T["nice:TaskStatement<br>nice:KnowledgeStatement<br>nice:SkillStatement"]
RE --> DCWF_E["dcwf:TaskOrKSA"]
RE --> SFIA_SL["sfia:SkillLevel"]
RE --> ECSF_E["ecsf:Task<br>ecsf:Skill<br>ecsf:Knowledge"]
RE --> CYB_S["cyberorg:Standard"]
RE --> CSTA_S["csta:Standard"]
RE --> CSEC_E["csec:Essential"]
RE --> DIG_C["digcomp:Competence"]
RE --> CYQ_E["cyqual:Task<br>cyqual:Requirement"]
RE --> CCS_E["ccssf:Task<br>ccssf:Competency<br>ccssf:ToolOrTechnology"]
RE --> OTC_E["otccf:KeyTask<br>otccf:Knowledge<br>otccf:Ability<br>otccf:ProficiencyDescription"]
RE --> SP["cybed:Subpoint<br>(parsed enumeration)"]
RE --> EX["cybed:Example<br>(parsed scaffolding)"]
classDef base fill:#0F172A,stroke:#38BDF8,color:#E0F2FE,stroke-width:2px
classDef sub fill:#1E293B,stroke:#7DD3FC,color:#E0F2FE
classDef parsed fill:#1E293B,stroke:#FCD34D,color:#FEF3C7
class RE base
class NICE_T,DCWF_E,SFIA_SL,ECSF_E,CYB_S,CSTA_S,CSEC_E,DIG_C,CYQ_E,CCS_E,OTC_E sub
class SP,EX parsed
A single SPARQL query against cybed:OrganizingUnit
returns comparable parent-level bindings across every framework in the
corpus at once. A query against cybed:RoleElement returns
every atomic content node (parents, Subpoints, and Examples). A query
against cybed:Role is workforce-restricted to NICE / DCWF /
ENISA ECSF / CyQUAL / CCSSF / OTCCF.
Tier 1: Base vocabulary (cybed:)
Framework-agnostic terms. cybed:OrganizingUnit is the
cross-framework abstract; every framework’s parent type subclasses it,
and queries against it reach every framework in the corpus.
cybed:Role is reserved for workforce frameworks where the
unit is genuinely a work role or work profile.
-
cybed:Framework, top-level container for a specific framework. -
cybed:OrganizingUnit,subClassOf skos:Concept. The cross-framework abstract for any framework’s top-level enumerated unit (work role, role profile, skill, grade-band x sub-concept cell, level x concept cell, Knowledge Area, competence area). -
cybed:Role,subClassOf cybed:OrganizingUnit. The workforce-specific intermediate type. Asserted on NICE work roles, DCWF work roles, ENISA ECSF profiles, CyQUAL work roles, CCSSF work and adjacent roles, and OTCCF job roles. Not asserted on SFIA skills, Cyber.org K-12 grade-band x sub-concept cells, CSTA level x concept cells, CSEC2017 Knowledge Areas, or DigComp competence areas. -
cybed:RoleElement, an atomic element attached to a parent unit (task, competence, skill statement, knowledge statement, learning standard, etc.). -
cybed:Subpoint,subClassOf cybed:RoleElement. Tags graph nodes parsed from framework-as-specified enumerations within a parent’s text (“such as” lists, “including” patterns, semicolon-delimited examples). Subpoints retain their parent’s framework-native subtype and link back viacybed:elaborates. Subpoints appear in defaultcybed:hasElementtraversals. -
cybed:Example,subClassOf cybed:RoleElement. Tags graph nodes parsed from pedagogical-scaffolding “Clarification statement:” prose (Cyber.org K-12 and CSTA convention). Examples carry no framework-native subtype because the source frameworks treat them as illustrative rather than enumerable. Examples are reachable only via the parent element’scybed:hasExamplepredicate and are excluded from defaultcybed:hasElementtraversals. -
cybed:hasElement, object property from a parent unit to acybed:RoleElement. Cluster-level queries return atomic elements (parents and Subpoints) but not Examples. -
cybed:hasExample, object property from a parentcybed:RoleElementto acybed:Example. The only path by which Examples are reachable from above. Distinct fromcybed:hasElementso role-level “all elements” queries remain restricted to framework-as-specified content. -
cybed:partOf, links a parent unit, atomic element, Subpoint, or Example to itscybed:Framework. -
cybed:elaborates, object property from acybed:Subpointto its parentcybed:RoleElement. Use this predicate to recover the parent-vs-Subpoint distinction when both appear in the samecybed:hasElementcollection. -
cybed:relatedUnit, object property from one organizing unit to another. The plain edge, for a one-hop “what is this connected to” query. Built withbuild_related_unit_metadata(). -
cybed:UnitRelation, a reified relation between two organizing units, used when the publisher qualifies the link. Carriescybed:fromUnitandcybed:toUnit(object properties naming the two units),cybed:relationLabel(the publisher’s own word for the relation), andcybed:proficiencyLevel(the level as printed, always a string, since framework level scales do not compare). Built withbuild_unit_relation_node(). -
cybed:niceCrossReference, a literal recording a framework’s own citation of a NICE work role, where that citation cannot be resolved to a link. A sibling ofcybed:ecfCrossReferenceandcybed:cybokCrossReference. -
cybed:elementText, literal text of the element. -
schema:identifieron an organizing unit, the framework’s own printed code for that unit. Present only where the unit IRI carries a discriminator (see below), so the code the framework prints is still in the graph as data. -
cybed:sourceSection, where this element appears in the source document. -
cybed:jurisdiction, e.g., “US”, “EU”, “UK”, “CZ”, “CA”, “SG”, “global”. -
schema:creditTexton acybed:Frameworknode, the steward’s attribution wording verbatim. -
schema:inLanguageon acybed:Frameworknode, a BCP 47 tag for frameworks whose text is not English. -
cybed:sector, e.g., “civilian”, “defense”, “general”, “K-12-education”, “higher-education”, “citizen-education”. -
cybed:specificity, e.g., “general-IT”, “cybersecurity-specific”, “general-computing”, “general-digital-competence”.
Tier 2: Framework-specific vocabularies
Each framework has its own prefix. The per-framework parent type
subclasses cybed:OrganizingUnit directly (non-workforce
frameworks) or via cybed:Role (workforce frameworks).
Per-framework atomic types subclass cybed:RoleElement.
| Framework | Parent type | Subclass-of | Atomic types |
|---|---|---|---|
| NICE Framework v2 | nice:WorkRole |
cybed:Role |
nice:TaskStatement,
nice:KnowledgeStatement,
nice:SkillStatement
|
| DCWF v5.1 | dcwf:WorkRole |
cybed:Role |
dcwf:TaskOrKSA |
| ENISA ECSF v1 | ecsf:RoleProfile |
cybed:Role |
ecsf:Task, ecsf:Skill,
ecsf:Knowledge, ecsf:Deliverable
|
| SFIA 9 | sfia:Skill |
cybed:OrganizingUnit |
sfia:SkillLevel |
| Cyber.org K-12 | cyberorg:StandardGroup |
cybed:OrganizingUnit |
cyberorg:Standard |
| CSTA K-12 CS | csta:StandardGroup |
cybed:OrganizingUnit |
csta:Standard |
| ACM/IEEE CSEC2017 | csec:KnowledgeArea |
cybed:OrganizingUnit |
csec:Essential |
| DigComp 3.0 | digcomp:CompetenceArea |
cybed:OrganizingUnit |
digcomp:Competence |
| CyQUAL 1.2.0 | cyqual:WorkRole |
cybed:Role |
cyqual:Task, cyqual:Requirement
|
| CyQUAL 1.2.0 | cyqual:Competency |
cybed:OrganizingUnit |
cyqual:Requirement |
| CCSSF 2022 |
ccssf:WorkRole, ccssf:AdjacentRole
|
cybed:Role |
ccssf:Task, ccssf:Competency,
ccssf:ToolOrTechnology
|
| OTCCF v1.1 | otccf:JobRole |
cybed:Role |
otccf:KeyTask |
| OTCCF v1.1 |
otccf:TechnicalSkillCompetency,
otccf:CriticalCoreSkill
|
cybed:OrganizingUnit |
otccf:Knowledge, otccf:Ability,
otccf:ProficiencyDescription
|
Unit IRIs: when a local id is not enough
A node’s IRI is its prefix plus its framework-local id. That works as long as a framework numbers its organizing units and its statements out of separate id spaces, because then no unit id can equal a statement id and no two nodes can land on the same IRI. Most frameworks in the corpus are like that.
A few are not. DCWF draws work-role codes and task/KSA numbers from
one numeric range, so work role 462 and statement 462 both wanted
dcwf:462. Cyber.org K-12 names a grade-band x sub-concept
cell after its axes and names the standards inside it the same way, so a
cell holding exactly one standard wanted that standard’s IRI. Where that
happened the two nodes did not conflict, they merged: one IRI carrying a
unit’s types and a statement’s types at once, and a
cybed:hasElement edge running from the node to itself.
The fix is a discriminator on the unit side only. A framework may
declare a unit_iri_prefix in
docs/framework-invariants.yml; the assembler prepends it to
the unit’s local id when minting the IRI, and the unit’s printed code is
kept as a schema:identifier literal so nothing the IRI used
to carry is lost. DCWF declares role-, Cyber.org K-12
declares cell-.
| Framework | Unit IRI | Statement IRI |
|---|---|---|
| DCWF v5.1 | dcwf:role-462 |
dcwf:462 |
| Cyber.org K-12 | cyberorg:cell-K-2.SEC.AUTH |
cyberorg:K-2.SEC.AUTH |
Three properties of the rule matter more than the rule itself.
It is one-sided. Statement IRIs do not move. They are the codes people cite, there are 13,962 of them (parent statements, strict count), and a framework’s own numbering is what a reader looks up.
It is declared, not inferred. A framework with no
unit_iri_prefix mints the IRIs it has always minted, so the
other nine frameworks’ graphs are byte-identical to what they were
before the rule existed. build_organizing_unit_node() and
build_role_node() take unit_iri_prefix as an
optional argument that defaults to no discriminator, so a framework of
your own is unaffected unless you ask for it.
It is enforced. assert_graph_identity() fails the build
if any IRI is typed both cybed:OrganizingUnit and
cybed:RoleElement, or if any cybed:hasElement
triple points at its own subject. There is no exemption list. A
framework that would need one needs a unit_iri_prefix
instead.
The national frameworks added after the package’s original release
mint their Tier 2 terms under
https://w3id.org/cybed/framework/<slug># rather than
under the steward’s own domain. The rest sit under a namespace derived
from the publisher’s site. The difference is deliberate. A term like
otccf:JobRole is a type cybedtools coined to describe what
CSA published, and it is not an identifier CSA issued. Putting it under
the package’s own namespace keeps that distinction visible in the URI
itself, so nobody reading the graph mistakes a package-coined subtype
for the steward’s vocabulary.
Example JSON-LD documents
A workforce framework parent (NICE work role) carries
cybed:Role and cybed:OrganizingUnit:
{
"@context": {
"schema": "http://schema.org/",
"skos": "http://www.w3.org/2004/02/skos/core#",
"cybed": "https://w3id.org/cybed/ontology#",
"nice": "https://nice.nist.gov/framework/terms#"
},
"@graph": [
{
"@id": "nice:OG-WRL-015",
"@type": ["nice:WorkRole", "cybed:Role", "cybed:OrganizingUnit"],
"schema:name": "Technology Portfolio Management",
"cybed:partOf": { "@id": "cybed:framework/nice-v2" },
"cybed:hasElement": [
{ "@id": "nice:OG-WRL-015-T01" }
]
},
{
"@id": "nice:OG-WRL-015-T01",
"@type": ["nice:TaskStatement", "cybed:RoleElement"],
"cybed:elementText": "Evaluate the strategic alignment of emerging technologies..."
}
]
}A non-workforce framework parent (Cyber.org K-12 grade-band x
sub-concept cell) carries cybed:OrganizingUnit only, and
its standard’s Clarification examples are typed
cybed:Example linked via cybed:hasExample.
This is also a framework that declares a unit_iri_prefix,
so the cell’s IRI carries cell- and its printed code sits
on schema:identifier:
{
"@context": {
"schema": "http://schema.org/",
"cybed": "https://w3id.org/cybed/ontology#",
"cyberorg": "https://cyber.org/standards/terms#"
},
"@graph": [
{
"@id": "cyberorg:cell-K-2.SEC.AUTH",
"@type": ["cyberorg:StandardGroup", "cybed:OrganizingUnit"],
"schema:name": "K-2 / Secure Computing / Authentication",
"schema:identifier": "K-2.SEC.AUTH",
"cybed:hasElement": [{ "@id": "cyberorg:K-2.SEC.AUTH.1" }]
},
{
"@id": "cyberorg:K-2.SEC.AUTH.1",
"@type": ["cyberorg:Standard", "cybed:RoleElement"],
"cybed:elementText": "Describe a good password. Clarification statement: ...",
"cybed:hasExample": [
{ "@id": "cyberorg:K-2.SEC.AUTH.1.example.1" },
{ "@id": "cyberorg:K-2.SEC.AUTH.1.example.2" }
]
},
{
"@id": "cyberorg:K-2.SEC.AUTH.1.example.1",
"@type": ["cybed:Example", "cybed:RoleElement"],
"cybed:elementText": "not using common words as passwords"
}
]
}The Example node deliberately carries no
cyberorg:Standard typing and is not in any organizing
unit’s cybed:hasElement. It is reachable only via the
parent standard’s cybed:hasExample, matching the
framework’s own treatment of Clarification examples as teacher-facing
scaffolding rather than enumerable sub-standards.