Sensemaking AI · Sensemaking Semantic Web
Submodule 2.3 · Modeling

Ontology design practice.

Design methodology, documented decisions, SHACL for closed-world validation, and REUSE.md practice. This is the primary project submodule — Exercise 2.3 produces naruto-ontology-1.0.0.ttl.

Module 2 · Weeks 4–6 Primary project: Exercise 2.3 ~3 hours concepts + 8–12 hours exercise design · SHACL · REUSE.md · Naruto
Checking for Fuseki at localhost:3030…

Scope, reuse, define, constrain — in that order.

Ontology design is creative work with real consequences. A premature restriction is a future bug. An undefined property is a future interoperability gap. A class hierarchy that does not match the domain's actual categorical structure will produce wrong inferences. The redos are inevitable — the methodology is how you minimize them.

Work through four phases in order:

The Naruto ontology starter file (Submodules 2.1 and 2.2) represents the output of the first three phases. Exercise 2.3 completes the fourth — adding restrictions and SHACL shapes after working with the Chunin Exams arc data and confirming which constraints actually hold.

The redos are the work

The Module 2 README says: "Expect to redo the class hierarchy at least twice." This is not a warning — it is calibration. The first hierarchy feels obvious. The second one emerges after you hit a modeling wall (Sage Mode: is it a Jutsu subclass or an instance?). The third one is the one that actually works. Most published ontologies represent the third or fourth version. The deleted versions are what built the judgment.

Every non-obvious choice has a reason.

The starter ontology's comments document each significant decision. Three decisions worth understanding before extending the ontology in Exercise 2.3:

Decision 1

NinjaRank uses SKOS, not OWL classes.

The ranks (Genin, Chunin, Jonin, Kage) look like candidates for an OWL class hierarchy: Kage is "above" Jonin, Jonin is "above" Chunin. But "above" here is an organizational position in a classification scheme — not a logical superclass relationship. A Kage is not a "superkind of Jonin" in the sense that every Kage is also a Jonin. SKOS broader/narrower is the right relationship for ordered vocabulary concepts. Using OWL subClassOf would imply that every Kage individual is also a Jonin individual — which a reasoner would accept and which is semantically wrong.

This is the SKOS-vs-OWL distinction from Submodule 1.3, applied to a real domain choice.

Decision 2

Arc is a subclass of schema:CreativeWork, not schema:Event.

An arc is a narrative unit — it has chapters, episodes, a publication span, and a story structure. schema:Event implies a location, an organizer, and an attendance pattern. An arc has none of these. schema:CreativeWork is a better fit: it covers works that are published, have a name, and can be part of a series. The tension: the Chunin Exams arc is also an event within the fiction. That event aspect — if it becomes important for the ontology — could be modeled as a separate schema:Event node linked from the arc, rather than merging the two concepts.

Decision 3

familyOf is symmetric but deliberately not transitive.

Family relationships are symmetric (if Naruto is family of Kushina, Kushina is family of Naruto). But they are not transitively closed in the useful sense: familyOf is used here to capture direct family ties, not an arbitrary transitive closure that would make all Uzumaki clan members "family of" each other through a long chain. Transitivity on familyOf would be semantically wrong (it would infer that Naruto's parents' teachers are his family) and computationally expensive on any realistically populated dataset. The comment in the starter TTL documents this explicitly — future contributors should not add transitivity without reading this reasoning.

The open design question: rank changes over time

Gaara becomes Kazekage (Kage-rank) after the Chunin Exams arc. The starter ontology has a single naruto:hasRank naruto:Genin triple for Gaara — his rank at the time of the Chunin Exams arc. Modeling rank changes across arcs requires either:

The starter ontology chooses the third option and documents it. Exercise 2.3 asks you to decide whether to extend to the time-indexed pattern or retain the documented simplification.

The closed-world answer.

OWL operates under the open-world assumption: missing data is absent, not false. This is epistemically honest but frustrating for applications that need to enforce data completeness. SHACL (Shapes Constraint Language) provides closed-world validation: a SHACL shape defines what a conforming node must look like, and any node that violates the shape is flagged as an error — not merely left to a reasoner's open-world inference.

The distinction in practice:

# A basic SHACL shape for naruto:Ninja
# Goes in artifacts/naruto-ontology/shapes/ninja-shape.ttl
@prefix sh:     <http://www.w3.org/ns/shacl#> .
@prefix naruto: <https://sensemaking-ai.com/ns/naruto#> .
@prefix xsd:    <http://www.w3.org/2001/XMLSchema#> .

naruto:NinjaShape
    a sh:NodeShape ;
    sh:targetClass naruto:Ninja ;
    sh:property [
        sh:path     naruto:canonicalName ;
        sh:datatype xsd:string ;
        sh:minCount 1 ;
        sh:maxCount 1 ;
        sh:message  "A Ninja must have exactly one canonicalName."
    ] ;
    sh:property [
        sh:path     naruto:memberOfVillage ;
        sh:class    naruto:Village ;
        sh:minCount 1 ;
        sh:message  "A Ninja must belong to at least one Village."
    ] .

SHACL shapes live in the shapes/ subdirectory of the naruto ontology artifacts. They are separate from the OWL ontology — a deliberate design: the ontology states what things are; shapes state what data must look like for applications to function correctly.

SHACL and the open-world assumption

SHACL does not change OWL's open-world assumption. The OWL ontology still reasons with OWA; the SHACL validator still reports a violation for missing data. They serve different purposes and can coexist. A production system might use the OWL ontology for inference (computing what follows from the data) and SHACL for data ingestion validation (refusing to load records that violate the shapes). This is the Module 3.3 territory — the full SHACL story lands there.

Document every vocabulary decision.

The Module 2 README requires a REUSE.md file in the naruto ontology artifacts folder. Here is what it should cover and why:

VocabularyTerms usedWhy this vocabulary, not a custom term
schema:schema:Person, schema:Organization, schema:CollegeOrUniversity, schema:CreativeWork, schema:TVEpisode, schema:name, schema:aboutBroad interoperability; search-engine readable; no semantic web tool needs to be told what schema:Person means.
skos:skos:Concept, skos:ConceptScheme, skos:prefLabel, skos:broader, skos:notation, skos:inSchemeNinjaRank is a controlled vocabulary, not a class hierarchy. SKOS is the standard for this distinction. Module 1.3 established why.
foaf:None in starter — schema:Person used insteadschema:Person is more permissive for fictional characters; FOAF's "person" connotation is weaker here.
dcterms:dcterms:title, dcterms:description, dcterms:created, dcterms:creatorDocument metadata on the ontology header node.
owl:owl:Ontology, owl:Class, owl:ObjectProperty, owl:DatatypeProperty, owl:SymmetricProperty, owl:inverseOf, owl:NamedIndividualStandard OWL vocabulary — required for OWL-aware reasoners to interpret the ontology correctly.
naruto:naruto:Ninja, naruto:Character, naruto:Village, naruto:Team, naruto:Jutsu, naruto:Arc, naruto:senseiOf, naruto:studentOf, naruto:memberOfTeam, naruto:memberOfVillage, naruto:hasJutsu, naruto:rivalOf, naruto:familyOf, naruto:hasRank, naruto:appearsInArc, naruto:canonicalName, naruto:villageCodeDomain-specific; no standard vocabulary covers these Naruto-specific concepts.

REUSE.md is the ontologist's equivalent of a license file — it makes your decisions legible to anyone who extends, imports, or critiques the ontology. Write it as you work, not after. The starter TTL's inline comments are the working notes that REUSE.md formalizes.

Extend the starter into a releasable ontology.

This walkthrough takes the starter ontology toward the 1.0.0 release. These steps are more open-ended than the 2.1 and 2.2 walkthroughs — they ask for design judgment, not just execution. There are no uniquely correct answers.

Design exercise — open to expand all steps
1 Add the time-indexed rank decision expand

Open the starter ontology in Protégé. The current naruto:hasRank is a flat functional property. Consider whether to extend it to a time-indexed pattern.

Option A (keep simple): Document the scope limitation in the ontology header — rdfs:comment "hasRank reflects rank at the primary canonical point for each arc. Rank changes across arcs are not modeled in v1.0."

Option B (time-indexed): Add a new class naruto:RankHolding with properties naruto:duringArc, naruto:rank, and naruto:holder. Replace hasRank with naruto:hasRankHolding pointing to a RankHolding individual.

Choose one option and implement it. Document your reasoning in the ontology comment.

Screenshot: Classes tab showing your chosen implementation — either the annotated hasRank property (Option A) or the new RankHolding class with its properties (Option B).
2 Add OWL restrictions for Ninja and Team expand

In the Classes tab, add these restrictions from the Module 2 README:

  1. On naruto:Ninja: memberOfVillage some naruto:Village (a Ninja must belong to at least one Village)
  2. On naruto:Team: inverse(memberOfTeam) some naruto:Ninja (a Team must have at least one Ninja member)

Run HermiT. If the ontology becomes inconsistent, check the data — do all Ninja individuals in the starter have memberOfVillage? Do all Team individuals have at least one member?

Screenshot: Classes tab, naruto:Ninja selected, Description panel showing the new restriction "naruto:memberOfVillage some naruto:Village" in the SubClass Of section. Reasoner status bar shows Synchronized.
3 Write SHACL shapes in a text editor expand

Protégé does not have native SHACL editing. Open a text editor and write shapes/ninja-shape.ttl using the template from Section 3 of this submodule. Extend it with:

  1. A shape for naruto:Arc requiring at least one schema:name with language tag @en
  2. A shape for naruto:Jutsu requiring at least one schema:name
  3. An optional property path constraint on naruto:NinjaShape that checks naruto:hasRank values are in the naruto:NinjaRankScheme concept scheme
Screenshot: Text editor showing the completed ninja-shape.ttl with at least the NinjaShape, ArcShape, and JutsuShape NodeShape declarations.
4 Validate the starter data against your SHACL shapes expand

Use Apache Jena's shacl command from the terminal (included with Jena 4.x):

shacl validate \
  --shapes shapes/ninja-shape.ttl \
  --data naruto-ontology-starter.ttl

Review the validation report. For each violation:

  1. Determine whether the shape is wrong (too strict) or the data is wrong (missing required triples).
  2. If the data is missing, add the missing triples to the starter TTL.
  3. If the shape is too strict, weaken it with a comment documenting why.
Screenshot: Terminal output showing the SHACL validation report — either "Conforms: true" (no violations) or a list of violation messages with source shape and focus node.
5 Save as naruto-ontology-1.0.0.ttl and write the README expand

Save the finalized ontology as naruto-ontology-1.0.0.ttl. Update the owl:versionInfo from "starter" to "1.0.0". Add owl:priorVersion pointing to a URI for the starter if desired.

Write the module artifact README at artifacts/naruto-ontology/README.md, covering: scope statement, class hierarchy description, key design decisions (the three from Section 2 of this submodule plus any you added), external vocabulary usage summary, link to REUSE.md, WebVOWL screenshot instructions.

Screenshot: The naruto-ontology-1.0.0.ttl file open in a text editor, showing the updated owl:versionInfo "1.0.0" and the ontology header with the new restrictions visible in the Ninja class definition.

Five queries that justify building the ontology.

These queries run against the starter ontology in Fuseki. They demonstrate what the ontology makes possible that the plain co-appearance graph from the Naruto Network Graph does not support directly.

q01
Who are the "grand-students" of Team 7's sensei — via two senseiOf hops?
Pattern: property path · / chain · multi-hop mentorship traversal
Open Fuseki ↗
PREFIX naruto: <https://sensemaking-ai.com/ns/naruto#>

SELECT ?ancestorName ?grandstudentName WHERE {
  ?ancestor naruto:senseiOf/naruto:senseiOf ?grandstudent .
  ?ancestor  naruto:canonicalName ?ancestorName .
  ?grandstudent naruto:canonicalName ?grandstudentName .
}
ORDER BY ?ancestorName ?grandstudentName
q02
For each arc, how many ninja from each village appear?
Pattern: GROUP BY arc + village · COUNT · cross-referencing arc, ninja, and village class properties
Open Fuseki ↗
PREFIX rdfs:   <http://www.w3.org/2000/01/rdf-schema#>
PREFIX schema: <https://schema.org/>
PREFIX naruto: <https://sensemaking-ai.com/ns/naruto#>

SELECT ?arcName ?villageName (COUNT(?ninja) AS ?ninjaCount) WHERE {
  ?ninja a naruto:Ninja ;
         naruto:memberOfVillage ?village ;
         naruto:appearsInArc    ?arc .
  ?arc     schema:name ?arcName .
  ?village rdfs:label  ?villageName .
  FILTER (LANG(?arcName)     = "en")
  FILTER (LANG(?villageName) = "en")
}
GROUP BY ?arcName ?villageName
ORDER BY ?arcName DESC(?ninjaCount)
q03
Which rival pairs are from different villages?
Pattern: join on rivalOf + memberOfVillage · FILTER for cross-village · value-add over co-appearance
Open Fuseki ↗
PREFIX rdfs:   <http://www.w3.org/2000/01/rdf-schema#>
PREFIX naruto: <https://sensemaking-ai.com/ns/naruto#>

SELECT DISTINCT ?nameA ?villageA ?nameB ?villageB WHERE {
  ?a naruto:rivalOf          ?b ;
     naruto:canonicalName    ?nameA ;
     naruto:memberOfVillage  ?vA .
  ?b naruto:canonicalName    ?nameB ;
     naruto:memberOfVillage  ?vB .
  ?vA rdfs:label ?villageA .
  ?vB rdfs:label ?villageB .
  FILTER (?vA != ?vB)
  FILTER (STR(?a) < STR(?b))
}
ORDER BY ?nameA
q04
For each ninja, which jutsu are they the only one to use?
Pattern: GROUP BY · HAVING COUNT = 1 · "unique skill" query
Open Fuseki ↗
PREFIX schema: <https://schema.org/>
PREFIX naruto: <https://sensemaking-ai.com/ns/naruto#>

SELECT ?ninjaName ?jutsuName WHERE {
  ?ninja naruto:hasJutsu      ?jutsu ;
         naruto:canonicalName ?ninjaName .
  ?jutsu schema:name          ?jutsuName .
  FILTER (LANG(?jutsuName) = "en")
  FILTER NOT EXISTS {
    ?other naruto:hasJutsu ?jutsu .
    FILTER (?other != ?ninja)
  }
}
ORDER BY ?ninjaName
q05
CONSTRUCT: build a village-to-village "conflict" graph from shared arc + different village pairs.
Pattern: CONSTRUCT · derived relationship · from schema properties to new graph structure
Open Fuseki ↗
PREFIX naruto: <https://sensemaking-ai.com/ns/naruto#>

CONSTRUCT {
  ?vA naruto:sharedArcWith ?vB .
}
WHERE {
  ?a naruto:memberOfVillage ?vA ;
     naruto:appearsInArc    ?arc .
  ?b naruto:memberOfVillage ?vB ;
     naruto:appearsInArc    ?arc .
  FILTER (?vA != ?vB)
  FILTER (STR(?vA) < STR(?vB))
}

Now build the 1.0.0 release.

Exercise 2.3 is the primary project for Module 2. The deliverable is naruto-ontology-1.0.0.ttl with a populated example dataset, SHACL shapes, REUSE.md, and query demonstrations. The five queries in this submodule's query lab are the "example queries that demonstrate value-add" the Module 2 README requires.

Minimum viable 1.0.0 checklist

OWL class hierarchy complete and consistent under HermiT · At least two OWL restrictions (Ninja has Village, Team has member) · SHACL shapes for Ninja, Arc, Jutsu · REUSE.md documenting all vocabulary decisions · One populated example data file (the Chunin Exams arc subset) · Five SPARQL queries committed to queries/ · README with scope statement and design decisions · WebVOWL visualization captured (see resources for the tool link).

The "redo" expectation

The Module 2 README says to expect at least two full redos of the class hierarchy. If you are redoing for the third time, that is normal — not a sign of failure. Document the failed approaches in the ontology README under a "Design decisions considered and rejected" section. The wrong turns are part of the published artifact.

When the ontology is published and validated, take the artifact test: can the five query lab queries in this submodule run against your 1.0.0 release and return results that demonstrate value the plain co-appearance graph cannot provide? If yes, modeling landed. Move to Module 3.

Reading, tools, and examples.

Primary reading

Allemang et al. — Ch 8

Modeling patterns: N-ary relations, time-indexed situations, information realization. The chapter that answers the rank-change and RankHolding design question concretely.

OWL Primer

W3C OWL 2 Primer

Read Section 7 (Advanced OWL) after completing the design exercise. The n-ary relation and punning sections are directly relevant to decisions made in the Naruto ontology.

SHACL

W3C SHACL spec

The abstract and Section 2 (Shapes and Constraints) are the relevant entry point. Full coverage of SHACL Advanced Features is Submodule 3.3 territory.

Ontology patterns

ODP portal

Patterns: Time-Indexed Situation (for rank changes), N-ary Relation (for relationships with attributes), Information Realization (for the arc-as-creative-work model). Read at least two before finalizing 1.0.0.

Visualization

WebVOWL

Upload your TTL file and capture the class hierarchy visualization. Required artifact for the 1.0.0 README. The visualization makes it easy to spot structural problems — a class with no properties is a red flag.

Cheatsheet

Module 2 RDFS / OWL quick-reference (coming soon)

RDFS and OWL term quick reference with Naruto examples — what each term asserts, what a reasoner derives, and when to use each. Available when Module 2 materials are complete.