The three stages named in the previous lesson, STEP Syntax, IFC Schema, Normative IFC Rules, aren't abstract categories. They're the actual pipeline behind a free, public tool: buildingSMART's own Validation Service at validate.buildingsmart.org. Upload a file, and it runs through exactly the three stages already named, plus a fourth, non-normative pass called Industry Practices that only produces warnings. This lesson covers what a real report from that tool looks like, how to read a single violation without needing to memorise every entity's attribute order, and closes by settling the exact question the last lesson left open.
A file submitted to the service is checked, in order, against STEP Syntax first, then IFC Schema, then Normative IFC Rules. Each stage produces its own findings, tagged with a specific rule name. Schema-layer findings come from the EXPRESS schema's own WHERE rules, baked into the standard itself. Normative-layer findings come from the separate, community-maintained Gherkin rule set covered in the previous lesson, rules like GEM001, PSE001, QTY001, each with its own ID and its own specific check. Industry Practices findings run last and never invalidate a file, they surface as warnings regardless of how many are found.
The report that comes back isn't a single pass/fail verdict. It's a list of individual findings, each naming a specific rule, a specific entity type, and the exact instance IDs that triggered it.
Every violation in a report reduces to the same shape: an entity, a rule, and a set of facts about that entity that the rule says shouldn't coexist. Here's a real one, worked through slot by slot.
IfcOwnerHistory carries eight attributes in order: OwningUser, OwningApplication, State, ChangeAction, LastModifiedDate, LastModifyingUser, LastModifyingApplication, CreationDate. A real instance from a benchmark ArchiCAD IFC4 file reads:
#12 = IFCOWNERHISTORY(#7, #11, $, .ADDED., $, $, $, 1482339244);
Reading the slots in order: OwningUser and OwningApplication are both populated (#7, #11). State is blank. ChangeAction is .ADDED.. LastModifiedDate is blank. LastModifyingUser and LastModifyingApplication are blank. CreationDate carries a real Unix timestamp.
The schema's own WHERE rule on this entity, CorrectChangeAction, requires one of three conditions: LastModifiedDate exists, or LastModifiedDate is absent and ChangeAction is also absent, or LastModifiedDate is absent and ChangeAction is specifically NOTDEFINED or NOCHANGE. This instance satisfies none of the three: LastModifiedDate is absent, and ChangeAction is ADDED, which isn't NOTDEFINED or NOCHANGE. The violation, in plain terms: something claims a change happened, ADDED, without saying when. CreationDate being correctly filled doesn't rescue the finding, since the rule specifically asks about LastModifiedDate, a separate field entirely.
That's the whole method. Identify the entity, read its slots in order like a contact card, find the rule's plain-English requirement, and check which specific facts about the instance contradict it. It never requires memorising an entity's attribute order from scratch, that's what the schema documentation is for, looked up fresh each time.
Occasionally a file's data matches a rule's own stated text exactly, and the validator still fails it. That's worth taking seriously rather than assuming the file is at fault by default.
IfcCurveStyle carries a WHERE rule, MeasureOfWidth, requiring that if CurveWidth is given as a descriptive measure rather than a numeric one, its value must be the literal string 'by layer', with a space. A real case surfaced where a file's CurveWidth was written exactly that way, 'by layer', matching the rule's own text precisely, and the validator still flagged it as a failure. Filed as issue #305 on buildingSMART's own validate GitHub repository, the root cause traces to the parser generating the tool's string comparisons being auto-built from the same grammar used for arithmetic expressions, where whitespace is safely ignored, 1 + 1 and 1+1 mean the same thing, but that logic doesn't hold for a string literal, where 'by layer' and 'bylayer' are different values entirely. A fix was confirmed and scheduled for deployment.
The lesson isn't "distrust the validator." It's that a validator finding is a claim worth checking against the rule's own stated text before accepting it, the same discipline this whole series has applied to every IFC file. Tools built on auto-generated parsers can inherit a grammar-level assumption that doesn't hold everywhere it's applied, and the way to catch that is the same method as reading any other violation: slot by slot, against the rule's own words, not the tool's verdict alone.
The previous lesson left one thing genuinely unresolved: whether QTY001, a real Normative Rule named "Base Quantities," actually catches a category of elements with zero quantity sets at all, the exact failure shape behind Mechanism 1, a real file's 18 strip footings carrying no IfcElementQuantity whatsoever.
That same file has now actually been run through the Validation Service. The result: Schema layer, zero violations. The Normative layer flagged exactly two rule types, GEM001 (a closed-shell geometry defect, two occurrences, unrelated to quantities) and PSE001 (property sets attached to the wrong entity type, ten occurrences, also unrelated to quantities). QTY001 does not appear anywhere in that file's report.
That's the answer, from an actual run, not inferred from documentation. QTY001 checks MethodOfMeasurement on quantity sets that already exist. It has nothing to check on an element that has no quantity set at all, so it stays silent. The file with the most consequential missing-data pattern in this entire series, the one that opened this module, passed through every stage of buildingSMART's own Validation Service without a single flag anywhere near it.
Comments use a free GitHub account — takes under a minute to create, and keeps discussions spam-free and permanently archived.