Commit af067e5
fix(parser,ids): keep relationship-resolved classifications on server-parsed stores (#3951)
* fix(parser,ids): distinguish classified-but-unresolved from unclassified on server-parsed stores
Closes #3948. extractClassificationsOnDemand and
extractClassificationSystemsOnDemand (packages/parser/src/classification-resolver.ts)
resolved classification ids via the relationship graph on server-parsed
(source-empty) stores, then unconditionally discarded the result with
`if (!store.source?.length) return [];` right after — a genuinely
classified entity was byte-identical to an unclassified one to every
caller, including the IDS bridge's classification facet.
The classification's own attributes (system name, identification code,
reference chain) need raw STEP bytes to read, and no precomputed table
covers them on a server-parsed store the way the type-inherited property
sets fix (#1795/#1787) had one to fall back to. So both functions now
signal "classified, but unresolved" distinctly from "genuinely
unclassified": extractClassificationsOnDemand returns one
`{ unresolved: true }` entry per resolved id instead of `[]`, and
extractClassificationSystemsOnDemand's return type changes from
`string[]` to `{ names: string[]; unresolved: boolean }`.
The IDS classification facet checker now passes a presence-only ("any
classification") requirement correctly for a classified entity (was a
false CLASSIFICATION_MISSING), and reports a new distinct
CLASSIFICATION_UNRESOLVED failure for a system/value-constrained facet
it cannot verify, instead of silently passing or failing on data it
never read. The viewer's classification-systems panel
(ModelMetadataPanel.tsx) shows an explicit "unavailable on this data
source" state instead of a false "no classification systems".
Claude-Session: https://claude.ai/code/session_01QPHChk3Ve9N519A4kY7436
* fix(ids): surface CLASSIFICATION_UNRESOLVED as a clear message, not the raw enum
Neither describeFailure (translation/service.ts) nor formatFailureReason
(validation/validator.ts) had a case for CLASSIFICATION_UNRESOLVED (added
earlier in this PR for #3948), so both fell through to their default
branch and showed the raw internal enum to the user:
"Validation failed: CLASSIFICATION_UNRESOLVED"
That string reached the IDS panel (styled identically to a genuine
violation) and the exported HTML/CSV report. Both formatters now say
plainly that the entity is classified but its details could not be read
from this data source, matching the length/voice of the neighbouring
classification cases. ClassificationCard.tsx gets the same "unavailable
on this data source" treatment ModelMetadataPanel.tsx already has,
instead of rendering an empty "Classification / Unknown" card for an
unresolved entry.
No new UI severity was introduced: a fail result has no softer variant
today (StatusIcon's not_applicable is a different, unrelated status), so
a clear message is the fix. The optionality exclusion in validator.ts
that keeps CLASSIFICATION_UNRESOLVED out of `missingFailures` is
untouched — that conservative call (an optional facet that cannot be
verified still fails, rather than silently passing) was deliberate.
Trimmed two unrelated JSDoc blocks to single lines to keep
translation/service.ts and validation/validator.ts within their
checked-in module-size budgets after the new switch cases.
Claude-Session: https://claude.ai/code/session_01QPHChk3Ve9N519A4kY7436
* fix(mcp): forward classification `unresolved` through the playground's own IDS accessor
The playground's `makeIdsAccessor().getClassifications` (used by the
`ids_validate` tool, the chat agent's IDS check) is a separate
reimplementation of `IFCDataAccessor` from `createDataAccessor`
(packages/ids/src/bridge/data-accessor.ts) — the "two paths that must
agree" shape this repo already caught once for materials.
#3948/#3951 added a tri-state `unresolved` marker to
`ClassificationInfo` so a classified-but-unreadable entity
(server-parsed store) reads distinctly from a genuinely unclassified
one. The canonical bridge forwards it; this accessor rebuilt a plain
object from `m.bim.classifications(...)` and dropped the field, so a
classified-but-unresolved entity looked to the IDS engine like a real
classification with an empty system/value — reported as a fabricated
CLASSIFICATION_SYSTEM_MISMATCH/_VALUE_MISMATCH instead of the honest
CLASSIFICATION_UNRESOLVED the viewer's own IDS panel already reports.
`ClassificationData` (@ifc-lite/sdk) gains the same optional
`unresolved` field so the accessor can type-check while forwarding it.
Verified against the real dispatcher + IDS engine: a fixture with a
genuine IfcRelAssociatesClassification edge, forced into the
server-parsed shape (no source bytes, no on-demand map) the same way
#3951's own fixtures do. Reverting the fix reproduces
CLASSIFICATION_SYSTEM_MISMATCH; with the fix, CLASSIFICATION_UNRESOLVED.
Claude-Session: https://claude.ai/code/session_01QPHChk3Ve9N519A4kY7436
---------
Co-authored-by: Louis Trümpler <78563314+louistrue@users.noreply.github.com>1 parent 4dc93be commit af067e5
24 files changed
Lines changed: 635 additions & 50 deletions
File tree
- .changeset
- apps/viewer/src/components
- mcp
- viewer/properties
- packages
- ids/src
- bridge
- facets
- translation
- locales
- validation
- parser
- src
- test
- sdk/src
- scripts
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
Lines changed: 7 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
Lines changed: 112 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1655 | 1655 | | |
1656 | 1656 | | |
1657 | 1657 | | |
1658 | | - | |
1659 | | - | |
| 1658 | + | |
1660 | 1659 | | |
1661 | 1660 | | |
1662 | 1661 | | |
| |||
1871 | 1870 | | |
1872 | 1871 | | |
1873 | 1872 | | |
| 1873 | + | |
1874 | 1874 | | |
1875 | 1875 | | |
1876 | 1876 | | |
1877 | 1877 | | |
| 1878 | + | |
1878 | 1879 | | |
1879 | 1880 | | |
1880 | 1881 | | |
1881 | | - | |
1882 | | - | |
1883 | | - | |
1884 | | - | |
| 1882 | + | |
| 1883 | + | |
| 1884 | + | |
1885 | 1885 | | |
1886 | 1886 | | |
1887 | 1887 | | |
| |||
Lines changed: 17 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
11 | 11 | | |
12 | 12 | | |
13 | 13 | | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
14 | 31 | | |
15 | 32 | | |
16 | 33 | | |
| |||
Lines changed: 12 additions & 4 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
114 | 114 | | |
115 | 115 | | |
116 | 116 | | |
117 | | - | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
118 | 121 | | |
119 | | - | |
| 122 | + | |
120 | 123 | | |
121 | 124 | | |
122 | 125 | | |
| |||
301 | 304 | | |
302 | 305 | | |
303 | 306 | | |
304 | | - | |
| 307 | + | |
| 308 | + | |
| 309 | + | |
| 310 | + | |
| 311 | + | |
| 312 | + | |
305 | 313 | | |
306 | 314 | | |
307 | 315 | | |
308 | 316 | | |
309 | 317 | | |
310 | | - | |
| 318 | + | |
311 | 319 | | |
312 | 320 | | |
313 | 321 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
14 | 14 | | |
15 | 15 | | |
16 | 16 | | |
| 17 | + | |
17 | 18 | | |
18 | 19 | | |
19 | 20 | | |
| |||
45 | 46 | | |
46 | 47 | | |
47 | 48 | | |
48 | | - | |
| 49 | + | |
49 | 50 | | |
50 | 51 | | |
51 | 52 | | |
| |||
0 commit comments