ifctester: PartOf false pass on USERDEFINED predefinedType - #9203
Open
BIMvoice wants to merge 4 commits into
Open
ifctester: PartOf false pass on USERDEFINED predefinedType#9203BIMvoice wants to merge 4 commits into
BIMvoice wants to merge 4 commits into
Conversation
get_predefined_type() never returns the literal string "USERDEFINED"; for a userdefined element it substitutes the custom ObjectType (or ElementType/ProcessType) text instead, per its own docstring. Every PartOf relation branch compared that text directly against self.predefinedType, so a requirement for predefinedType="USERDEFINED" could never match. Combined with the prohibited-cardinality flip at the end of __call__, this produced a false PASS: an element genuinely contained in, aggregated into, grouped with, nested under, or voided/filled by a userdefined-type parent was reported as satisfying a "must not" requirement. The required-cardinality case produced the mirror false FAIL. Entity.__call__ already special-cases this via is_userdefined_type(). Added the same handling to PartOf via a shared predefined_type_matches() helper, applied at all 6 relation branches (including the no-relation ancestor walk). Reproduced and verified each of the 6 branches directly against real API-built IFC4 models before and after the fix. Two of the six branches (no-relation ancestor walk, voids/fills) had no prior test coverage at all; added baseline coverage alongside the USERDEFINED regression tests. Generated with the assistance of an AI coding tool.
Records the branch enumeration, existing-work check against IfcOpenShell#9187- IfcOpenShell#9190/IfcOpenShell#9058/IfcOpenShell#9059/IfcOpenShell#9142/IfcOpenShell#8407/IfcOpenShell#8292/IfcOpenShell#8253/IfcOpenShell#8161, the PartOf USERDEFINED false-pass reproduction and fix, and the areas checked and not pursued (bounded minOccurs/maxOccurs, reporter layer). Generated with the assistance of an AI coding tool.
Member
|
For all ids fixes please make sure there is a minimal .ids .ifc pair that
demonstrates the defect fixed by the pr.
Sent from a mobile device, excuse my brevity. Kind regards, Thomas
Op za 1 aug 2026, 01:11 schreef Petru Conduraru ***@***.***>:
… PartOf never recognises predefinedType="USERDEFINED", in any of its six
relation branches. The result is a *false pass*: a model that violates a
prohibition is reported as compliant.
The cause
ifcopenshell.util.element.get_predefined_type() never returns the literal
string "USERDEFINED". Its own docstring says so: it substitutes the
custom ObjectType / ElementType / ProcessType text instead.
Entity.__call__ already special-cases this. PartOf.__call__ does not, at
any of its six sites: aggregates, group, contained-in-spatial-structure,
nests, voids and fills, and the no-relation ancestor walk.
The wrong verdict, reproduced
IFC4, an IfcSpace containing an IfcWall, checked with PartOf(predefinedType="USERDEFINED",
cardinality="prohibited"):
- *Before: PASS*, is_pass=True, reason PROHIBITED.
- *Correct: FAIL.* The wall genuinely sits in a userdefined-type
space, which the prohibition forbids.
The mirror case, cardinality="required", gives the opposite wrong answer:
FAIL where it should PASS.
All six branches were built and run independently, before and after.
Why this matters more than a crash
A false pass in an IDS checker tells someone their model is compliant when
it is not, and nothing surfaces the mistake later. That is why this was
prioritised over the false-fail cases in the same audit.
Fix and tests
Adds PartOf.predefined_type_matches(), mirroring the pattern
Entity.__call__ already uses, applied at all six call sites.
37/37 pass, both at baseline and after. Two previously untested PartOf
branches gained coverage as a byproduct.
Deliberately not changed
- Specification.minOccurs / maxOccurs as exact numeric bounds. This
reads as ternary-by-design and no fixture uses other values, so changing it
would be a guess about intent rather than a fix.
- The remaining wrong-verdict site in the reporter layer is exactly
what #9190 <#9190>
already fixes.
Generated with the assistance of an AI coding tool.
------------------------------
You can view, comment on, or merge this pull request online at:
#9203
Commit Summary
- cb5742e
<cb5742e>
ifctester: fix PartOf USERDEFINED false pass
- 0f2b2ed
<0f2b2ed>
docs: add ifctester verdict audit notes
File Changes
(3 files <https://github.com/IfcOpenShell/IfcOpenShell/pull/9203/files>)
- *A* docs/dev-notes/ifctester-verdict-audit.md
<https://github.com/IfcOpenShell/IfcOpenShell/pull/9203/files#diff-e49eeb11a21b136c4161e7a792cb38e2f4d76c2b130c05a12a64c5148ed9473f>
(205)
- *M* src/ifctester/ifctester/facet.py
<https://github.com/IfcOpenShell/IfcOpenShell/pull/9203/files#diff-e4f525da742bfa86a399fbe543e779f6280d5c3acd4e487db25090d007a47fd8>
(22)
- *M* src/ifctester/test/test_facet.py
<https://github.com/IfcOpenShell/IfcOpenShell/pull/9203/files#diff-c6bb81b3ea3868fedf1922f9ae47c738aee12f2329f8b16db8cc398763b139b5>
(134)
Patch Links:
- https://github.com/IfcOpenShell/IfcOpenShell/pull/9203.patch
- https://github.com/IfcOpenShell/IfcOpenShell/pull/9203.diff
—
Reply to this email directly, view it on GitHub
<#9203?email_source=notifications&email_token=AAILWV5ZSHR3BG2D3IUOWAT5HTHLFA5CNFSNUABEM5UWIORPF5TWS5BNNB2WEL2QOVWGYUTFOF2WK43UF42DCNZZGU4DKMRSGWTHEZLBONXW5KTTOVRHGY3SNFRGKZFFMV3GK3TUVRTG633UMVZF6Y3MNFRWW>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAILWV5ZGUNMD6WUEJ7L4TT5HTHLFAVCNFSNUABEKJSXA33TNF2G64TZHM2DANBXGMZDAMJ3JFZXG5LFHM2TAMZRHAYDKNBRGKQXMAQ>
.
Triage notifications, keep track of coding agent tasks and review pull
requests on the go with GitHub Mobile for iOS
<https://github.com/notifications/mobile/ios/AAILWVY4HHFTO7PX3Z5YSCD5HTHLFA5CNFSNUABEM5UWIORPF5TWS5BNNB2WEL2QOVWGYUTFOF2WK43UF42DCNZZGU4DKMRSGWTHEZLBONXW5KTTOVRHGY3SNFRGKZFFMV3GK3TUVJTG633UMVZF62LPOM>
and Android
<https://github.com/notifications/mobile/android/AAILWV7FO5E3QRXXE7VMQED5HTHLFA5CNFSNUABEM5UWIORPF5TWS5BNNB2WEL2QOVWGYUTFOF2WK43UF42DCNZZGU4DKMRSGWTHEZLBONXW5KTTOVRHGY3SNFRGKZFFMV3GK3TUVZTG633UMVZF6YLOMRZG62LE>.
Download it today!
You are receiving this because you are subscribed to this thread.Message
ID: ***@***.***>
|
Minimal .ids/.ifc pair demonstrating the false pass fixed by this branch: a wall inside a user-defined-type IfcSpace, checked with a prohibited PartOf(predefinedType="USERDEFINED"). Verified red (PASS) against the pre-fix code and green (FAIL) against this branch's fix, both through ids.open/ifcopenshell.open, not by calling the facet directly. Requested by aothms on PR IfcOpenShell#9203. Generated with the assistance of an AI coding tool.
BIMvoice
added a commit
to BIMvoice/IfcOpenShell
that referenced
this pull request
Aug 1, 2026
Minimal .ids/.ifc pair: a prohibited specification (no walls allowed) violated by one wall. Requirement checks are skipped for prohibited specifications, so requirement.failures stays empty; the requirement's status must still be False. Verified red (requirement.status True) against the pre-fix code and green (False) against this branch's fix, through ids.open and ifcopenshell.open, not by calling the facet directly. Requested by aothms on PR IfcOpenShell#9203/IfcOpenShell#9205 (applies repo-wide to all ids PRs). Generated with the assistance of an AI coding tool.
BIMvoice
added a commit
to BIMvoice/IfcOpenShell
that referenced
this pull request
Aug 1, 2026
Minimal .ids/.ifc pair: an IfcWall with an IfcPropertyTableValue carrying a real value, checked by a Property requirement with no dataType constraint. With nothing to match against, presence alone should pass. Verified red (FAIL, "does not match the required data type of None") against the pre-fix code and green (PASS) against this branch's fix, through ids.open and ifcopenshell.open, not by calling the facet directly. Requested by aothms on PR IfcOpenShell#9203/IfcOpenShell#9205 (applies repo-wide to all ids PRs). Generated with the assistance of an AI coding tool.
BIMvoice
added a commit
to BIMvoice/IfcOpenShell
that referenced
this pull request
Aug 1, 2026
Minimal .ids/.ifc pair: a wall with an IfcMaterialLayerSet whose single layer has no Material assigned (a valid air gap), checked by a Material value requirement. Verified red (pre-fix code raises AttributeError: 'NoneType' object has no attribute 'Name' via ids.py:306, aborting the whole run) and green (post-fix, the run completes and correctly reports FAIL since the layer has no matching material name). Verified through ids.open and ifcopenshell.open, not by calling the facet directly. Requested by aothms on PR IfcOpenShell#9203/IfcOpenShell#9205 (applies repo-wide to all ids PRs). Generated with the assistance of an AI coding tool.
Contributor
Author
|
Done, and applied to the other five IDS PRs as well (#9205, #9190, #9189, #9188, #9187).
Each pair was checked in both directions, since a fixture that passes before and after proves nothing:
There were no |
This was referenced Aug 1, 2026
BIMvoice
added a commit
to BIMvoice/IfcOpenShell
that referenced
this pull request
Aug 4, 2026
Minimal .ids/.ifc pair: an IfcWall with an IfcPropertyBoundedValue carrying only an UpperBoundValue of 40, checked by a Property requirement with a minInclusive=20 restriction. The missing lower bound could be anything, including below 20, so the requirement must fail rather than pass by omission. Verified red (PASS) against the pre-fix code and green (FAIL) against this branch's fix, through the ifctester CLI (ids.open, ifcopenshell.open), not by calling the facet directly. Requested by aothms on PR IfcOpenShell#9203/IfcOpenShell#9205 (applies repo-wide to all ids PRs). Generated with the assistance of an AI coding tool.
BIMvoice
added a commit
to BIMvoice/IfcOpenShell
that referenced
this pull request
Aug 4, 2026
test_fixtures.py is shared with our other open ids-fixture PRs (IfcOpenShell#9203, IfcOpenShell#9205), which each independently create the same file and collide with each other and with this branch. Renaming to a fixture-specific file name avoids the clash; fixture folders under test/fixtures/ never collide since each PR uses its own subfolder. Generated with the assistance of an AI coding tool.
test_fixtures.py is shared with our other open ids-fixture PRs (IfcOpenShell#371-branch, IfcOpenShell#9205), which each independently create the same file and collide with each other and with this branch. Renaming to a fixture-specific file name avoids the clash; fixture folders under test/fixtures/ never collide since each PR uses its own subfolder. Generated with the assistance of an AI coding tool.
BIMvoice
added a commit
to BIMvoice/IfcOpenShell
that referenced
this pull request
Aug 4, 2026
test_fixtures.py is shared with our other open ids-fixture PRs (IfcOpenShell#371-branch, IfcOpenShell#9203), which each independently create the same file and collide with each other and with this branch. Splitting into one file per fixture avoids the clash; fixture folders under test/fixtures/ never collide since each PR uses its own subfolder. Generated with the assistance of an AI coding tool.
This was referenced Aug 4, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
PartOfnever recognisespredefinedType="USERDEFINED", in any of its six relation branches. The result is a false pass: a model that violates a prohibition is reported as compliant.The cause
ifcopenshell.util.element.get_predefined_type()never returns the literal string"USERDEFINED". Its own docstring says so: it substitutes the customObjectType/ElementType/ProcessTypetext instead.Entity.__call__already special-cases this.PartOf.__call__does not, at any of its six sites: aggregates, group, contained-in-spatial-structure, nests, voids and fills, and the no-relation ancestor walk.The wrong verdict, reproduced
IFC4, an
IfcSpacecontaining anIfcWall, checked withPartOf(predefinedType="USERDEFINED", cardinality="prohibited"):is_pass=True, reasonPROHIBITED.The mirror case,
cardinality="required", gives the opposite wrong answer: FAIL where it should PASS.All six branches were built and run independently, before and after.
Why this matters more than a crash
A false pass in an IDS checker tells someone their model is compliant when it is not, and nothing surfaces the mistake later. That is why this was prioritised over the false-fail cases in the same audit.
Fix and tests
Adds
PartOf.predefined_type_matches(), mirroring the patternEntity.__call__already uses, applied at all six call sites.37/37pass, both at baseline and after. Two previously untestedPartOfbranches gained coverage as a byproduct.Deliberately not changed
Specification.minOccurs/maxOccursas exact numeric bounds. This reads as ternary-by-design and no fixture uses other values, so changing it would be a guess about intent rather than a fix.Generated with the assistance of an AI coding tool.