The Semantic Layer, From ScratchCorrections log
Afterword

Corrections log

What a reader flagged while working through the build, and what changed.

This book is read by a real person. Vinodh reads it chapter by chapter and does every build step himself in Stardog Studio and DBeaver. Whenever a passage confuses him, or Studio shows something different from the page, he says so, and the passage is fixed in place in the same session. This page records those fixes.

Each entry gives the date, the part of the book, what the reader flagged, and what changed. Entries are grouped by chapter in reading order, newest first within each chapter. Small typo and wording fixes are not listed one by one.

93 corrections so far, from September 23 to October 4, 2026. Chapters after 10 have not been read closely yet, so their entries will come later.

The whole book

DateWhereWhat the reader flaggedWhat changed
Key idea callouts, Chapters 1 to 9, and a new summary pageIdeas like “a shared variable is a join” are easy to forget, and the reader asked for them to stand out so he could find them again later.Each chapter from 1 to 9 now has gold “Key idea” callouts, and the new Key ideas at a glance page collects them, each with a link back to where it is taught.
Contents page, time per chapterThe reader asked for an estimated time for each chapter on the contents page, and later for the times to be rounded to whole quarter hours.The contents table has a Time column split into reading and hands-on minutes, plus a total for the book. Each time is rounded up to the next 15 minutes.
Every page, the ☰ chapter menuThe reader wanted to jump to any chapter without going back to the contents page.Every page now has a ☰ button at the top left that opens a list of all chapters.
End of every chapterThe reader did not see why he should paste a “Chapter N done” message after every chapter, since he already asks questions as soon as something is unclear.Reading chapters no longer have the button. Build chapters have a “Build step N done” button instead, used only to confirm results before the next build step relies on them.

Preface

DateWhereWhat the reader flaggedWhat changed
“You'll see ‘like a JOIN’ a lot” paragraphThe sentence “this world assumes what isn't stated might still be true” was too abstract to follow.It now uses one example: there is no phone number for Carolyn. A database reads that as “she has no phone”; a graph reads it as “we don't know her phone”.
Technology table, OWL rowThe reader asked what R2RML stands for, and could not make sense of the example that called :hasRewards the reverse of :rewardsAccountUsed.That example was wrong. It now uses a correct pair: :purchasedBy links an order to a customer, and :placedOrder is the same link read the other way. R2RML is spelled out at first use.
Technology table, RDFS rowThe reader put it in his own words: SQL splits DDL and DML, and you read the shape with DESCRIBE, but in RDF the shape is just more triples you can SELECT.The RDFS row was rewritten around that comparison.
Technology table, “Why it exists” columnThe reasons assumed the reader already knew the answer, for example “one shape for all data, so facts combine without reconciling schemas”.All ten rows were rewritten. Each now starts from a problem a database engineer already knows, then says how the technology solves it.
“Think of Stardog as a shared view layer” paragraphThe reader summed up the idea in one line of his own and asked for it to be added.The paragraph now ends: “an ETL-free business view over many databases, where the ontology supplies the meaning and the mappings supply the connections.”

Chapter 1 · One question, five systems

DateWhereWhat the reader flaggedWhat changed
1.3 What a semantic layer isThe reader asked whether a semantic layer and a knowledge graph are the same thing, and what other ways there are to build a semantic layer.The definition now separates the job (a semantic layer) from one technology that can do it (a knowledge graph). A new part, “Other ways to build a semantic layer”, compares the main approaches.

Chapter 2 · The triple: the atom of knowledge

DateWhereWhat the reader flaggedWhat changed
Note under the first INSERT DATAThe reader asked whether urn: means a thing and tag: means a property, which seemed to clash with “anything in angle brackets is a thing”.A note now says: everything in angle brackets is a thing; urn: and tag: are only naming formats; a name's role comes from its position in the triple. The first wording read like a contradiction, so it was reworded the same day.
Terms table, “Variable”The table called a variable a “blank”, and the reader asked where the blank was when all he could see was a question mark and a name.A variable is now described as a placeholder name for a value you don't know yet, with two real lines of data and the value Stardog fills in (?city = “Milwaukee”).
“Three table shapes you know” boxThe sentence about child tables and join tables made the reader picture the tables in his head instead of showing them.Each case now shows real rows and the exact triples they become.

Chapter 3 · Names, values and files

DateWhereWhat the reader flaggedWhat changed
3.5 and Key ideas, Turtle punctuationWhile reading Chapter 11's Turtle sample, the reader had forgotten what ; and . mean.Added a key idea where Chapter 3 introduces them, and to the Key ideas summary: ; same subject next predicate, . done with this subject, , another object, with a written-out example and the SQL row/column comparison.
Loading the practice fileThe reader could not see where to enter the named graph in Studio's Load Data dialog, so his first load went into the default graph.The step now points to the “Search or create…” box in the graph drop-down, where you type the new graph name.
Chapter opening, the “two cents” storyThe opening described a federated query “the first time it ran”, which the reader had never seen. A preview of Chapter 9 also broke the flow of Chapter 3.The opening now stands on its own: write 502,529.42 once as a decimal and once as a float, read both back, and see the float come back wrong. Other references to an earlier, unseen build were removed across the book.

Chapter 4 · SPARQL for people who know SQL

DateWhereWhat the reader flaggedWhat changed
Step 1, loading the practice dataLoading the practice file with Load Data failed with Expected ':', found ' '.A note now explains that this file is a SPARQL update, not a Turtle file: paste it into the Workspace and press Run. A small table shows how to tell the two apart.

Chapter 5 · The T-Box, part 1: classes (RDFS)

DateWhereWhat the reader flaggedWhat changed
5.4, the word “axiom”“Axiom” was used from Chapter 5 to Chapter 13 and never explained.5.4 now defines it right after the first subclass triple, with a subclass and an inverse example, and the glossary has an entry.
Introducing schema.ttl (also Chapter 6)The reader asked for a direct link to the kit's ontology file, since the kit is public.schema.ttl now links straight to the file on GitHub.
5.2 OWL paragraphWords like “reverse”, “overlap” and “same thing” were abstract as written.The list became a table of three worked examples from the c360 data, each showing what you write and what you gain.

Chapter 6 · The T-Box, part 2: properties and the c360 ontology (OWL)

DateWhereWhat the reader flaggedWhat changed
Build step 2, Check 3The expected counts said 11 relationships and 22 attributes, and the reader asked which properties those words meant.Check 3 now says that a relationship is an object property (like :purchasedBy) and an attribute is a datatype property (like :firstName).
The reasoner paragraphThe text said the reasoner's “default level SL” without ever explaining it.It now says in plain words that you can choose how much of OWL the reasoner applies, that the default (SL) covers everything in this book, and that you never need to change it.
“Why this matters” boxPhrases like “inference rules that re-type things are a liability” were big words for a simple point.The box now uses one example: if a bad row ever gives Wax Paper a :purchasedBy value, rdfs:domain would label Wax Paper an Order in every answer; with so:domainIncludes the bad row stays just a bad row.
The so: documentation paragraphThe discussion was about :name, and the paragraph suddenly switched to :email.The paragraph keeps the :name example throughout.
6.4 owl:inverseOfThe reader asked how to read the :rewardsAccountUsed and :hasRewards pair with a real order and account.Explained with a real triple and the triple Stardog concludes from it, with no formula.
6.2 rdfs:domain and rdfs:rangeThe reader asked for domain and range to be explained the way they were explained to him in conversation, not with placeholder formulas.Rewritten in plain words: one real triple, and what Stardog concludes from it on the left and right side.
Loading the kit files (also Chapter 10)The load steps pointed to a folder on the author's machine that a reader would not have.The steps now download the kit files from GitHub.
Why the kit uses so: instead of rdfs:The text promised to explain why the kit uses so:, then never said where.It now says what so: is (schema.org) and points straight to sections 6.2 and 6.3.
Chapter opening on rdfs:domainThe opening riddle compared the problem to a foreign-key error, which added more to think about instead of less.The opening now says directly what rdfs:domain does, without the foreign-key comparison.

Chapter 7 · Where the data lives: materialized vs virtual

DateWhereWhat the reader flaggedWhat changed
Materialized vs virtual boxThe comparison was shown in Java, and the reader suggested SQL would say it better.The box now compares CREATE MATERIALIZED VIEW with CREATE VIEW, using a real query on the c360 tables.

Chapter 8 · Mappings: teaching Stardog to read your tables

DateWhereWhat the reader flaggedWhat changed
Reading a query plan (also Chapter 9)The reader's Studio showed different plan controls from the ones the book described.The text now describes Studio's real controls (the plan tree icon and Run Profiler) and notes that Studio returns at most 1000 rows by default.
New section 8.9, how it worksWhile reading Chapter 9, the reader asked whether separate mapping blocks really end up as one SQL query, and said Chapter 8 should explain this.New section 8.9 shows the real plan for the Wisconsin query: small mappings in, one SQL query with joins out.
The command-line boxThe reader asked what the curl and jq box was for, since the book does every step in Studio.It is now labelled as optional automation that you can skip. A leftover reference to “the working build” was also removed.
Create Virtual Graph steps (also Chapters 9 and 16)The reader's screenshots showed that Studio's Create Virtual Graph form did not match the steps.The steps now follow the real form: upload the mapping file, and untick Auto-generate mapping.
8.4, the .sms fileThe reader asked what “.sms” means.It is now explained at first use: a mapping file written in Stardog's SMS2 mapping language.
8.4, the safe and PII graphsaurora_c360_safe was used before the book said what “safe” meant.Both graphs are introduced at first mention: the safe graph leaves out SSNs and card numbers, and the PII graph holds only those.
Reading a template backwardsThe reader asked what “building 500 IRIs” referred to.Explained as a slow way and a fast way: build an IRI for every customer and compare text, or strip the fixed prefix and send WHERE cid = 225 to the database.
Where the join happensThe reader asked how customers get joined to addresses when no mapping contains a JOIN.New text: mappings never join. Two mappings that build the same IRI produce the same node, and Stardog writes the SQL join at query time.
Figure in 8.3Reading the TO block, the reader asked where ?loc_iri comes from.The figure was missing the BIND that builds ?loc_iri. It was added.
8.3, the order a mapping runs inThe FROM SQL block made sense, but the TO and WHERE blocks did not.New text: a mapping is written FROM SQL, TO, WHERE but runs FROM SQL, WHERE, TO, followed with one real row and a SQL equivalent.
8.1 What a mapping isThe section talked about FROM SQL, TO and WHERE before showing any mapping.A tiny real mapping now comes first.

Chapter 9 · Federation: where the magic happens

DateWhereWhat the reader flaggedWhat changed
9.7, where the rows landThe reader asked where the rows go inside Stardog, and why the SUM in the 9.5 query cannot be done inside Redshift.New text with real rows: rows stream into Stardog's memory for the life of the query and nothing is stored. The SUM is grouped by name and state, which only Aurora has, so it has to wait for the join.
The different-template bugThe reader did not follow “if Redshift minted urn:c360:buyer:{cid}” and asked for an example.A concrete example now shows one side calling her a customer and the other a buyer: the IRIs never match, and the query returns 0 rows with no error.
Cost paragraphThe reader found the paragraph about cloud cost per query off topic for this chapter.Removed.
9.7, the proof tableThe reader asked how many rows each version of the query brings into Stardog, whether LIMIT can be pushed down, and wanted the comparison in the book.9.7 now has a table comparing three versions with the real SQL each one sends, plus a third option and the safety nets it needs.
Build step, the Redshift mappingThe reader's Redshift graph returned nothing: his mapping file was missing its prefix lines.The build step warns about this and lists the symptoms: predicates under api.stardog.com and an empty plan.
“Step 10 by hand” Java boxThe reader asked for the hand-written Java version of the federated query to be removed.Removed.
Figure 9.2The numbers in the figure read like counts, not step numbers.Each step now has a circled badge and a “Step N:” caption.
“Stardog operators above the SQL leaves”The reader asked what this phrase means.Explained in plain words with a small plan tree: what one database can answer is sent to it as SQL, and only the cross-database work is done in Stardog. A stray tag was fixed too.
Calcite and the “not found within c360” errorThe reader asked to be reminded why that Chapter 7 error happened.The text now says plainly what caused it and what the plan operators are.
Product, category and vendor mappingsThe text discussed these blocks before the reader had seen them.The blocks are now shown before they are discussed.
Vendors by name, percent-encoding, list priceThe reader asked whether percent-encoding was something he had to worry about, and what the vendor and float details meant.Explained with real rows, for example how the brand Charmin Ultra Soft becomes vendor:Charmin%20Ultra%20Soft in both mappings.
Where the cross-database join comes fromThe text quoted “the Redshift DDL's comment”, and the reader asked where that comment was.The point is now stated directly: the join comes from the shared IRI template, not from a foreign key.
How Stardog finds the right mappingThe passage talked about a “routing table”, Voicebox and Trino, none of which the reader had met yet. A note on the T-Box was also fuzzy.Rewritten using only what the reader had built: the query for :name and :hasRewards was answered from the customer and rewards blocks. The fuzzy note was dropped.

Chapter 10 · Reasoning: teaching the graph to conclude

DateWhereWhat the reader flaggedWhat changed
10.8, last line“Saying no is the next chapter's job” points at something not yet explained.Removed; the section now ends at “Reasoning only adds conclusions.”
10.5, after Figure 10.2The reader ran the profiler on the reasoning query and asked how reasoning had changed it.Added “The proof: what the profiler shows”: the real plan (one SQL statement per database, WHERE "price" > 250 in Redshift) and a table tracing each pattern, written or added by a rule, to what actually ran. The “treat as a mental model” hedge now points to this proof.
Build step 5, sub-step 6, timingThe reader measured the reasoning query: 51.6 s on the first run, 355 ms on the second.The sub-step now shows these measured times instead of guessing why the first run is slow: it is almost all wake-up time.
10.6 and build step 5, sub-step 6The book only said the schema picker “sits by the toggle”; the reader found it is the gear icon, and his first reasoning run took 51.6 seconds against a 60-second timeout.10.6 now gives the exact clicks (Reasoning toggle on, gear icon → Reasoning Schema → c360_extended_rules); sub-step 6 warns about the slow first run and where to raise the timeout.
10.7, build step 5, the Models screenWhere to see the rules in Studio, and why the Overview picture is empty for c360_schema but not for c360_extended_rules.Added what the Models screen shows: Overview draws only subclass links (0 in Chapter 6's schema; 7 nodes and 5 edges in the extended one), no Rules tab (use Text Editor), and the Text Editor's prefixes come from the database.
10.7, build step 5, loading the two kit filesWhat “Load Data To” actually means, and why the model file goes into a graph named “…extended_rules…”.Added a table of real stored triples showing the graph as a fourth column, and why both files share one graph (one reasoning-schema entry); the name is only a label.
10.5, the reasoning cost noteThe text warned about a “1 RPU-hour daily cap” without ever saying what an RPU is or where the cap came from.The note is now a Gotcha box that defines RPU and RPU-hour, explains the 60-second minimum and the daily usage limit (15 minutes at 4 RPUs), and says why reasoning can send more SQL.
10.5, “Reasoning is like a JPA Specification” Java boxThe reader asked for this box to be removed.Removed.
10.3, the prefix puzzleThe section explained prefix traps in a rules file the reader had not opened yet, and used the term “local part” without ever defining it.10.3 now starts from the Chapter 9 missing-prefix bug and expands both spellings side by side in a table that defines the local part. The two traps moved to build step 5, where the file is open.
10.3, the kit's rules fileThe text quoted c360_extended_rules.ttl as if the reader knew where that file was.The kit's model and rules files are now introduced, with GitHub links, before they are quoted.
“A rule is a derived getter” Java boxThe reader asked for this box to be removed.Removed.
Chapter openingThe opening described a “before” world the reader had already left: after Chapter 9 he could answer the question with one federated query.The opening now starts from that federated query, with the rule written inline, and shows what is still missing: a definition of “big spender” written once and reused everywhere.

Chapter 11 · SHACL: when you do want rules to reject data

DateWhereWhat the reader flaggedWhat changed
11.8 and the recap, “canary”The coal-mine “canary” is trivia the reader shouldn't need to know.Replaced everywhere with the plain term “must-fail check” (the shape is now :MustFailShape), and removed a stray “tell Claude” from the stretch.
11.8, optional stretch“Canary” was used without being explained.Added one line: a canary is a check that must fail, so if it passes, the checking itself is broken.
11.8, “Same shape of call in both worlds” Java boxThe reader asked for this box to be removed.Removed.
11.8, reading a validation reportWhere sh:conforms false comes from (a setting?), and what the report looks like once the data is fixed.Added a before/after pair: false with three sh:result entries vs true alone, plus: passing nodes never appear, and nothing but fixing the data makes it true.
11.7, triple count after the INSERTThe reader counted 67 triples where the book said 17.The book's 17 was wrong: the INSERT stores 19 (now itemised). The 67 came from Studio's Reasoning toggle still being on; the step now says to count with reasoning off and explains the 48 inferred owl:Thing facts.
11.5, where shapes liveThe paragraph on shacl.shape.graphs and VALIDATE ALL made no sense.Rewritten as a two-row table (VALIDATE ALL uses shapes from every stored graph; USING SHAPES GRAPH uses only the one you name), with a dbt test comparison and the concrete risk of a forgotten scratch shapes graph.
11.6, where SHACL fits in a federated setup“A SHACL report shows them in the business vocabulary” was unclear, and the bullets read as if SHACL can't help with upstream data.Upstream problems: SHACL finds them but can't fix or block them, shown with customer 225's NULL email as SQL sees it vs as the report says it. Mapping mistakes now use Chapter 9's buyer-vs-customer template bug as the example.
11.3, “A shape is Jakarta Bean Validation” Java boxThe reader asked for this box to be removed.Removed.

Chapter 12 · Governance: same question, different answers

DateWhereWhat the reader flaggedWhat changed
12.2 and build step 6 (steps 1, 2, 5, 7 and the gotcha)After turning on named-graph security, step 1 returned nothing, where the book promised “unchanged”.Tested and corrected: once named-graph security is on, even the cloud role and the reader role (named-graph *) see no graphs; Studio runs as your portal login, not the native admin user; step 5 now gives yourself the hr role to get access back. The “reader trap” gotcha was wrong and is replaced. Step 7 now quotes the real SERVICE error, “Invalid service IRI”.
12.2, the server's rolesThe reader shared what Studio → Security actually shows.Added what to expect there: the cloud role's seven all-* permission rows, plus two users you didn't create (admin, the superuser, and your portal login).
12.3, “Hibernate @Filter” Java boxThe reader asked for this box to be removed.Removed. The silent drop it illustrated is shown with real results in Figure 12.2 (HR sees the SSN; marketing gets Jolynn Bithany with an empty SSN).
12.2 and the step-6 gotcha, the reader roleThe book asked the reader to “remember that named-graph * line” for a later gotcha.The “remember” line is gone; 12.2 now says what * means, and the gotcha explains itself where it's used (reader can read every graph, PII included; roles only add). Also removed a stray “tell Claude”.
12.1, “Roles and permissions work like Spring Security” Java boxThe reader asked for this box to be removed.Removed. Its one Stardog fact (unreadable graphs vanish silently; only SERVICE errors) is already in 12.2 and the recap.

Chapter 13 · The Stardog toolbox

DateWhereWhat the reader flaggedWhat changed
13.6, the MCP serverThe portal's profile menu has no “Manage API Keys”, so no Voicebox API token for MCP.Confirmed (Voicebox developer guide and a Stardog Community thread): API keys aren't available on the Free tier. The section now says so, marks MCP as read-along, and notes that Chapter 14 doesn't depend on it.
13.5, “stored query is the graph world's @NamedQuery” Java boxThe reader asked for this box to be removed.Removed.
13.4, Voicebox exercise step 1The reader checked voicebox.enabled and found it already on.The step now says so: on kit-c360 it is already ticked, set by the kit, so nothing needs changing.
13.4, “Voicebox reads your ontology like a JPA entity” Java boxThe reader asked for this box to be removed.Removed.
13.3, StudioThe reader preferred a clearer comparison than “DBeaver that speaks SPARQL”.Now: “What DBeaver is for SQL, Studio's Workspace is for SPARQL.”
13.2, “DataSource” Java boxThe reader asked for this box to be removed.Removed.
13.2, the native admin user's rolesThe text said the admin user has “the role cloud”; after Chapter 12 it has more.The text and Figure 13.1 now say cloud + hr, and why: with named-graph security on, cloud alone reads no graphs.

Chapter 14 · The agent: from question to answer

DateWhereWhat the reader flaggedWhat changed
14.9, “The same agent in Java”The reader doesn't want a Java version of the agent.Section removed, along with Agent.java; the Python agent is the one agent. Sections 14.10 and 14.11 are now 14.9 and 14.10.
14.5, “You know this from JDBC” Java boxThe reader asked for this box to be removed.Removed.
14.5, “A tool is a method you expose to the model” Java boxThe reader asked for this box to be removed.Removed (and a later “see Section 14.5” pointer to it reworded).
14.4, “If you use Hibernate” Java boxThe reader asked for this box to be removed.Removed.
Figure 14.2Same issue as Figure 9.2: step numbers read like counts.Gold step badges and “Step N:” captions, matching Figure 9.2.

Chapter 15 · Build your own Voicebox

DateWhereWhat the reader flaggedWhat changed
New chapterAfter Voicebox summed unit prices for Wisconsin (Carolyn Inworth $27,991.66 instead of $502,529.42), the reader asked for a chapter on building his own Voicebox.New Chapter 15 builds askgraph: the Chapter 14 agent as a Chainlit chat page with Stardog login, per-user chat history, visible SPARQL, a model picker and measured cost and timing. The code is in code/askgraph on GitHub.

Chapter 16 · At scale: huge ontologies and answers you can trust

DateWhereWhat the reader flaggedWhat changed
Chapter numberThe new Chapter 15 goes before it.The old Chapter 15 is now Chapter 16: its sections are 16.1 to 16.13, its build step is 9, and every link and mention in the book points to the new number.

Spotted something unclear? Fixes go in the same way: the passage is rewritten where it stands, and a line is added here.