Repository navigation
Expand file tree
/
Copy pathsupport-matrix.json
More file actions
799 lines (799 loc) · 262 KB
/
Copy pathsupport-matrix.json
File metadata and controls
799 lines (799 loc) · 262 KB
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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
{
"schema_version": 1,
"matrix_id": "rvt-rs-support-matrix",
"reviewed": "2026-10-29",
"description": "Executable support matrix for rvt-rs. Seeded from honest current capabilities in docs/status.md, docs/supported-profile.md, and ROADMAP.md — not aspirational milestone goals. Do not claim converter-grade typed recovery.",
"sources": [
"docs/status.md",
"docs/supported-profile.md",
"ROADMAP.md"
],
"status_vocabulary": [
"verified",
"partial",
"experimental",
"unsupported",
"unknown"
],
"audit_controls": [
"COR-001",
"TEST-001",
"DOC-001",
"A3"
],
"honesty_invariants": {
"never_verified_capability_ids": [
"typed-project-elements",
"typed-decoder-registry",
"ifc4-export-real-projects",
"converter-grade-rvt-ifc",
"typed-door-window",
"schema-field-wall",
"level-elementid-storey-bind",
"aparameter-host-joins",
"semantic-revit-editing",
"stream-level-writer"
],
"max_status_by_capability_id": {
"typed-project-elements": "partial",
"typed-decoder-registry": "partial",
"ifc4-export-real-projects": "partial",
"adocument-walker": "partial",
"browser-viewer": "partial",
"python-package": "partial",
"inspect-cli": "partial",
"stream-level-writer": "partial",
"community-corpus-scaffold": "partial",
"converter-grade-rvt-ifc": "unsupported",
"typed-door-window": "unsupported",
"schema-field-wall": "unsupported",
"level-elementid-storey-bind": "unsupported",
"aparameter-host-joins": "unsupported",
"semantic-revit-editing": "unsupported"
}
},
"capabilities": [
{
"id": "cfb-container-open",
"area": "container",
"name": "Open .rvt / .rfa / .rte / .rft CFB containers",
"status": "verified",
"evidence": "reader module; CI open matrix; Q-01 corpus open path",
"notes": "Standard OLE/CFB Revit layout. Corrupt, encrypted, or non-CFB inputs fail closed.",
"user_impact": "Files can be inspected without Revit."
},
{
"id": "truncated-gzip-streams",
"area": "compression",
"name": "Decode Revit truncated-gzip streams",
"status": "verified",
"evidence": "compression; fuzz targets; samples and the corpus jobs on real files; checksum-page strip on Partitions, Global and (#410) Formats/Latest; probes/examples/probe_schema_page_strip.rs",
"notes": "Every paged stream is stripped before inflate. Formats/Latest joined in #410: stripped, every file of one release inflates to the byte-identical schema (2023: 4 files, 2024: 5, 2025: 8); unstripped it drifted after about 140 KB. Writer path has separate audit coverage.",
"user_impact": "Internal streams can be read safely."
},
{
"id": "metadata-partatom-preview",
"area": "metadata",
"name": "Extract BasicFileInfo (incl. worksharing text block), PartAtom / ProjectInformation Atom, preview PNG",
"status": "verified",
"evidence": "basic_file_info; part_atom; project_information; metadata; tests/samples.rs basic_file_info_properties_read_on_every_release (2016-2026); rvt_info_cli; preview tests",
"notes": "Identity, build, GUID, title, OmniClass, stream preview, and the BasicFileInfo Key: value block (worksharing, central model path, last-saved-by user, save counter, cloud flag) on every release 2016-2026. Folder inventory via rvt-info. Workshared values other than 'Not enabled' are read verbatim; no workshared sample is in the redistributable corpus.",
"user_impact": "Users can identify and audit files, one at a time or a folder at once."
},
{
"id": "formats-latest-schema",
"area": "schema",
"name": "Parse Formats/Latest schema with field classification",
"status": "verified",
"evidence": "formats::parse_schema over the whole page-stripped stream (#410): 3,490 to 4,285 classes and 9,932 to 12,144 fields per release on the 2016-2026 family corpus, 122,107 fields in all; tests/field_type_coverage.rs gates classification, in the scan and in the exact grammar, with 2 or 3 fields per release listed as unclassified (RE-323); probes/examples/probe_schema_page_strip.rs",
"notes": "Class and field structure for developers. Not per-element instance recovery. Before #410 only the first 64 KB were parsed (the 395 classes and 13,570 fields previously quoted), because the rest was inflated without its page strip and read as noise. The class tag here is the u16 after each name; the element records name their class by definition ordinal (#154, #223).",
"user_impact": "Schema introspection works across the verified family band."
},
{
"id": "adocument-walker",
"area": "document",
"name": "Read document-level ADocument data",
"status": "partial",
"evidence": "Layer 5a walker; reliable on newer samples",
"notes": "Good for diagnostics. Older/project bands need more corpus proof. Not complete model extraction.",
"user_impact": "Document metadata aids triage; not a full model read."
},
{
"id": "typed-project-elements",
"area": "elements",
"name": "Revit 2024 partition element records as typed IFC elements, with joins, profiles and cuts where decoded, storeys, family and type names, materials and layers, GlobalIds and stair dimensions",
"status": "partial",
"evidence": "Production iter_elements: ArcWall (2023) + partition MVP Level/Material + 2024 ArcWallRectOpening (ElemTable-confirmed ids) + 2024 partition element-record Wall/Door/Window/Column instances (RE-21/#211) Slab/BuildingPad instances with per-element IFC export overrides (RE-22/#212) and Room instances with their parameter-block name, number and Level (RE-29/#90); RE-19/RE-20 negatives",
"notes": "Revit 2024 projects export typed elements from their partition element records (RE-21 onward), with joins, profiles and cuts where decoded and the element's bounding box elsewhere; the measured figures are in docs/evidence.md. Full model conversion is not solved. Never mark verified without corpus-backed converter-grade evidence (COR-001).",
"user_impact": "Useful recovery on supported subsets; full model conversion is not ready."
},
{
"id": "typed-decoder-registry",
"area": "elements",
"name": "Per-class decoder registry",
"status": "partial",
"evidence": "elements::all_decoders() (81 SimpleDecoder entries); MVP_TYPED_CLASSES consulted by iter_elements",
"notes": "Library building blocks plus production MVP/ArcWall path. Broader registry is not production conversion.",
"user_impact": "Developers can compose decoders; users should not read this as full coverage."
},
{
"id": "element-record-instance-recovery",
"area": "elements",
"name": "Wall / Door / Window / Column / Slab instance recovery from Revit 2024 partition element records",
"status": "verified",
"evidence": "partition_element_records + partition_schema_mvp::instances_from_partition_category_records / slabs_from_partition_category_records + partition_ifc_export_overrides; tests/project_count_fixtures.rs (IFCWALL 360/360, IFCDOOR 132/132, IFCWINDOW 6/6, IFCCOLUMN 256/256, IFCSLAB 80/80, IFCSHADINGDEVICE 20/20, tolerance 0) and the magnetar-2024-core-interior-slim OctetProof verdict, where entity_counts.IFCWALL / IFCDOOR / IFCWINDOW / IFCCOLUMN / IFCSLAB / IFCSHADINGDEVICE are all inside the claimed surface and rvt-rs, IfcOpenShell and IFClite agree exactly",
"notes": "Scope is six BuiltInCategories (OST_Walls, OST_Doors, OST_Windows, OST_Columns, OST_Floors, OST_BuildingPad), one release band (Revit 2024) and one recorded edge. Selection is a direct byte test, not a heuristic: the record must carry no container reference at +0x32 and placement kind 0xffffef7f at +0x42 (RE-21). It supersedes the #204 column rule, whose family-local bbox proxy and highest-ElementId-per-footprint collapse are removed. RE-22 (#212) extended the same rule to slabs and found it already exact there: its 99 OST_Floors selections are all exported (79 IfcSlab + 20 IfcShadingDevice), and the 80th exported slab is an OST_BuildingPad (Pad:Site Pad, ElementId 21975). The IfcSlab / IfcShadingDevice split is a per-instance Revit 'IFC Export As' override read out of the partition parameter block: the UTF-16LE value string with the owning ElementId as a u64 at -0x0dc and again at -0x11e, both required to agree and to be declared in Global/ElemTable. Thirty-one entries pass on this file, naming 21 ids; the 20 that are also placed instances are exactly the export's IFCSHADINGDEVICE Tag set. Only IfcShadingDevice is honoured as an override target — an unrecognised value leaves the element on its class mapping. Where one ElementId is framed more than once, the record with the greatest bounding-box z extent is kept; that agrees with the export's IfcExtrudedAreaSolid.Depth on 79 of 80 slabs (the 80th is exported as two stacked solids summing to it). Ties go to the newest frame - the greatest (stream, offset) - because Revit rewrites an edited element into a higher-numbered Partitions stream and leaves the earlier copy in place (RE-26): 171 of 360 walls and 96 of 132 doors carry two frames that disagree about the plan box, and on the newest one the wall's thin plan extent equals the nominal thickness of the IfcWallType Revit's export assigns on 360 of 360 (201 of 360 on the oldest) and its type slot equals that IfcWallType.Tag on 356 of 360 (183 of 360 on the oldest; the positional read is superseded by RE-28's set test, which is 360 of 360 - see element-record-wall-type-join). Global/ElemTable's u32 at +0x1c is a monotone version counter that ranks the same way across all 976 exported instances. No frame of any instance on this file disagrees about the box's z, so the tie-break cannot move an element between storeys - storey_bound_elements was 801 either way when this was measured, and is 853 since #219 / RE-27. Column, window, slab and building-pad boxes are unchanged; door boxes move without a measurement that adjudicates them, since a door's record box is not the panel Revit exports and 0 of 132 are world-exact either way. Bodies are the record's own bounding box, not a recovered family profile or wall location curve; for plates the z extent is the real thickness, and since RE-25 (#31) the plan profile of a slab whose sketch closes is the recovered sketch boundary rather than the box rectangle - see element-record-slab-plan-profile. Base/top Level ElementIds stay unbound (#86); doors and windows are attached to their host wall as of RE-23/#222 (see element-record-door-window-host-binding). Storey containment came from the #213 column-derived elevation set when this row landed: walls, doors and columns bound by their record base, plates by their record top face (Revit hangs a floor below its level) — 51 of 100 plates bound and all 51 agreed with the export, none wrongly, while windows never bound because their record base is a sill height, measured 0 of 6. Since #219 / RE-27 the first join tried is the Level ElementId the record itself names, which reaches all 100 plates and all 6 windows; that elevation path survives as the fallback - see record-level-reference-storey-bind. This is not evidence for any other category or release. The decoded Door and Window records also carry m_hand_flipped and m_facing_flipped, the m_flippedX and m_flippedY booleans of their native record, on Revit 2024 to 2027 (RE-343). A door or window set in a plain wall (its host a non-curtain wall whose native record gives a straight level line the stored X runs along) is placed on Revit's axes (RE-347, #1447): the IfcLocalPlacement X is the stored X, reversed with Y where the two booleans differ, Z up, the origin unchanged, and RvtElementRecordGeometry.PlacementAxesSource says so. Revit's axes are the same on all 521 doors and 540 windows so placed in the open models (Core Interior, RE1 Architecture, the BIM4LCA office as built and at permit, the last two one building), on the 24 doors and windows of the R2025 models and on all 145 of the 2024 to 2027 held-out models' (counts only; Measure run 42106711251, with tools/re/door_axes_vs_ifc.py in every unfiltered run), where the default axes were Revit's on 115 doors and 226 windows of the 521 and 540; the body and the opening each fills are unmoved in world coordinates, as a saved mesh and as a record box, with their GlobalIds, type GlobalId and host (tools/re/placed_bodies_vs_base.py, runs 42092391898 and 42106731054). On Revit 2025, 2026 and 2027 they are held to the 2024 save of the same project by tools/re/bodies_across_saves.py (two Autodesk sample buildings; a few the 2024 save places are left on the default axes, counted). A door bound to none, an element with no stored transform (Revit 2023 and older) and a turned instance keep the default axes, which say nothing of the direction they face. The origin is the record box's centre, more than 0.5 ft from Revit's on all 1,061 walled doors and windows scored (#1465, RE-357): Revit's is the stored origin plus an offset that is one value for every element of an IfcDoorType or IfcWindowType entity (160 of 160), which revit-ifc keeps in the type's StyleTransform from the instance that created the type and the file does not record; two of its axes follow the element's own opening and the third does not, so no rule with 0 wrong exists (Measure run 42127619521).",
"user_impact": "On the recorded Revit 2024 project, walls, doors, windows, architectural columns, floor slabs and building pads come out as placed IFC entities with position, a solid body and (for slabs) a measured thickness and plan profile, matching Revit's own export element for element. On Autodesk's Snowdon Towers 2024 samples most element frames use a second prologue; their ElementIds come from the enclosing partition record (RE-35), and walls, doors, windows, columns and floors export under Revit's own ids (see element-records-second-prologue-ids). Structural framing, structural columns, foundations and generic models export from the same records (see element-records-structural-categories)."
},
{
"id": "element-records-revit-2025",
"area": "elements",
"name": "Revit 2025 partition element records (walls, slabs, rooms, and the rest of the RE-21 categories)",
"status": "partial",
"evidence": "partition_element_records::bbox_marker; tests/element_records_2025.rs against Drshelden/IFC-ECS RE1-Architecture (MIT, fetched by tools/fetch-corpus.sh); reports/element-framing/RE-32-revit-2025-element-records.md",
"notes": "The 2024 record shape carries over with a per-release bbox marker whose tail is the Global/ElemTable header constant + 40 (0x05d3 on 2025). The RE-21 instance rule reproduces Revit's export exactly on RE1-Architecture (walls 7/7, slabs 2/2, rooms 11/11), and found no false positive across six 2025 files when RE-32 measured them; the doors and the curtain wall, whose frames use the second prologue (RE-30), take their enclosing record's ElementId (RE-35), so every wall, slab, door and room Revit exported is exported; the one element Revit's export leaves out is a plumbing fixture on RE1 Plumbing (442378, attributed since RE-35). RE1's exports are by Revit 26.2, a cross-release pair; puzzbobb's Revit 2025 models, exported by Revit 2025, are exact by ElementId on all 22 that have an export (Measure run 40927543524). Room names, storeys, export-type overrides and wall types stay 2024-only. 2023 (RE-81) and 2026 (RE-124) are read under their own entries.",
"user_impact": "Revit 2025 projects export their walls, slabs, rooms, doors and windows under Revit's own ElementIds, matching Revit's export on the measured files; the diagnostics say what was skipped."
},
{
"id": "element-records-revit-2026",
"area": "elements",
"name": "Revit 2026 partition element records, with storeys, rooms, doors and windows, type names and layer sets",
"status": "experimental",
"evidence": "partition_element_records::BBOX_MARKER_2026 and file_bbox_marker; partition_level_records::elevation_marker; partition_names::ELEMENT_DATA_HEADER_2026; partition_compound_structure::layer_layout; partition_materials (2026 tags); probes/examples/probe_re124_revit_2026_records.rs; tools/re/instances_vs_ifc_tags.py; reports/element-framing/RE-124-revit-2026-element-records.md",
"notes": "Measured on one Revit 2026 project, the flowbim.ee single-dwelling house (local only), against Revit 26.4's own IFC4X3 export. Every per-release constant is the tag of a class in the file's own schema (Outline and ElementParents for the record marker, Plane for Level elevations, CellList for element data, VerticalRegionsStructure for layers, Material, PatternHelper and PhysicalParamSet for materials); a 2026 layer record is 41 bytes, the 2025 fields at their offsets plus a repeated u32. Result: 113 of the export's 115 elements, none outside it, each in Revit's class, with Revit's GlobalId on all 113; the 4 storeys with Revit's names and elevations; 13 of 13 rooms with Revit's number and name; 13 of 13 doors and 15 of 16 windows as IfcDoor/IfcWindow in their host; walls named Family:Type as Revit's; 61 layer sets named and as thick as Revit's, with Revit's layer material names in Revit's order on all 320 layers (RE-125, RE-126), and 65 of the 67 elements given materials with Revit's set. Wall bodies are drawn along each wall's centreline and joined by its join lists (RE-126): faces Revit's on 59 of 59 and height on 37; against Revit's CoordinationView export, which draws each wall as one box, 85 of 118 ends are where it puts them. Since RE-341, beams along their axes (RE-49, RE-328), stair runs as their steps and treads from their native records (RE-217) with the stair property sets and quantities read from them, tread landings (not monolithic ones, which stay boxes; #824) and the sketch lines' exact ends, curves and Sketch curve lists (RE-50, RE-96, RE-97, RE-100) are read as on 2024 or 2025, so sketch-driven floors, ceilings and slabs take their outline from their lines (shaft openings are not cut there: RE-345 turned off the cut that RE-341 had turned on for 2026 and 2027); a roof keeps the record-box solve alone (RE-341 section 5). No beam, landing, stair run or sketch outline is scored against a Revit 2026 export. Each is held to the same Autodesk project's earlier save by tools/re/bodies_across_saves.py, which Measure runs and fails on, and that cannot catch an error the earlier save shares; for one stair flight, Revit's own 2026 export scores its property values and quantities as equal (Measure run 41988011289, head 1d5bbf03). Run 42004827803 (head f9035152) left 102 of 111 exports unchanged. In run 42023546789 (head d3635bbb) the check passes on all six 2026 and 2027 samples (103 of 111 exports unchanged, 8 move). The 2025 save of rac_advanced drew a floor's arcs as chords (24 vertices, against 170 on the 2024, 2026 and 2027 saves) until RE-345 enabled its arc readers, held to the 2024 save alone (#1440). Not read on 2026: roof slopes, spiral stair runs, stair names, railing heights and lengths, a wall's profile openings, IFC export overrides, the opening index. Revit 2025's beams and tread landings are read since RE-345, held to the 2024 save alone. Rooms take their stored solid's outline as on 2025 (RE-314); their prism volume is not written.",
"user_impact": "Revit 2026 projects export typed elements under Revit's ElementIds and GlobalIds, on Revit's storeys, with rooms named and doors and windows in their walls; measured on one model."
},
{
"id": "element-records-revit-2027",
"area": "elements",
"name": "Revit 2027 partition element records, with storeys, rooms, doors and windows, type names, layer sets and wall joins",
"status": "experimental",
"evidence": "partition_element_records::BBOX_MARKER_2027 and assign_second_prologue_ids_with; partition_level_records::elevation_marker; partition_names::ELEMENT_DATA_HEADER_2027; partition_compound_structure::layer_layout; partition_materials (2027 tags); partition_curtain_materials; probes/examples/probe_re179_revit_2027.rs; reports/element-framing/RE-179-revit-2027-element-records.md",
"notes": "Every per-release constant is the tag of a class in the file's own schema (RE-124), and the 2027 values are the same on all seven of Autodesk's 2027 sample files. Layer records, wall join lists and mullion type materials keep their 2026 layouts. Revit 2027 writes most element frames without an ElementId at +0x00 (the second prologue), type symbols among them; from 2027 a symbol frame takes its enclosing chain record's id as instances already do (RE-35), which gives 17,619 of 17,621 such frames the id of the 2026 copy's frame. There is no Revit 2027 IFC export: the oracle is the same model saved by Revit 2026. On Autodesk's five 2027 sample projects the production elements equal their 2026 copies' (20,818 of 20,818 ElementIds, every class the same) and 363,072 of 363,256 fields agree, measured on GitHub's runners by Measure's paired probe (#799); the rest are in the 2027 bytes (79 corner mullions naming two curtain walls, one f32 rounding, a different original symbol) or in RE-82's type-material scan, which has no per-release constant. Read on 2027 as on 2026 since RE-341 (its counts equal 2026's on every Autodesk sample, and the held-out 2027 export scores as the 2026 one does), with the same check against the project's earlier save. Not read on 2027, as on 2026: roof slopes, spiral stair runs, stair names, railing heights and lengths, a wall's profile openings, IFC export overrides, the opening index. Rooms take their stored solid's outline as on 2025, with the same outline and area on the 257 rooms of Autodesk's 2025, 2026 and 2027 samples; their prism volume is not written (RE-314).",
"user_impact": "Revit 2027 projects export typed elements under Revit's ElementIds, on Revit's storeys, with rooms named and doors and windows in their walls; checked against the same models saved by Revit 2026, not against a Revit 2027 export."
},
{
"id": "element-records-revit-2008-2010",
"area": "elements",
"name": "Revit 2008 to 2010 partition element records, read in the 32-bit layout of Revit 2011 to 2023, with storeys and named materials",
"status": "experimental",
"evidence": "partition_element_records_2023::REVIT_32BIT_RELEASES, schema_tags and envelope_shortfall; partition_materials (name_before_properties); partition_level_records::framed_plane_marker; probes/examples/probe_re260_revit_2008_2010.rs; reports/element-framing/RE-260-revit-2008-2010-element-records.md",
"notes": "Revit 2009 and 2010 frame their element records as 2011 does (a declared u32 ElementId 52 bytes before every marker of the local files); Revit 2008's envelope has 12 bytes between the category and the placement kind where later releases have 16, all ff, so its id is 48 bytes before the marker. Each release takes its own tags of the five schema classes RE-180 lists, and 2011 to 2013's shading frame and value blocks (RE-259) hold on 2008 and 2009. A 2008 to 2011 material's name is a u32-counted string followed by three equal f64s, with no PhysicalParamSet tag after it: every material of the local 2008 to 2011 files is now named, and where its own MaterialElemGroupHelper frame names it too the two agree (43 of 43). A 2008 to 2012 Level's elevation follows ff ff ff ff and the Plane tag after its name, one reference slot and 16 bytes, written twice 24 bytes apart: every local 2008 to 2012 file reads its Levels as storeys (Revit's template 0 and 10 ft, and 0 and 4 m on one 2012 project). There is no Revit export and no copy of the same model saved by another release of any 2008 to 2010 file here, and every one is closed source and measured locally only; what is shown is that the records read without a byte left over and that the elements hang together (a 2009 wall and its 8 doors on two storeys, a 2008 causeway as one generic model). Not read, as on 2015 to 2023: layered joins, IFC export overrides, parameters. Design options and the export phase are not applied before Revit 2016 (RE-315 applies them on 2016 to 2023).",
"user_impact": "Outside the 1.0 range (2015 to 2027), measured on the contributor's local closed-source files only. Revit 2008 to 2010 projects export typed elements under Revit's ElementIds, on their storeys, with named materials; checked only for consistency within each file, not against Revit's export. Revit 2011 and 2012 projects gain their storeys and, on 2011, their material names."
},
{
"id": "element-records-revit-2011-2014",
"area": "elements",
"name": "Revit 2011 to 2014 partition element records, read in the 32-bit layout of Revit 2015 to 2023, with storeys, hosts, type names, layer sets and materials",
"status": "experimental",
"evidence": "basic_file_info (release years from 2008, the build-date release); formats::schema_classes (schemas without GUID lists); partition_element_records_2023::REVIT_32BIT_RELEASES and schema_tags; partition_materials::shading_ids_32; partition_type_materials (2011 to 2013 blocks that hold no map); probes/examples/probe_re259_revit_2011_2014.rs; reports/element-framing/RE-259-revit-2011-2014-element-records.md",
"notes": "Files written before Revit 2014 did not open: BasicFileInfo was read only for a year from 2014 on, and a schema written before 2014 has no GUID list after a class's fields. With both read, every local 2008 to 2013 file opens and its schema reads to the end; 2008 and 2009, which state no year, take the build year plus one. Revit 2011 to 2014 frame their element records as 2015 does: on eight local 2011 to 2014 files every record marker has a declared u32 ElementId 52 bytes before it. Each release takes its own tags of the five schema classes RE-180 lists. Two layouts differ from 2015's on 2011 to 2013: a material's shading frame holds two u32 ElementIds between the 0.5 and the pattern slots, and an ElementId and the value-block mark also open blocks that hold no type's map. 2011 to 2013 Levels hold the instance placement kind; 2014 Levels hold 2015's. There is no Revit export of a file before 2015, and every one measured is closed source and measured locally only: the oracle is a local copy of Autodesk's 2013 rac_advanced sample against the pinned 2015 copy. Every ElementId both hold has its class, and 62,071 of 62,153 fields agree; the rest are in the files' own records (a re-divided curtain wall, a shorter wall, two beams' Level references). 2011, 2012 and 2014 have no same-model pair. Revit 2008 to 2010 files open with their metadata and schema, and their element records are not read. Not read, as on 2015 to 2023: layered joins, IFC export overrides, parameters. Design options and the export phase are not applied before Revit 2016 (RE-315 applies them on 2016 to 2023).",
"user_impact": "Outside the 1.0 range (2015 to 2027), measured on the contributor's local closed-source files only. Revit 2008 to 2013 files open and report their release, metadata and schema. Revit 2011 to 2014 projects export typed elements under Revit's ElementIds, on Revit's storeys, with doors and windows in their walls and named types and layer sets; checked against one 2013 sample saved by Revit 2015, not against Revit's export."
},
{
"id": "element-records-revit-2015-2018",
"area": "elements",
"name": "Revit 2015 to 2018 partition element records, read in the 32-bit layout of Revit 2019 to 2023, with storeys, hosts, type names, layer sets and materials",
"status": "experimental",
"evidence": "partition_element_records_2023::REVIT_32BIT_RELEASES and schema_tags; partition_level_records::LEVEL_PLACEMENT_KIND_2015; partition_compound_structure::wall_orientation_has_word; partition_materials::pattern_slots_32; partition_names::find_element_data_names_32; probes/examples/probe_re181_revit_2015_2018.rs; reports/element-framing/RE-181-revit-2015-2018-element-records.md; reports/element-framing/RE-198-revit-2015-bimcollab-export.md; probes/examples/probe_re315_32bit_record_chain.rs; reports/element-framing/RE-315-32bit-second-prologue-records.md",
"notes": "Revit 2015 to 2018 frame their element records as 2019 does (RE-180): on Autodesk's 2016 to 2018 sample projects every record marker but 4 to 109 per file (as many as on the 2019 copy, but 15 on 2016 rst_basic) has a declared u32 ElementId 52 bytes before it, and so do all but 4 to 6 per file of Autodesk's six 2015 sample projects (pinned by #801) and 0 to 68 per file of three of its 2015 templates; 2014 is not read, since the one 2014 file measured is not documented. Each release takes its own tags of the five schema classes RE-180 lists. Three layouts differ from 2019's: a Level record's placement kind is 0xffffef6f, a wall's flip follows its location line with no word between (as on 2019 and 2020), and a material's shading frame holds two pattern slots, not four. On 2015 to 2018 a type's element-data name is looked for in its own data only and a one-unit entry is passed over. Revit's own export is measured on one 2015 project, BIMcollab's structural example (RE-198, a public download): all 241 of its elements by ElementId, in Revit's class or IFC4's for its IFC2X3 one, 3 written that the export leaves out (#879), and none of its elements' GlobalIds Revit's (#878). Revit's own export is measured on one 2018 project, Vitoria's ALD26 Before (RE-315, CC BY 4.0, spent to find why it exported nothing): 1,314 of Revit's 1,321 elements by ElementId, 1,305 of them in Revit's class or IFC4's (9 curtain walls are written as walls), none written that the export leaves out, 7 missing (4 curtain-panel walls and 3 element assemblies; the conduits, conduit fittings and gutters are recovered since RE-319); for 2016, 2017 and the other 2018 projects there is no Revit export and the oracle is the same model saved by Revit 2019. On rac_basic, rst_basic and rac_advanced of 2016 to 2018 every ElementId shared with the 2019 copy has its class; 2018 rac_basic and rac_advanced agree on every field, and the other differences are in the files' own bytes (boxes, reference lists, 2016's shading colours, 2016 rst_basic's renamed families). On five of the six 2015 sample projects every ElementId shared with the 2019 copy has its class; the sixth, rst_basic, shares no ElementId with it (another model), and the differing fields (type materials from RE-82's scan, renamed families, curtain-wall member boxes) are counted in RE-181 §6, not explained. Not read, as on 2019 to 2023: layered joins, IFC export overrides, parameters. Design options and the export phase are applied on 2016 to 2018 and not on 2015 (RE-315). Design options are read as on 2024 with u32 ids, on the eight saves of Autodesk's rst_basic_sample_project of 2016 to 2023 only: 1 set, 4 frames in a non-primary option, a Mass that Revit does not export, so the exported IFC does not change and no Revit export of these files is measured. The phase is read as RE-281 reads it for 2015 to 2023; no Autodesk sample has an element outside it, so the only evidence that applying it is right on a 32-bit file is the held-out Vitoria Project's counts (198 elements Revit's export lacks, then none), which cannot tell the phase from the design options. A frame with no declared ElementId of its own (the second prologue) takes the id of the declared record around it when it is a placed instance and its reference list names that id (RE-315): on Vitoria's Revit 2018 `ALD26 Before`, which wrote no element before, 1,136 of Revit's 1,321 elements by ElementId, 1,127 of them in Revit's class or IFC4's, none written that its IFC2X3 export leaves out, 1,073 on Revit's storey and 7 storeys, as many as Revit's; the 185 missing are conduits, conduit fittings and gutters in categories not yet recovered (178), 4 panel walls and 3 assemblies.",
"user_impact": "Revit 2015 to 2018 projects export typed elements under Revit's ElementIds, on Revit's storeys, with doors and windows in their walls and named types and layer sets; checked against the same models saved by Revit 2019, and for one 2015 project (RE-198) and one 2018 project (RE-315) against Revit's own export of their release."
},
{
"id": "element-records-revit-2019-2022",
"area": "elements",
"name": "Revit 2019 to 2022 partition element records, read in Revit 2023's 32-bit layout, with storeys, hosts, type names, layer sets and materials",
"status": "experimental",
"evidence": "partition_element_records_2023::REVIT_32BIT_RELEASES and schema_tags; partition_names::element_data_header_32, find_element_data_names_32 and lone_non_ascii; partition_compound_structure::wall_orientation_has_word; partition_materials::scan_materials_32; partition_type_materials::type_material_names_32; probes/examples/probe_re180_revit_2019_2022.rs; reports/element-framing/RE-180-revit-2019-2022-element-records.md",
"notes": "Revit 2019 to 2022 frame their element records as 2023 does (RE-81): on Autodesk's 2019 to 2022 sample projects every record marker but 4 to 11 per file (the same count as the 2023 copy) has a declared u32 ElementId 52 bytes before it, and none at any other distance. Every constant of the 2023 readers is 2023's tag of a schema class (CellList, Material, PhysicalParamSet, PatternHelper, VerticalRegionsStructure), and each release takes its own tag of the same class. Revit 2019 and 2020 write a wall's flip right after its location line, with no word between them. In 32-bit data a one-id list reads as a one-unit name; such names are not taken. There is no Revit export of a 2019 to 2022 file: the oracle is the same model saved by Revit 2023. On rac_basic, rst_basic and rac_advanced of 2019 to 2022 every ElementId shared with the 2023 copy has its class; the field differences are in model edits between releases, RE-113's type-material scan, a faucet and a sink without a type, and type names where the 2024 or 2026 copy sides with 2019 to 2022. Not read, as on 2023: layered joins, IFC export overrides, parameters. Design options and the export phase are applied on 2016 to 2023 (RE-315), with the evidence stated for 2015 to 2018.",
"user_impact": "Revit 2019 to 2022 projects export typed elements under Revit's ElementIds, on Revit's storeys, with doors and windows in their walls and named types and layer sets; checked against the same models saved by Revit 2023, not against Revit's export."
},
{
"id": "element-records-product-categories",
"area": "elements",
"name": "Furniture, casework, fixtures, equipment, ceilings, curtain-wall parts, railings, wall sweeps, ducts and pipes from partition element records",
"status": "partial",
"evidence": "partition_element_records::PRODUCT_RECORD_CATEGORIES; tests/element_records_2025.rs against Drshelden/IFC-ECS RE1 Architecture, Mechanical and Plumbing (MIT, fetched by CI tier 2); probes/examples/probe_re33_category_census.rs; reports/element-framing/RE-33-product-categories.md",
"notes": "Thirteen more BuiltInCategory values decode under the unchanged RE-21 instance rule, and every ElementId they select from a record carrying it at +0x00 is a Tag in Revit's own export of the same file: zero false positives on RE1 Architecture, Mechanical and Plumbing (Revit 2025) and on Snowdon Towers (Revit 2024, measured locally). With RE-35's second-prologue ids, RE1 Architecture exports all 58 elements of these categories, RE1 Mechanical all 66 ducts, pipes and fittings and RE1 Plumbing all 117 pipes and fittings and all 6 fixtures, plus one fixture Revit's export leaves out; on Snowdon, curtain panels, railings, ceilings, furniture and fixtures are complete, and 47 curtain panels are elements Revit's export omits (#309). The 60 placed instances with no 3D volume are left out as Revit leaves them out. Second-prologue frames keep the container and placement fields, so the unattributed count covers placed instances only and matches the missing elements exactly for pipes, fittings, mullions, columns, railings, ceilings and furniture. Bodies are the record bounding box; entities are the IFC4 types (IfcFurniture, IfcSanitaryTerminal, IfcCovering, IfcMember, IfcPlate, IfcRailing, IfcBuildingElementProxy, IfcDuctSegment, IfcDuctFitting, IfcPipeSegment, IfcPipeFitting). Revit 2024 and 2025 only.",
"user_impact": "Revit 2024 and 2025 projects export furniture, casework, plumbing fixtures, specialty equipment, ceilings, curtain-wall mullions and panels, railings, wall sweeps, ducts and pipes whose records carry their ElementId, each one an element Revit's own export also holds; the diagnostics count the rest."
},
{
"id": "element-records-second-prologue-ids",
"area": "elements",
"name": "ElementIds for second-prologue partition element records, read from the enclosing partition record",
"status": "partial",
"evidence": "partition_element_records::partition_record_chain / assign_second_prologue_ids / RevitFile::second_prologue_ids; tests/partition_record_chain.rs (every first-prologue frame starts a record of its own id on Core Interior and the RE1 models); tests/element_records_2025.rs; probes/examples/probe_re35_record_wrapper.rs; reports/element-framing/RE-35-partition-record-wrapper.md; reports/element-framing/RE-43-invalid-element-id.md",
"notes": "Every Partitions/* stream opens with a chain of records, one per element: u64 ElementId, u32 size, u16 prologue constant (release constant + 28), u16 count, the body, and a 16-byte trailer that repeats the size (RE-35). A first-prologue frame starts its record; a second-prologue frame (RE-30) sits inside its element's record, so its ElementId is the record's, read rather than inferred. All 30,432 first-prologue frames across nine 2024 and 2025 files start a record of their own id, and the chains hold every declared id on Core Interior and the RE1 models. Records after the chain belong to loaded families' own documents and never export. Against Revit's own exports: RE1 Architecture, Mechanical and Plumbing reach 100% of every recovered entity; Snowdon Towers Architectural exports 6,045 elements, 5,945 in Revit's export (a frame holding u32::MAX, the invalid ElementId, also takes its record's id, RE-43), with every wall, column, door, window, curtain wall and panel, railing, ceiling, furniture item, fixture and generic model of Revit's export attributed once RE-41 declares the ElemTable's second id. The rest are real elements Revit's export leaves out (#309); the 18 in non-primary design options are left out as Revit leaves them out (RE-40). Floors, building pads and ceilings get their ids too. It replaces RE-34's reference-order inference, which gave a door its type's id on a Revit 2025 file outside its hold-outs. Placed instances with no 3D volume are left out, as Revit leaves them out. Revit 2024 and 2025; on Revit 2008 to 2023, whose ElementId is a u32 in a 12-byte record header, the same idea is RE-315 (RE-35's chain walk stops at the first record whose trailer flag word is neither 0 nor 0x01000000, which these files have), measured against Revit's own export on one Revit 2018 project only, ALD26 Before: 1,314 of Revit's 1,321 elements by ElementId with RE-319's conduits, conduit fittings and gutters, 1,305 of them in Revit's class or IFC4's, and all 7 of its Levels; no other release of that layout is measured for it.",
"user_impact": "Files whose element records mostly lack an ElementId at their start (Autodesk's Snowdon Towers samples, the RE1 models, projects saved incrementally) export their walls, doors, windows, floors, ceilings, columns, curtain-wall parts, railings, furniture, fixtures, ducts and pipes under the ElementIds Revit itself uses; the diagnostics count what is still left out."
},
{
"id": "elem-table-secondary-element-ids",
"area": "elements",
"name": "ElemTable records whose two ids differ declare the second",
"status": "experimental",
"evidence": "elem_table::declared_ids; probes/examples/probe_re41_elem_table_secondary_ids.rs; reports/element-framing/RE-41-elem-table-secondary-ids.md",
"notes": "A 40-byte Global/ElemTable record carries two u32 ids, at +16 and +36. They agree on every record of Core Interior, the RE1 models, teste_export_2025, Projeto1 and the 2016-2023 projects measured. On Autodesk's Snowdon Towers samples (local only) they differ on 84 records (Architectural) and 27 (Structural); there the second is the id of the element's partition record (RE-35) and the Tag Revit's own IFC export writes, and the first is neither. The declared id set now holds both (a 0 in the second is not added), which attributes all 37 element records Snowdon Architectural left unattributed (16 walls, 4 columns, 17 generic models, all in Revit's export) and one floor on Snowdon Structural (in the VIM export). Licensed files export byte-identically. Revit 2024 and 2025 only.",
"user_impact": "Elements whose ElemTable record carries a second id, such as those in a primary design option on Autodesk's sample, export under the ElementId Revit itself uses instead of being counted as unattributed."
},
{
"id": "element-records-structural-categories",
"area": "elements",
"name": "Structural framing, structural columns, structural foundations and generic models from partition element records",
"status": "experimental",
"evidence": "partition_element_records::PRODUCT_RECORD_CATEGORIES (OST_StructuralFraming, OST_StructuralColumns, OST_StructuralFoundation, OST_GenericModel); probes/examples/probe_re36_vim_oracle.rs; reports/element-framing/RE-36-structural-categories.md",
"notes": "Four more BuiltInCategory values decode under the RE-21 instance rule with RE-35's enclosing-record ElementIds and export as IfcBeam (.BEAM.), IfcColumn (.COLUMN.), IfcFooting and IfcBuildingElementProxy. Measured locally on Autodesk's Snowdon Towers 2024 samples, which have no licence and are not in CI. Against the VIM export of the Structural sample (a later edition), every exported id the VIM carries has the record's category there: 914 framing members, 74 columns, 90 foundations and 91 generic models, none under another category. The 28 framing ids it lacks are beam-system members the later edition regenerated. On the architectural sample 260 of 261 generic models are in Revit's own IFC4 export; the other is in a non-primary design option. Framing on that file has no braces (Structural Usage: joists, girders, purlins), so IfcBeam is the entity; a brace would also export as IfcBeam, since the record's structural type is not decoded, and Revit's own PredefinedType is not measured. Rebar, structural connections and beam systems have correct ids but are not exported. Bodies are the record bounding box. Revit 2024 and 2025 only.",
"user_impact": "Revit 2024 and 2025 structural models export their beams, joists, girders, columns, footings and generic models as IFC elements under Revit's own ElementIds, with bounding-box bodies; rebar and connections are not exported."
},
{
"id": "element-records-fixture-site-categories",
"area": "elements",
"name": "Lighting fixtures, air terminals, food-service equipment, site elements, elevators and ramps from partition element records",
"status": "partial",
"evidence": "partition_element_records::PRODUCT_RECORD_CATEGORIES; tests/element_records_2025.rs against Drshelden/IFC-ECS RE1 Mechanical and Electrical (MIT, fetched by CI tier 2); reports/element-framing/RE-37-fixture-site-circulation-categories.md",
"notes": "Nine more BuiltInCategory values (OST_LightingFixtures, OST_DuctTerminal, OST_FoodServiceEquipment, OST_Planting, OST_Parking, OST_Entourage, OST_Hardscape, OST_VerticalCirculation, OST_Ramps) decode under the RE-21 instance rule with RE-35's enclosing-record ElementIds. Every exported element is a Tag of Revit's own export with none outside it, and each entity is complete: 447 lighting fixtures, 26 food-service items, 157 planting, parking, entourage and hardscape proxies, 2 ramps and 2 elevators on Snowdon Towers (local only); 7 air terminals on RE1 Mechanical; 12 lighting fixtures on RE1 Electrical. Entities follow Revit's IFC4 export on Snowdon (IfcLightFixture, IfcElectricAppliance, IfcBuildingElementProxy, IfcTransportElement, IfcRamp); air terminals use IfcAirTerminal, the IFC4 subtype of the IfcFlowTerminal Revit writes in IFC2x3. Slab edges are added by RE-40 once non-primary design options are left out; electrical fixtures, lighting, fire alarm and data devices and electrical and mechanical equipment by RE-79 (element-records-mep-devices); stairs and roofs are RE-39. Bodies are the record bounding box. Revit 2024 and 2025 only.",
"user_impact": "Revit 2024 and 2025 projects export their lighting fixtures, air terminals, kitchen equipment, planting, parking, entourage, hardscape, elevators and ramps as the IFC entities Revit itself uses, each one an element Revit's own export also holds."
},
{
"id": "element-records-mep-devices",
"area": "elements",
"name": "Electrical and mechanical devices and equipment from partition element records, without their nested symbols (RE-79)",
"status": "partial",
"evidence": "partition_element_records::PRODUCT_RECORD_CATEGORIES and NESTED_COMPONENT_CATEGORIES; partition_schema_mvp::without_nested_components; probes/examples/probe_re79_nested_mep_components.rs; tests/element_records_2025.rs (revit_2025_electrical_devices_are_revits_own); reports/element-framing/RE-79-mep-devices-nested-components.md",
"notes": "Six BuiltInCategory values (OST_LightingDevices, OST_FireAlarmDevices, OST_DataDevices, OST_ElectricalFixtures, OST_ElectricalEquipment, OST_MechanicalEquipment) decode under the RE-21 instance rule. A shared nested device (the symbol a switch or receptacle nests) is a record of its own in its parent's category; the two list each other among their references and the nested one has the larger ElementId, and Revit's export leaves it out, so rvt-rs does too (21 of 21 on RE1 Electrical). RE1 Electrical then exports exactly Revit's elements: 12 lighting fixtures, 2 data devices, 5 fire alarm devices and 30 devices and panels, none outside its export; RE1 Mechanical adds its AHU. Entities are the IFC4 subtype of what Revit's IFC2x3 export writes: IfcAlarm (IfcAlarmType), IfcElectricAppliance (IfcElectricApplianceType), proxies. Measured on the RE1 models only; Core Interior and Snowdon Towers hold none of these categories and are unchanged. Bodies are the record bounding box. Revit 2024 and 2025 only.",
"user_impact": "MEP models export their switches, receptacles, sensors, alarms, panels and equipment, each an element Revit's own export also holds."
},
{
"id": "element-records-conduits-gutters",
"area": "elements",
"name": "Conduits, conduit fittings and gutters from partition element records (RE-319)",
"status": "experimental",
"evidence": "partition_element_records::PRODUCT_RECORD_CATEGORIES and RECOVERED_CATEGORIES (OST_CONDUITS, OST_CONDUIT_FITTING, OST_GUTTER); probes/examples/probe_re319_category_census.rs; tools/re/category_census_vs_ifc.py; reports/element-framing/RE-319-conduits-conduit-fittings-gutters.md",
"notes": "Three BuiltInCategory values (OST_Conduit, OST_ConduitFitting, OST_Gutter) decode under the unchanged RE-21 instance rule on every release the exporter reads. Measured against Revit's own export on one file, BIM-Speed's Vitoria ALD26 Before (Revit 2018, IFC2X3, CC BY 4.0): all 102 conduits, 74 conduit fittings and 2 gutters the rule selects are Tags of Revit's export and none is outside it, so 1,314 of its 1,321 elements are written (1,136 before), 1,305 of them in Revit's class or IFC4's for its IFC2X3 one, 1,251 on Revit's storey (1,073 before), with no validation finding and the values Revit does not write unchanged at 20; the 7 missing are 4 panel walls and 3 assemblies. Entities: IfcCableCarrierSegment, IfcCableCarrierFitting and IfcPipeSegment (gutters), the IFC4 subtypes of the IfcFlowSegment and IfcFlowFitting Revit's IFC2X3 export writes, which its type objects name (IfcCableCarrierSegmentType 102 of 102, IfcCableCarrierFittingType 74 of 74, IfcPipeSegmentType 2 of 2); no IFC4 export of any of the three exists in the development set, so PredefinedType is left unset. Bodies are the record bounding box: the 102 conduit and gutter boxes within 0.01 ft of Revit's world box are 102 of 104 (the scorer does not say which two). Not measured: any release but 2018 against an export; Autodesk's rme_basic and rme_advanced samples of 2015 to 2027 (19 or 20 conduits, 14 fittings) and Snowdon Towers Electrical (530 conduits, 322 fittings) export them too, counted and not scored since no Revit export of them exists. Cable trays and cable tray fittings (OST_CableTray, OST_CableTrayFitting) are not recovered: no file with a Revit export holds an instance of either. The conduit and conduit fitting centerline categories (OST_ConduitCenterLine, OST_ConduitFittingCenterLine), which revit-ifc leaves out of the export, are never recovered. Conduit and gutter names are not read on Revit 2018 (Name differs, as for pipes), and no Constraints Level parameter is written for the three classes.",
"user_impact": "Projects with conduits, conduit fittings or roof gutters export them as IFC elements with their Revit ElementIds and storeys, drawn as their record's box; on the one Revit 2018 project with a Revit export every one is an element Revit also exports. Cable trays are not exported."
},
{
"id": "element-records-revit-2023",
"area": "elements",
"name": "Revit 2023 partition element records, with wall joins, beam cuts, room outlines, storeys, hosts, family and type names, materials and layer sets (RE-81)",
"status": "partial",
"evidence": "src/research/partition_element_records_2023.rs; partition_schema_mvp::recover_2023_records and nested_in_openings; probes/examples/probe_re81_2023_element_records.rs; reports/element-framing/RE-81-2023-element-records.md; RE-107: partition_level_records::find_level_records_2023 / schema_elevation_marker / OWNER_SENTINEL_RUN_LEN_2023, partition_schema_mvp::select_newest_instance_records, tools/re/storeys_vs_ifc.py, reports/element-framing/RE-107-levels-2023.md; RE-111: partition_names::find_element_data_names_2023, partition_schema_mvp::system_type_names_2023, probes/examples/probe_re111_system_types_2023.rs, reports/element-framing/RE-111-system-types-2023.md; RE-112: partition_compound_structure::layer_layout, probes/examples/probe_re112_layers_2023.rs, reports/element-framing/RE-112-layers-2023.md; RE-114: partition_names::ElementDataLayout / element_data_layout, probes/examples/probe_re114_wall_lines_2023.rs, reports/element-framing/RE-114-wall-layers-2023.md; RE-115: partition_materials::CATEGORY_MATERIAL_FRAME_2023 / scan_category_material, probes/examples/probe_re115_category_materials_2023.rs, reports/element-framing/RE-115-category-materials-2023.md; RE-116: partition_materials::frame_at_2023 / scan_material_appearances, partition_schema_mvp::materials_from_records, tools/re/material_colours_vs_ifc.py, reports/element-framing/RE-116-material-colours-2023.md; RE-117: partition_room_parameters::scan_room_parameter_entries, probes/examples/probe_re117_room_names.rs, reports/element-framing/RE-117-room-names.md; RE-119: partition_schema_mvp::resolve_framing_top_levels, tools/re/storeys_vs_ifc.py, reports/element-framing/RE-119-framing-storeys-2023.md; RE-120: partition_schema_mvp::recover_2023_records, element_record_wall_joins::join_trims, reports/element-framing/RE-120-wall-joins-2023.md; RE-122: element_record_beam_cuts::beam_column_trims, probes/examples/probe_re122_beam_column_refs.rs, probes/examples/probe_re122_beam_supports.rs, reports/element-framing/RE-122-beam-column-cuts.md",
"notes": "A 2023 record sits behind the schema-derived marker (RE-80) with a u32 ElementId 52 bytes and its BuiltInCategory 38 bytes before it, the rest where 2024 has it, and u32 reference lists. Exported with rvt-ifc against Revit's own IFC4 exports of two local 2023 projects: modelo_bim 37 of 37 elements, none outside the export; Exemplo_data 37 of 45, none outside it, the 8 missing being window trims nested in windows, left out with the mullion patterns Revit also leaves out because nothing decoded tells them apart. Every body is the record's bounding box, walls cut back at their joins (RE-120) and beams at their columns (RE-122). Doors and windows bind to their host wall by RE-85's rule on the u32 reference lists: all 19 on Exemplo_data and 11 on modelo_bim take the wall Revit's filled opening voids, and 15 of the 30 openings equal Revit's within 0.01 ft. Not read on 2023: profiles, layered or angled joins, IFC export overrides (4 spread footings Revit writes as IfcSlab come out as IfcFooting); names, types, storeys and materials are read since RE-107 to RE-116 (user_impact). Einhoven (2023, no Revit export) gains 2 walls, 9 curtain panels and 2 windows, unverified. Design options and the export phase are applied since RE-315, with the evidence stated for 2015 to 2018.",
"user_impact": "Revit 2023 projects export their walls, doors, windows, floors, roofs, columns, beams, foundations and rooms as typed IFC elements in the right place and size, under Revit's own ElementIds, instead of an empty scaffold. Since RE-107 they also carry Revit's own Levels as storeys, each element on the storey of the Level its record names (since RE-119 a beam on the Level at its top): Exemplo_data 37 of 37 and modelo_bim 37 of 37 in Revit's storey, all 6 storeys Revit's name and elevation. Since RE-109 each family instance carries its family and type name: all 50 doors, windows, columns, beams and footings of the two projects as Revit names them. Since RE-111 each wall, floor and roof carries its type's name (24 of 24 as Revit's), and since RE-112 its type's layers name its system family, so every element Revit's export types is typed with Revit's type Tag: 37 of 37 on each project. Since RE-113 family instances carry their type's materials (Revit's set on 44 of 45), and since RE-114 walls and floors whose layer materials are named carry a material layer set (modelo_bim's 4 walls and floor); since RE-120 walls are cut back by the walls they join, by 2024's join solver (RE-26, RE-29) over the 2023 records, whose reference lists name the joined walls: Exemplo_data's 17 and modelo_bim's 4 walls exact against Revit's export (2 of 17 and 4 of 4 before). Since RE-115 a layer that takes its category's material takes the one 2023's object styles give it (i32 category · ff ff ff ff · u32 1|2 · u32 1 · ff ff ff ff 3f 01 · 8 bytes · i32 -3000010 · u32 material): Exemplo_data's 17 walls and floor, so its elements with Revit's material set are 35 of 37, and modelo_bim's 31 of 37. Since RE-116 2023 materials carry their shading colour, transparency and shininess (a 2024 frame whose four pattern slots are eight bytes, u32 id and u32 COLORREF) and are named as RE-58 names a 2024 material: by its own name field, else the string ending before ff ff ff ff eb 0b (ff ff ff ff 17 0c on 2024); the material list is the file's own materials (Exemplo_data 114, modelo_bim 108, Einhoven 36), Revit's colour and transparency on 20 of the 21 materials the two exports style, none different, and Exemplo_data's elements with Revit's material set are 36 of 37. Since RE-117 2023 rooms carry their number and name, the parameter entries i32 -1006901 (ROOM_NUMBER) and i32 -1006900 (ROOM_NAME) that follow the room's object: 9 of 9 on Exemplo_data as Revit's (see element-record-room-recovery). Since RE-122 a beam stops at the face of each column its record names and holds its end, as Revit's export stops it: modelo_bim's 8 beams exact (their boxes ran to the column centres before)."
},
{
"id": "element-records-stair-aggregates",
"area": "elements",
"name": "Stairs as IFC aggregates of their runs, landings and stringers, and roofs",
"status": "experimental",
"evidence": "partition_schema_mvp::attach_aggregate_wholes; IfcEntity::Aggregate and the STEP writer's IfcRelAggregates; probes/examples/probe_re39_stair_parts.rs; reports/element-framing/RE-39-stair-aggregates.md",
"notes": "A stair's runs, landings and stringers name the stair's ElementId in their reference lists. Each stair exports as a bodiless IfcStair and its parts (IfcStairFlight, IfcSlab .LANDING., IfcMember .STRINGER.) are related to it by IfcRelAggregates, not contained in a storey. Measured locally on Snowdon Towers Architectural, which has no licence and is not in CI: the same 26 stairs aggregate as in Revit's IFC4 export, and every one of the 228 parts rvt-rs attaches is in the matching Revit aggregate; all 256 new elements (27 stairs, 42 flights, 17 landings, 170 stringers) are in Revit's export. Railings stay standalone: Revit aggregates 65 of the 70 that name a stair, and nothing read tells the other five apart. A flight's PredefinedType is STRAIGHT or SPIRAL, from the m_runType its treads' native records give (#323, RE-217 §10): Revit's on all 35 flights of each BIM4LCA office file and on the 5 R2025 stair models. A landing is .LANDING. and a stringer .STRINGER.. A stair's own PredefinedType comes from its runs and landings by revit-ifc's GetValidatedStairType rule (three square runs and two landings are always DOUBLE_RETURN_STAIR, as Revit writes all ten of the office's; RE-217 §12): Revit's on all 16 stairs of each BIM4LCA office file and on the 5 R2025 stair models. Roofs (OST_Roofs) export as one IfcRoof each with the record box: all 20 Snowdon roofs are IfcRoof Tags in Revit's export, which decomposes 7 of them into a same-Tag IfcSlab .ROOF. part that rvt-rs does not reproduce. Revit 2024 and 2025 only.",
"user_impact": "Stairs come out as Revit exports them: one IfcStair per stair holding its flights, landings and stringers, so IFC viewers show and select a stair as one assembly."
},
{
"id": "element-records-design-options",
"area": "elements",
"name": "Design options: leave out non-primary options, and slab edges",
"status": "experimental",
"evidence": "partition_design_options::compute_design_options and option_set_members_32 (Revit 2016 to 2023); PartitionElementRecord::design_option; probes/examples/probe_re315_32bit_record_chain.rs; reports/element-framing/RE-315-32bit-second-prologue-records.md; probes/examples/probe_re40_design_options.rs; tests/design_options.rs (the licensed files read no design option); reports/element-framing/RE-40-design-option-primary.md",
"notes": "An element record holds its design option's ElementId at +0x2a. A design option set's partition record lists its options at +0x56, and the set's name entry repeats that list and closes with the primary option's ElementId. The exporter drops records in a set's other options, as Revit's IFC export does by default, and reports them as the skipped item element_record_in_non_primary_design_option. A set whose name entry is missing or ambiguous stays unresolved and its options are kept. Measured locally on Snowdon Towers Architectural, which has no licence and is not in CI: of the placed instances of recovered categories, the 29 in the primary option 2059970 are all in Revit's IFC4 export and the 27 in non-primary options are all missing from it; removing them takes the elements outside Revit's export from 118 to 100 and removes none it holds. Slab edges (OST_EdgeSlab) are added as IfcBuildingElementProxy: all 59 exported are in Revit's export. No licensed file has a design option. Revit 2024 and 2025; on Revit 2016 to 2023 with u32 ids (RE-315), measured on the eight saves of Autodesk's rst_basic_sample_project only: 1 set (primary 875635), 4 frames in a non-primary option, 1 Mass left out of the production counts and reported as the skipped item, and no change to the exported IFC (Revit does not export a Mass), with no Revit export of those files measured. Revit 2008 to 2015 read no set.",
"user_impact": "Projects with design options export the model Revit itself exports, the main model with each option set's primary option, instead of every option stacked on top of each other."
},
{
"id": "element-record-family-type-names",
"area": "elements",
"name": "Family and type names of element-record elements, from partition name entries",
"status": "partial",
"evidence": "partition_names::find_name_entries / resolve_type / resolve_family; RevitFile::element_names; tests/element_names.rs against 2024_Core_Interior_slim.ifc and the RE1 exports (CI tier 2); probes/examples/probe_re38_names.rs; reports/element-framing/RE-38-family-and-type-names.md; probes/examples/probe_re42_nested_families.rs; reports/element-framing/RE-42-nested-families.md",
"notes": "Revit 2024 and 2025 partitions carry a name entry for every loaded family and family type: u64 ElementId, u32 length, UTF-16 name, i64 BuiltInCategory. An element's type is the one reference-list id of its own category with an entry, and its family is the one such id in the type's partition record (RE-35); where that record also names families nested in the type's family, the family is the one candidate whose own record names all the others (RE-42). The IFC Name becomes Family:Type:ElementId and the ObjectType Family:Type, as in Revit's export, and the property set gains FamilyName and TypeName. Every name written equals Revit's for the same Tag: 394 on Core Interior, 3,831 on Snowdon Towers (plus 71 elements Revit's export omits), 56, 42, 60 and 12 on RE1 Architecture, Mechanical, Plumbing and Electrical (plus one each omitted on Architecture and Plumbing), 1 on teste_export_2025. On the Snowdon structural sample 1,132 of the 1,156 named elements in the VIM export equal its family and type; the other 24 are a type the VIM's later edition renamed. On Snowdon the name table agrees with the VIM export on all 348 shared ids, name and category. System families (walls, floors, roofs, ceilings, stairs, railings, curtain walls) have no name entry and keep Class-ElementId names and no ObjectType; their type names come from the type's own element data (RE-44, element-record-system-type-names). Revit 2024 and 2025 only.",
"user_impact": "Doors, windows, columns, furniture, fixtures, mullions, panels and other family instances show the same Family:Type names in the IFC and the viewer that Revit gives them."
},
{
"id": "element-record-system-type-names",
"area": "elements",
"name": "Type names of system-family elements (walls, floors, ceilings, roofs, railings, slab edges, ramps, curtain panels that are walls, stairs and their parts), from the type's element data",
"status": "partial",
"evidence": "partition_names::element_data_header / find_element_data_names; partition_type_records::scan_type_records (2024 and 2025, second-prologue records); partition_schema_mvp::recover_partition_schema_mvp; tests/element_names.rs core_interior_system_type_names_are_revits and re1_system_type_names_are_revits (CI tier 2); probes/examples/probe_re44_system_type_names.rs; reports/element-framing/RE-44-system-type-names.md; RE-63: partition_schema_mvp::system_family / attach_system_family_names (FamilyNameSource system_family_by_category); tools/re/names_vs_ifc.py; reports/element-framing/RE-63-system-family-element-names.md; RE-64: partition_schema_mvp::attach_panel_wall_types; probes/examples/probe_re64_panel_wall_types.rs; reports/element-framing/RE-64-panel-walls-slab-edges-ramps.md; RE-65: partition_stairs::component_type_at / scan_component_types; partition_schema_mvp::attach_stair_names (ELEMENT_NAME_FIELD, FamilyNameSource system_family_by_type_kind); probes/examples/probe_re65_stair_names.rs; reports/element-framing/RE-65-stair-names.md; RE-66: partition_names::find_railing_type_names; probes/examples/probe_re66_railing_type_names.rs; reports/element-framing/RE-66-railing-type-names.md; RE-67: partition_names::find_text_type_names; partition_schema_mvp::attach_model_text_types; probes/examples/probe_re67_model_text_types.rs; reports/element-framing/RE-67-model-text-names.md; RE-69: partition_names::find_type_object_ids; partition_schema_mvp::attach_wall_sweep_types; probes/examples/probe_re69_wall_sweep_types.rs; reports/element-framing/RE-69-wall-sweep-names.md; RE-123: partition_schema_mvp::localized_system_family, reports/element-framing/RE-123-localized-system-families.md",
"notes": "A system-family type has no RE-38 name entry. Its serialised element data opens with ff ff ff ff, a u16 header word (0x02d3 on Revit 2024, 0x02ef on Revit 2025), 01 00 00 00 and the type's u64 ElementId, and its name is the first framed string after that (ff ff ff ff, a u16 tag other than 0xffff, a u32 length, UTF-16). An element's type is the one type-definition record of its own category its reference list names (RE-28); on Snowdon and RE1 most such records are second-prologue frames that take their partition record's id (RE-35), and on 2025 they carry the 2025 marker and prologue constant. The element's property set gains TypeName. Every name written equals the type half of Revit's ObjectType for the same Tag: 460 on Core Interior (360 walls, 99 floors, the pad), 1,545 on Snowdon Towers Architectural, 16 on RE1 Architecture, 1 on Projeto1, and 6 of 7 on teste_export_2025, where the seventh wall's frame, data and bounding box all describe the other type, so that export was made from a later state of the model. The system family's own name (Basic Wall, Floor) is not stored in the file - the Portuguese export writes Parede basica for the same family - so no FamilyName is written, the IFC Name stays Class-ElementId and ObjectType stays unset. Types with no element-data block stay unnamed: RE1's one railing type and 7 of 22 Snowdon railing types. No other field of the type's data is read; since RE-110 each typed element is typed by an IFC type object of its type (see ifc-type-objects). Revit 2024 and 2025; since RE-111 (2026-09-28) also Revit 2023, whose data header is ff ff ff ff c0 02 01 00 00 00 with a u32 ElementId and whose types have no type record: an element's type is, of the named ids its record names with no record or name entry, the one named by records of a strict subset of the categories naming each of the others; Exemplo_data 18 of 18 and modelo_bim 6 of 6 walls, floors and roofs with Revit's type name. RE-63 (2026-09-24): the system family itself is derived, since Revit stores none - a curtain wall is a Curtain Wall, a railing a Railing, a floor a Floor, a building pad a Pad, and a wall, ceiling or roof whose type has compound layers (an element of the type drawn in layers, or the type's own data) a Basic Wall, Compound Ceiling or Basic Roof - so these elements are named Family:Type:ElementId with ObjectType Family:Type as Revit names them: Snowdon 1,077 of 1,077 walls, 42 of 42 curtain walls, 68 of 68 ceilings, 20 of 20 roofs, 101 of 131 railings (the others have no type name), 167 of 182 floors (the 15 are floors Revit exports in two parts); Core Interior 460 of 460; RE1 16 of 17. RE-64 (2026-09-24): a curtain panel whose cell holds a basic wall keeps the panel category, and its record names one wall type rather than a panel type; the panel takes it when that type has compound layers, and its family is Basic Wall - Snowdon 18 of 18 named as Revit names them, while 23 panels naming a wall type without layers, which Revit's export leaves out, stay unnamed. Slab edges and ramps take their only system family (Slab Edge, Ramp): Snowdon 59 of 59 slab edges named as Revit names them, and both ramps with Revit's ObjectType (Revit adds a :1 part suffix to the ramp's Name). RE-65 (2026-09-24, Revit 2024): stair, landing and support types are serialised like run types (tag db 0f) and keep their name and a family flag at their own offsets - stair type construction u32 +0x129 (0 Assembled Stair, 1 Cast-In-Place Stair; 2, Precast, unmeasured and unnamed), its parameter entries then name from +0x13f and its component types in seven u64 slots from +0xc9; landing flag +0x95 (0 Non-Monolithic Landing) and name +0x98; support flag +0x89 (0 Stringer, 1 Carriage) and name +0x92; a run's family is Monolithic or Non-Monolithic Run by RE-52's flag. A stair is named Family:Stair:ElementId and each part '<stair> Run|Landing|Stringer N', N its ElementId rank among every record of its category naming the stair. On Revit 2025 the names come from native records instead (RE-65 §6, #323): StairsType.m_constructionMethod (0 Assembled, 1 Cast-In-Place), each type's SymbolInfo.m_name, the run type's m_hasMonolithicSupport and the stair type's support style (1 Stringer); every stair, flight and stringer of puzzbobb's five R2025 stair models has Revit's Name, ObjectType and type object GlobalId (Measure 40179287273). Landings and other constructions or styles are not measured on 2025. Where a part names two types or two stairs, the pair its stair's type lists decides. Snowdon: 26 of 26 stairs, 43 of 43 runs, 17 of 17 landings, 170 of 170 supports with Revit's Name (any of the copies Revit writes of a multistory stair) and ObjectType; Snowdon only, since no other oracle has stairs. RE-66 (2026-09-24, Revit 2024): a railing type with no element data keeps its name in its type object (tag db 0f), as the u32-length UTF-16 string ending at the first ff ff ff ff 0b 02 past +0x100 (+0x1ae on 18 of Snowdon's 20 railing types, +0x1cb on the 2 that carry a Uniformat code); read only where the element-data name is missing. Snowdon railings named as Revit names them: 131 of 131 (was 101); on the 14 types with both, the two names agree. RE-67 (2026-09-24, Revit 2024): model text is a Generic Model that is not a family instance; its list names one text type, a type object (tag db 0f) that frames its name with tag 0x0149 and then a font with tag 0x07eb. It is named Model Text:<type>:<ElementId>: Snowdon 7 of 7 as Revit names them; no other local file has model text. RE-69 (2026-09-24, Revit 2024): a wall sweep's type has no type-definition record of OST_Cornices; it is the one id the sweep's record names that has a type object (tag db 0f) and no name entry, named by its element data, and the sweep is Wall Sweep:<type>:<ElementId>; a sweep naming none is a sweep of a wall type's structure and is named by its ElementId alone, as Revit names it. Snowdon: 258 of 258 wall sweeps named as Revit names them (249 typed, 9 by ElementId). A system family's own name is not in the file; Revit writes it in the locale the file was saved in (BasicFileInfo's Locale when saved). On the four PTB files (two Revit 2023, two Revit 2025) Revit's export names walls Parede básica, floors Piso and roofs Telhado básico, and rvt-rs does too (32 of 32, RE-123); other families and locales keep the ENU name, which is unmeasured outside ENU.",
"user_impact": "Walls, floors, ceilings, roofs and railings show the type name Revit gives them (for example 8\" Interior Partition 3 Hour or Basement Slab) in the IFC property set and the viewer."
},
{
"id": "type-text-parameters",
"area": "elements",
"name": "Type Mark, Description and Fire Rating of element types, on their instances (RE-77)",
"status": "partial",
"evidence": "partition_type_parameters::type_text_parameters; partition_schema_mvp::attach_type_text_parameters; tools/re/type_parameters_vs_vim.py; tools/re/type_parameters_vs_ifc.py; reports/element-framing/RE-77-type-text-parameters.md",
"notes": "Value blocks open [owner u64][56 x 0xff][3 x 0x00]; a type's block holds some text parameters as i64 BuiltInParameter, u32 n, UTF-16 x n. -1001405 Type Mark, -1010103 Description and -1001206 Fire Rating were named by matching values against the VIM export of Snowdon Towers' 2027 edition. Snowdon Towers: Type Mark 1,257 of 1,276 equal to the VIM (the 19 others are empty there), Description 70 of 70, Fire Rating 696 of 696 equal to Revit's IFC4 export; RE1 Architecture Fire Rating 7 of 7. A type with conflicting values gets none. Its Fire Rating is also written as the element's Pset_<Entity>Common.FireRating where no parameter named for that property supplies one, as Revit's exporter does: on the BIM4LCA office Pset_WallCommon.FireRating 97 of Revit's 97 (71 from parameters, 26 from types), RE1 Architecture 7 of 7. Instance parameters and numbers are not read; recall is partial (696 of 862 rated Snowdon elements).",
"user_impact": "Doors, walls and other elements carry their type's Type Mark, Description and Fire Rating in the IFC, the viewer and schedules."
},
{
"id": "family-instance-materials",
"area": "properties",
"name": "Family instances' materials from their type's geometry-material map (RE-82)",
"status": "partial",
"evidence": "src/research/partition_type_materials.rs; partition_schema_mvp::attach_type_materials; ifc::material_constituent_sets_from_types; step_writer IfcMaterialConstituentSet; probes/examples/probe_re82_type_material_maps.rs; tools/re/element_materials_vs_ifc.py; reports/element-framing/RE-82-type-material-maps.md; RE-113: partition_type_materials::type_material_names_2023, partition_materials::scan_materials_2023, probes/examples/probe_re113_type_materials_2023.rs, tools/re/element_materials_vs_ifc.py, reports/element-framing/RE-113-type-materials-2023.md; RE-200: src/research/native_instance_materials.rs, probes/examples/probe_re200_instance_material_params.rs, tests/element_materials.rs, reports/element-framing/RE-200-instance-material-parameters.md; RE-201 to RE-206: partition_curtain_materials::scan_curtain_type_materials, src/research/native_column_joins.rs, src/research/native_rendered_content.rs, src/research/native_type_materials.rs, src/research/native_family_forms.rs, partition_materials::native_category_material, probes/examples/probe_re201_curtain_render_styles.rs, probes/examples/probe_re202_column_joins.rs, probes/examples/probe_re203_type_maps.rs, probes/examples/probe_re204_family_forms.rs, probes/examples/probe_re206_category_styles.rs, reports/element-framing/RE-201-curtain-render-styles.md, RE-202-column-joins-and-rendered-content.md, RE-203-native-type-maps.md, RE-204-family-document-forms.md, RE-205-columns-and-hidden-forms.md, RE-206-category-styles-and-nested-visibility.md",
"notes": "A family type's value block holds a counted map of (u32 key, u64 material) pairs, the materials its geometry uses; each instance exports them as an unnamed IfcMaterialConstituentSet, as Revit does. Against Revit's own exports, elements whose material set equals Revit's: Snowdon Towers 2,533 of the 2,574 given materials (1,202 before), Core Interior 220 of 226 (88 before), RE1 Architecture 58 of 58 (15 before). Differences then: counter tops whose map carries a nested appliance's materials (Revit's since RE-203), planting Revit writes as <Unnamed> (since RE-202), Core Interior's windows. A type whose map holds only unset values gives its columns and products the materials their instance parameters name (FamilyInstance.m_pInstParams, RE-200: the 9 window trims and muntins of each R2025 model 12 to 17, all Revit's), and <Unnamed> where they name none (RE-149). Since RE-201 to RE-206 (2026-10-21) materials are read from the native records: a mullion or panel type's m_renderStyleId (RE-201); an off-centre column the layer of its first overlapping joined wall (CutPairGStep order) on its side, or the exterior layer where it stands out past both faces (RE-202, RE-205); Family.m_eRenderModelType 4 gives <Unnamed> (RE-202); a type's FamilySymbol.m_geomTag2MaterialId by name replaces the scan where they differ, its -1 values giving the instance's material parameters or <Unnamed> (RE-203); <Unnamed> only where the family's own document (its keyed block) shows a visible, non-void form with no material, and a material only hidden forms have, nested families' forms included with Visible bound to a family parameter evaluated by caption, is dropped (RE-204, RE-205, RE-206). Snowdon Towers (local only): 5,134 of the 5,134 elements given materials have Revit's set (3,457 on main before RE-200); RE1 Architecture 71 of 71, RE1 Electrical 49 of 49; Core Interior unchanged. Other instance material overrides are not read. Since RE-113 (2026-09-28) Revit 2023 is read: its value block is [owner u32][28 x ff][3 x 00], its first map u32 n · n x (u32 key · u32 material), and a material is an object 01 00 00 00 · u32 id with class tag 0x09fb 0x27 bytes past the id, named by its element data or a -1001203 parameter entry; Revit's own set on Exemplo_data 17 of 18 and modelo_bim 27 of 27 family instances, doors, windows, columns and beams; a type naming a material whose name is not read gets none.",
"user_impact": "Doors, windows, furniture, fixtures and equipment carry their real materials in the IFC, as Revit's own export does, instead of none."
},
{
"id": "ifc-is-external",
"area": "properties",
"name": "Each element's IsExternal, as Revit's exporter sets it (RE-193)",
"status": "partial",
"evidence": "src/research/native_wall_types.rs; partition_schema_mvp::attach_type_functions / attach_wall_type_functions / attach_is_external (IS_EXTERNAL_FIELD, NAMED_PARAMETER_FIELD_PREFIX); ifc::export_content is_external_set / is_external_value; probes/examples/probe_re193_is_external.rs; tools/re/is_external_vs_ifc.py; reports/element-framing/RE-193-is-external.md",
"notes": "Revit's exporter (revit-ifc IFC_v24.3.40, read and cited) reads a Yes/No parameter named <set>.IsExternal on the element before anything else, then calculates the value: a parameter named IsExternal, the type's Function (external unless interior; a wall type's native m_function, RE-185), a roof is external, a family instance takes its host's, otherwise not external. rvt-rs writes it in the common set of the entity an element is exported as. A wall, curtain wall, door, window, floor or building pad whose Function and parameters are not read gets none; a window never takes its host's (6 of 18 on the R2025 models); curtain mullions and panels get their curtain wall's value, as revit-ifc's host rule gives it from IFC_v24.2.20 on (RE-288; the maintainer, 2026-10-30). The exporter that made the office's exports (24.0.5.432) instead gives them their curtain wall's value through its own cache of element types, so every wall's members of a type after the first wall that uses it read false (members of one type on the same external curtain walls are 8,460 times not external and 397 times external), a value the model does not hold (RE-269): the property census counts it apart, and rvt-rs's value differs from it on 8,579 of the office's 10,003 mullions and 33 of 260 panels as built. The only model of a newer exporter with curtain members is RE1 Architecture (26.2), whose 12 members, all on one interior curtain wall, are false by either rule and equal; the exterior members' values are checked against revit-ifc's source only. No IsExternal is written on a member type. Measured: on the BIM4LCA office as built 2,110 of the 12,375 IsExternal values Revit writes, none different (266 and 29 on main), 2,118 of 12,420 at building permit; on the reference and R2025 models 245 of 310, none different. Parameters and the type Function are read on every release from 2024; a wall's native Function and the last step on 2024 and 2025, the releases measured. On Revit 2015 to 2023 a wall's native Function and the parameters named for IsExternal are read from the saved parameters (RE-283, experimental): Revit's value on all 114 walls of BIMcollab's Revit 2015 export and all 4 of modelo_bim's, none different; no other class gets one there. Core Interior's Revit export writes no property values, so its IsExternal values are values Revit's export does not have.",
"user_impact": "Walls, curtain walls, doors, windows, slabs, roofs, columns, beams, coverings, railings, stairs, ramps, proxies and spaces say whether they are external, as in Revit's own export, which energy and code-checking tools read."
},
{
"id": "ifc-named-pset-parameters",
"area": "properties",
"name": "Parameters named for a standard property set's property, in that set (RE-194)",
"status": "partial",
"evidence": "ifc::standard_property_sets and its generated table (IFC4 sets, their entities and property kinds; tools/ci/gen_standard_property_sets.py); partition_room_parameters::scan_parameter_entries (EntryKind); partition_schema_mvp::attach_named_parameters (NAMED_PARAMETER_FIELD_PREFIX); ifc::export_content named_parameter_sets / add_element_set; ifc::entities PropertyValue::ThermalTransmittance; probes/examples/probe_re194_pset_parameters.rs; tools/re/pset_parameters_vs_ifc.py; reports/element-framing/RE-194-pset-parameters.md",
"notes": "Revit's exporter (revit-ifc IFC_v24.3.40, read and cited) reads a parameter named <set>.<property> on the element before anything else for that property, and writes a common set where its IFC4 definition applies it to the element's entity. rvt-rs reads each such parameter of a property listed in standard_property_sets (IFC4's 278 property sets that apply to an entity, generated from buildingSMART's IFC4 definitions as its validation service lists them, with IFC4's entity hierarchy, #817) from the element's own data object, by how it is stored: a Yes/No or integer as the u32 after its key, a text as u32 n · UTF-16 after it, a number as the f64 just before it (a length in feet, a thermal transmittance in W/(m²·K)). Booleans, identifiers, labels, text, counts, integers, lengths and thermal transmittance are read; angles, areas, ratios, enumerations and a type's parameters are not. Each is written in its set on the element, where the set applies to the entity written, as the type IFC4 declares, replacing rvt-rs's own value. Measured on the BIM4LCA office, the only model measured that defines such parameters: every value Revit's export writes from them is on the element itself; as built, property values equal to Revit's go from 14,531 to 18,374 and at building permit from 14,501 to 18,373, and the 7 stair values that differed are now Revit's; 55 OccupancyNumber values differ in type only (IFC4's IfcCountMeasure, the export's IfcInteger). That export, IFC4 Reference View, also used a user-defined property set file: its glazing set on 846 walls, curtain walls and coverings, its Pset_SpaceCommon covering texts and the absence of IsWired come from it and are not reproduced, and rvt-rs writes IsWired, a stored 0, as No on the doors and windows that carry it, where the export writes none. Revit 2024 files only, among those measured.",
"user_impact": "Fire and acoustic ratings, load bearing, U-values, glazing, handicap access and stair dimensions that a Revit model keeps in parameters named for IFC properties reach the IFC in their standard sets, as in Revit's own export."
},
{
"id": "family-instance-transforms",
"area": "elements",
"name": "Family instances' transforms, and turned instances drawn turned (RE-87)",
"status": "partial",
"evidence": "src/research/partition_instance_transforms.rs (instance_transform, scan_instance_transforms); partition_schema_mvp::attach_instance_axes (INSTANCE_X_AXIS_FIELDS, INSTANCE_TURN_MIN_RADIANS); ifc::export_content::turned_box (BodySource partition_family_instance_turned_box); probes/examples/probe_re87_instance_transforms.rs; tools/re/instance_transforms_vs_ifc.py; tools/re/turned_instances_vs_ifc.py; reports/element-framing/RE-87-instance-transforms.md; ifc::tapered_host_window_cut (RE-89), export_content::INSTANCE_ORIGIN_PROPERTIES (a hand-off, not written in the IFC), reports/element-framing/RE-89-tapered-wall-window-openings.md; partition_instance_transforms::InstanceTransform::plan_axis (RE-90), reports/element-framing/RE-90-hosted-instance-turns.md; probes/examples/probe_227_missing_transforms.rs; tools/re/opening_copies_vs_ifc.py; reports/element-framing/RE-216-current-instance-copies.md",
"notes": "A family instance's element data holds twelve f64: a 3 x 3 rotation stored row by row, then its origin in model feet; the reader takes the first nine f64 that are orthonormal with determinant 1. Against Revit's own IFC placements: Snowdon Towers (2024) 1,951 of 1,956 upright transforms have Revit's placement X, its reverse (57, mostly doors) or a right angle from it (49); the other 5 are walls, which it does not use. RE1 Architecture (2025) 49 of 49. An upright FamilyInstance record (RE-76) turned at least 1e-4 rad off the model's axes is drawn as the rectangle at its angle whose axis-aligned box is its record box, not within about 3 degrees of 45 degrees; columns, beams, curtain-wall panels and mullions keep their own bodies. On Snowdon all 181 turned instances are closer to Revit's body along their own axes (median 1.473 to 0.482 ft; within 0.01 ft 0 to 55), and the openings of the 27 turned doors and windows are within 0.26 ft of Revit's along them (none before). Status is partial: the extent is still the record box (no family geometry), instances with no vertical axis keep their box, and origins are not used. RE-89: a window's opening in a tapered wall (RE-86) is Revit's vertical box, the host type's thickness deep and centred on the window's origin from its transform; all 20 on Snowdon match Revit's across the wall (0.773 and 0.125 ft off before). Doors there, which Revit cuts flush with the exterior face, keep their box. RE-90: an instance hosted on a ceiling or a wall (one vertical axis, Z not up) takes its plan direction from its first flat axis, which agrees with Revit's placement modulo a right angle on every such Snowdon family instance; 58 more are drawn turned (44 proxies, 14 light fixtures), 44 closer to Revit's body and none further. RE-216 (#227, #548): where an instance's copies in different partitions disagree, the copy taken is the one in the partition its current record is in (the partition its stored revision routes to, or the latest holder where that holds none, as native_document reads records); before, such an instance had no transform. On Core Interior 8 stacked doors' copies differ by an inch across the host, and the current copy places Revit's opening exactly (132 of 132 doors within 0.001 ft, from 124); on the BIM4LCA office at building permit 10 more door types take Revit's GlobalId.",
"user_impact": "Doors, windows, furniture and fixtures set at an angle export and display at that angle instead of as the larger box around them."
},
{
"id": "type-length-parameters-window-openings",
"area": "elements",
"name": "Window and door openings and door sizes from their type's lengths (RE-93, RE-94, RE-187, Revit 2024)",
"status": "partial",
"evidence": "partition_type_parameters::scan_partition_lengths / family_parameters_named / type_window_openings / type_door_openings / type_door_sizes; partition_schema_mvp::attach_window_openings / attach_door_openings (FILLER_OPENING_FIELDS) / attach_door_sizes (DOOR_TYPE_SIZE_FIELDS) and filler_opening_from_fields; ifc::export_content FILLER_OPENING_PROPERTIES / DOOR_TYPE_SIZE_PROPERTIES (hand-offs, not written in the IFC); ifc::filler_type_cut and entities::OpeningCut::z_range_feet; ifc::filler_sizes_from_handoffs and IfcModel::filler_sizes; step_writer OverallWidth/OverallHeight; probes/examples/probe_re93_window_openings.rs; probes/examples/probe_re94_door_openings.rs; probes/examples/probe_re187_door_window_sizes.rs; tools/re/door_window_sizes_vs_ifc.py; tests/door_overall_sizes.rs; tools/re/opening_boxes_vs_ifc.py; reports/element-framing/RE-93-window-openings.md; reports/element-framing/RE-94-door-openings.md",
"notes": "A type's value block (RE-77) holds length parameters as f64 feet, ff x 8, i64 parameter: a BuiltInParameter's negative id (Width -1001301, Height -1001300) or a declared family parameter, whose definition names it 0x56 bytes past its id followed by a revit.local.family id. Revit's IFC4 export cuts a window's opening its type's Width wide, centred on the window's origin (RE-87) along its X axis, and its Height high from 3.0 ft above the origin, on all 66 Snowdon Towers windows whose type stores Width and Height. The 3.0 ft is the type's Default Sill Height where the type stores one; the Double-Hung types store none, so the value Revit uses is the instance's sill, which is not read. A window takes the opening only where its type stores all three and its record box holds the opening with at most 0.5 ft to spare on every side, a guard against a sill moved off the default that no Snowdon window exercises. 56 of Snowdon's 68 windows take it, each within 0.001 ft of Revit's opening (none before), with OverallWidth and OverallHeight equal to Revit's. Double-Hung windows and louvers keep their box opening. Measured on Snowdon Towers only; every other local file is unchanged. RE-94: Revit cuts 57 of Snowdon's 126 doors at their type's Rough Width x Rough Height (-1001305, -1001304), centred on the origin and from it up, and those are exactly the doors whose body (record box) is Rough Height tall; the rest have a frame-height body and a frame-sized opening no stored value gives, and keep their box opening. Such a door takes the rough opening and OverallWidth/OverallHeight: 54 within 0.001 ft of Revit's (none before) and the 3 in tapered walls right along the wall and in height; all 57 overall sizes equal Revit's. Opening-only door types (RE-84) are left out: RE1 Architecture's cased opening is 1.0 m wide against a 1.1 m Rough Width. A door type's Width and Height (the same BuiltInParameters) are Revit's OverallWidth and OverallHeight on every door where they are read, 136 of 136 on Core Interior and RE1 (RE-187); a door with no opening read writes them. Windows do not: Core Interior's six hold 1010 mm where Revit writes 1500 x 2700 mm, which RE-215 gives them from the symbol that draws them (native-symbol-cut-sizes).",
"user_impact": "Most Snowdon windows and the doors Revit cuts at their rough size cut the exact opening Revit's export cuts, and carry their overall size; other doors whose type stores its size carry it too."
},
{
"id": "native-symbol-cut-sizes",
"area": "elements",
"name": "A door's and window's overall size from the outline the symbol that draws it cuts in its host (RE-215, Revit 2024 and 2025)",
"status": "partial",
"evidence": "native_symbol_cuts::instance_cut_loops / CutLoop; partition_schema_mvp::attach_cut_loop_sizes (CUT_LOOP_SIZE_FIELDS, CUT_LOOP_REVIT_VERSIONS); ifc::export_content CUT_LOOP_SIZE_PROPERTIES (a hand-off, not written in the IFC); ifc::filler_sizes_from_handoffs and IfcModel::filler_sizes; step_writer OverallWidth/OverallHeight; probes/examples/probe_re215_symbol_cuts.rs; tools/re/symbol_cuts_vs_ifc.py; tools/re/door_window_sizes_vs_ifc.py; tests/door_overall_sizes.rs; reports/element-framing/RE-215-symbol-cut-loops.md; native_symbol_cuts::symbol_wire_widths; partition_schema_mvp::SYMBOL_WIRE_WIDTH_FIELD; probes/examples/probe_re318_symbol_curve_extents.rs; tools/re/symbol_curve_extents_vs_ifc.py; reports/element-framing/RE-318-symbol-wire-width.md",
"notes": "A FamilySymbol record's m_pCutLoops points at one CurveLoop of GLines in the symbol's XZ plane, the outline the symbol cuts in its host. A FamilyInstance names its type in m_masterSymbolId and the symbol that draws it in its InstanceInfo object's m_symbolId, which differs from the type where the instance's own parameters change the geometry (Core Interior's windows: type 17335 cuts 1010 mm square, their symbol 19275 cuts 1500 x 2700 mm). That symbol's loop's extent along X and Z is Revit's OverallWidth and OverallHeight on every door and window measured with one: Core Interior's 132 doors and 6 windows, RE1 Architecture's 4 doors, and the door and 3 windows of each of the R2025 models 12 to 17. On the BIM4LCA office (Revit 2024; Measure 40121636312 and 40122363218) the 187 of its 269 doors whose symbol cuts an outline have Revit's sizes; its 269 windows and other 82 doors are drawn by symbols with no cut loop and keep what they had (#810). It takes precedence over RE-93's opening and RE-187's type size. Those agree with it on every element of the measured files where both are read; on Snowdon Towers (local only), where RE-93 and RE-94 size most windows and doors, whether they agree is NOT MEASURED. Read on Revit 2024 and 2025 only, from loops of straight lines only; a loop with an arc, a door that is an opening alone (RE-84) and a curtain-wall door (RE1's 445975, which has no cut loop) keep what they had. Where no opening is read from the type (RE-93, RE-94), the opening is that loop through the instance's transform (RE-87), centred along its X axis on the loop's middle and from the loop's bottom up, across the host's band: in the instance's frame Revit's opening is the loop's X and Z ranges and runs from the loop's plane to its mirror. All 138 of Core Interior's openings and RE1 Architecture's 4 are within 0.001 ft of Revit's (Measure 40118849373, and for Core Interior's 8 stacked doors whose data copies disagree, RE-216, Measure 40138537515). RE-218 (#810): a door or window whose symbol cuts no loop, upright and along a model axis, and whose element record names a wall or a curtain wall, is sized by its record box along its own X axis and its height, after the type's opening (RE-93, RE-94) and before the type's Width and Height (RE-187): on the BIM4LCA office all 269 windows (265 at building permit) and 258 of 269 doors have Revit's OverallWidth and OverallHeight (187 before), and RE1 Architecture's curtain-wall door 445975 too (Measure 40167653898). One whose record names no wall takes its height along its own Y axis instead, as revit-ifc's GetDoorWindowDimensionFromSymbol measures a family no wall hosts: 266 of the office's 269 doors are then Revit's (Measure 40177398023), the four roof hatches and four doors of type 3267242 among them; two are 0.1137 ft wider than Revit's. RE-318 (#810): the width of such a door or window is the extent along X of the lines of no category in its symbol's saved graphics, the edges of the boxes that bound its forms (the 90 degree wall hatch hides the leaf its width includes), ahead of the box's: all 268 of the office's doors Revit sizes and 269 of 269 windows have Revit's OverallWidth (268 and 265 at building permit; Measure 41725344128), and the only other measured door it reaches, RE1 Architecture's 445975, keeps its width. One building's families; what the boxes are is inferred from Revit's widths. Their openings stay what they were: Revit's runs 18 mm lower and 100 mm past the host wall on each side, the families' own void geometry.",
"user_impact": "Doors and windows on Revit 2024 and 2025 projects carry the OverallWidth and OverallHeight Revit's export writes: from the outline the symbol that draws them cuts, including windows sized by their instance parameters, and, for families that cut their host another way, such as the BIM4LCA office's windows, from their own extents (RE-218)."
},
{
"id": "ifc-export-overrides",
"area": "ifc",
"name": "Revit's IFC export overrides (Export to IFC As, IFC Predefined Type, and their type-level twins), from element data",
"status": "partial",
"evidence": "partition_ifc_export_overrides::find_export_parameters / find_export_parameters_in_objects / scan_export_parameters / ExportParameters; ifc::category_map::lookup_export_override / predefined_type_for; tests/ifc_export_overrides.rs (CI tier 2); probes/examples/probe_re45_ifc_export_parameters.rs; tools/re/export_parameters_vs_ifc.py; reports/element-framing/RE-45-ifc-export-parameters.md; reports/element-framing/RE-190-office-export-values.md",
"notes": "Revit's four IFC export parameters are entries i64 BuiltInParameter, u32 n, UTF-16 value in an element's serialised data: IFC_EXPORT_ELEMENT_AS (-1019014), IFC_EXPORT_ELEMENT_TYPE_AS (-1019015), IFC_EXPORT_PREDEFINEDTYPE (-1019016) and IFC_EXPORT_PREDEFINEDTYPE_TYPE (-1019017), public BuiltInParameter values. An entry belongs, on Revit 2024 and later, to the declared element whose data object (RE-153) holds it, and on earlier releases to the declared element whose element-data header (RE-44) is the last one before it, at most 0x800 bytes back (0x1ac measured); on the BIM4LCA office's permit file the header rule gave IfcSpace to doors, curtain walls, sketch lines and five drains (RE-190); a value must have the shape of an IFC entity name or an enumerator. An element exports as its own override, else its type's (IfcCoveringType naming IfcCovering), with its own predefined type, else its type's, written only when it is an IFC4 enumerator of that entity. Honoured entities are the ones a reference export demonstrates: IfcShadingDevice (RE-22), IfcSlab and IfcCovering, and on the BIM4LCA office IfcWasteTerminal, IfcFireSuppressionTerminal, IfcSanitaryTerminal, IfcAirTerminal and IfcElectricAppliance (RE-190: 185 of 185 elements as built have Revit's class, 165 of 185 at building permit, where 20 appliances have no type), and IfcStair and IfcDoor (#792: 2 generic models and a curtain panel on each office file). Measured: on Core Interior every element rvt-rs writes has Revit's entity, and floors 20912 and 70325, which carry ifcSlab with ROOF, are IFCSLAB .ROOF. as in Revit's export (previously .FLOOR.); on teste_export_2025 (local only) the three walls of type 402, which carries IfcCoveringType with CLADDING, are IFCCOVERING .CLADDING. as in Revit's (previously IFCWALL). RE1, Snowdon Towers, Einhoven and Projeto1 carry no export parameter. The owners of IfcShadingDevice equal RE-22's owner-offset read, which no longer feeds the export. IfcSpace and IfcFooting overrides exist on Core only on elements Revit does not export and stay unhonoured. Revit's own category-to-entity mapping table is not read, and no IfcSlabType or IfcCoveringType is written. Revit 2024's exporter does not act on a curtain wall's value (RE-188) or, measured on the BIM4LCA office only, a wall sweep's (RE-192), so a 2024 file's curtain walls and wall sweeps keep their class. Revit 2024 and 2025.",
"user_impact": "Elements a modeller set to export as another IFC entity or predefined type - a roof-like floor, a wall used as cladding - come out of rvt-rs as they do out of Revit."
},
{
"id": "element-record-curtain-walls",
"area": "elements",
"name": "Curtain walls from Revit 2024 and 2025 element records: the walls their mullions name, aggregating their panels and mullions",
"status": "partial",
"evidence": "partition_schema_mvp::scan_curtain_grid_walls / CURTAIN_GRID_WALL_OFFSETS / CURTAIN_PANEL_WALL_CLASS, ifc::category_map (CurtainPanelWall -> IFCCURTAINWALL), probes/examples/probe_re72_curtain_panels.rs, tools/re/aggregates_vs_ifc.py, reports/element-framing/RE-72-curtain-grids.md; partition_schema_mvp::attach_curtain_walls / CURTAIN_WALL_CLASS / CURTAIN_WALL_PART_CLASSES; ifc::category_map (CurtainWall -> IFCCURTAINWALL .NOTDEFINED.); tests/curtain_walls.rs against RE1 Architecture (CI tier 2); probes/examples/probe_re46_curtain_walls.rs; reports/element-framing/RE-46-curtain-walls.md; RE-62: partition_schema_mvp::attach_curtain_walls (box containment, CURTAIN_PART_BOX_TOLERANCE_FEET) and reports/element-framing/RE-62-curtain-part-containment.md",
"notes": "RE-72: a part names the curtain grid it lies on, and the grid's element data names its curtain wall (u64 at +85 and +478); that wall comes first, before RE-46's named wall and RE-62's box. On Snowdon Towers every one of the 2,075 curtain parts Revit aggregates has Revit's whole (16 panels had none and one, nested curtain wall 1593696, another), and the 18 panels that hold a basic wall export as IfcCurtainWall with their own body, as Revit's do, so all 60 of Revit's curtain walls are matched. A placed wall named in the reference list of a placed OST_CurtainWallMullions record is a curtain wall: on Snowdon Towers Architectural those walls are exactly the 42 Revit's IFC4 export writes as IfcCurtainWall, and on RE1 Architecture the one; no other wall in the corpus is named by a mullion. Six Snowdon walls named only by panels are basic walls used as panel infill, which Revit exports as IfcWall, so a panel alone does not make a curtain wall. The wall exports as a bodiless IfcCurtainWall .NOTDEFINED. (Revit's value on all 60 of its rows), and each panel and mullion whose list names exactly one curtain wall is its IfcRelAggregates part. Against Revit's aggregates: 1,798 of 1,906 parts on Snowdon and 12 of 13 on RE1 sit under the same whole; 89 late Snowdon mullions name no curtain wall (72 reach it through a record that names it, likely the curtain grid, not shipped), 18 panels Revit writes as nested IfcCurtainWall stay IfcPlate, and doors are not aggregated because 3 of the 9 Snowdon doors naming a curtain wall are standalone in Revit's export. Core Interior's export is byte-identical. No curtain grid, panel type or IfcCurtainWallType is read or written. Revit 2024 and 2025. RE-62 (2026-09-24): a part whose reference list names no curtain wall (Snowdon's 'Solar Panels' mullions name only one another) takes the one curtain wall whose record box contains its own within 0.05 ft; that is Revit's parent for 89 of 89 such mullions, and Snowdon parts with Revit's parent rise from 1,967 to 2,057, none with a wrong one.",
"user_impact": "Curtain walls and storefronts come out as IfcCurtainWall with their glazing panels and mullions grouped under them, as in Revit's export, instead of a solid wall box drawn over the glass. Since RE-106 a mullion or panel turned or tilted off the model's axes is the box along its own transform axes whose axis-aligned box is its record box: 1,019 on Snowdon Towers, with Revit's own mesh extents along those axes on every one."
},
{
"id": "element-record-stair-dimensions",
"area": "elements",
"name": "Stair and flight riser count, riser height and tread length from Revit 2024 element data, as Pset_StairCommon / Pset_StairFlightCommon",
"status": "partial",
"evidence": "partition_stairs::stair_dimensions_at / run_riser_count_at / scan_stair_dimensions / flight_riser_counts; partition_schema_mvp (STAIR_* fields); ifc::entities::IfcEntity::ElementPropertySet and PropertyValue::PositiveLengthFeet; probes/examples/probe_re47_stair_dimensions.rs; reports/element-framing/RE-47-stair-dimensions.md",
"notes": "A stair's element data carries, past ff ff ff ff fb 03 ff ff ff ff fb 03 00 00 00 00 (found within its first 0x100 bytes, at 0x63 or 0x6b on Snowdon), its riser height (f64 ft, +16), tread depth (f64 ft, +24) and number of risers (u32, +88); a run's data carries its number of risers after fc ff ff ff ff ff ff ff 00 00 00 02 00 00 00. A flight's count is the stair's for a single run, else its own when the runs add up to the stair's. They are written as Pset_StairCommon / Pset_StairFlightCommon NumberOfRiser (IfcCountMeasure), RiserHeight and TreadLength (IfcPositiveLengthMeasure), the sets and types Revit's export uses, through a new IfcEntity::ElementPropertySet. Measured on Snowdon Towers (local only) against Revit's own values for the same Tags: stairs 26 of 26 on all three; flights RiserHeight and TreadLength 43 of 43, NumberOfRiser 37 of 43, the other 6 being both flights of the three stairs Revit's export splits into two IfcRelAggregates, where it writes the stair total (24) on each flight and rvt-rs the runs' 13 and 11. NumberOfTreads is not written (risers minus runs on 23 of 26 stairs; the other 3 depend on an unread begin/end-with-riser setting), no stair geometry changes, and no licensed CI file has a stair. Revit 2024 only for these byte anchors; the same property sets are read from the stair's and its runs' native records on Revit 2025, 2026 and 2027 (RE-217, RE-341). Since RE-287 a stair also gets TreadLengthAtInnerSide, the tread depth as a flight's, and with rvt-rs --revit-set-placement its Pset_StairFlightCommon: NumberOfRiser and NumberOfTreads summed over its flights and each length as its flights' common value, which equals Revit's export on all 14 stairs of each BIM4LCA office file and on the five R2025 stair models, measured only (revit-ifc's calculators give the stair its own values; where the exporter fills the container's flight set from its runs is not read). The assembled stair's tread count is not read, and no stair type's inside-boundary width is.",
"user_impact": "Stairs and flights carry the riser count, riser height and tread length Revit schedules them by, in the standard IFC property sets, and the viewer shows them."
},
{
"id": "element-record-beam-axes",
"area": "elements",
"name": "Beams along their location lines from Revit 2024 to 2027 structural-framing element data",
"status": "partial",
"evidence": "partition_beam_axes::bounded_line_at / first_bounded_line / scan_bounded_lines / beam_body; partition_schema_mvp::attach_beam_axes (BEAM_AXIS_* fields); ifc::export_content RecordGeometry and BEAM_AXIS_BODY_SOURCE; probes/examples/probe_re49_beam_axes.rs; reports/element-framing/RE-49-beam-axes.md; RE-328 beams longer in their box than on their line: partition_beam_axes::beam_check / beam_body_in_box, ifc::export_content BEAM_BOX_BODY_SOURCE, probes/examples/probe_re328_beam_rejections.rs, probes/examples/probe_re328_beam_meshes.rs, reports/element-framing/RE-328-beam-rejections.md; RE-103 I sections: partition_type_parameters::type_i_sections, partition_schema_mvp::attach_beam_sections (BEAM_I_SECTION_FIELDS), partition_beam_axes::i_section_body, export_content beam_i_solid (SectionShape I), probes/examples/probe_re103_beam_sections.rs, tools/re/beam_sections_in_ifc.py, reports/element-framing/RE-103-beam-i-sections.md; RE-104 columns: partition_schema_mvp COLUMN_I_AXIS_FIELDS, export_content column_i_section and COLUMN_I_SECTION_BODY_SOURCE, probes/examples/probe_re104_column_sections.rs, reports/element-framing/RE-104-column-i-sections.md; RE-105 material profile sets: ifc::material_profile_sets_from_sections, entities::MaterialProfile.profile, reports/element-framing/RE-105-material-profile-sets.md; RE-221 hollow-section columns: partition_type_parameters::type_hollow_sections (HollowSection, HOLLOW_SECTION_PARAMETER_NAMES), partition_schema_mvp::attach_hollow_sections (HOLLOW_SECTION_FIELDS), export_content hollow_section_profile and COLUMN_HOLLOW_SECTION_BODY_SOURCE, entities::ProfileDef::IndexedPolyCurveWithVoids, probes/examples/probe_hss_sections.rs, tools/re/column_bodies_vs_ifc.py, reports/element-framing/RE-221-hollow-section-columns.md; RE-345 Revit 2025: tools/re/bodies_across_saves.py, reports/element-framing/RE-345-2025-beams-landings-arcs.md",
"notes": "A structural-framing element's data carries its location line as a bounded line record: 04 00 08 01, start and end parameters (f64 ft), an origin (3 f64, model ft) and a unit direction (3 f64), found in the data up to the next element-data header. With the element's record box, beam_body solves a box length x width x depth along the line: the length is the line's, the depth comes from the vertical extent, the width from one plan extent, and the other plan extent must come out to 0.01 ft. A level beam exports as Extrusion::rectangle(length, width, depth) rotated to the line's plan angle; a sloped one keeps its record box as the extrusion and sweeps its section along its centreline (SolidShape::SweptPath, IfcFixedReferenceSweptAreaSolid with +Z as the fixed reference). On Snowdon Towers Structural (local only) all 942 exported framing elements carry a line, 940 inside their box, and 923 solve (802 level on a model axis, 111 level rotated in plan, 10 sloped); IfcOpenShell meshes each exported solid to its record box (938 to 0.001 ft, 4 to 0.0016 ft). Against the meshes of the 2027 edition's VIM export, scored only where that edition kept the beam's Location, type and mesh consistent (839), the section across the line equals Revit's on 613 and Revit's less the top a floor join cuts on 179; the ends equal Revit's on 485 and Revit trims 352 at their supports (median 0.625 ft at the larger end), which is not read. Rotated beams' solids are 1.108 times Revit's own beam envelope at the median, against 8.406 times for the record box they replace. RE-328 (2026-11-04) measured why the other 19 keep their box, against each beam's own saved mesh in the file (Revit's tessellation, not an IFC export): 17 of them are level, unrotated beams whose record box is longer than their line by at most a foot, not beams with oblique end cuts; an unrotated level beam in that class (34 on Autodesk's 2024 samples: 17 Snowdon, 9 rst_basic, 8 rac_advanced) is drawn as the box along the line, BodySource partition_beam_box_along_axis: its direction and section come from the line and the record box (the section across the line is the mesh's on all 25 of them whose mesh decodes whole), its length is the record box's, not the beam's, and Revit's mesh ends inside it at one end or both on 9 of the 25, so it can run past the beam at its ends. It gets no Qto_BeamBaseQuantities.Length, Span, Slope or Roll and no I section; its AxisLength is the line's and its BodyLength the box's. 16 sloped, rolled beams of rst_basic and 2 Snowdon beams whose line leaves the box by up to 100 ft keep their box. Status is partial: ends are not trimmed, floor-join cuts are not applied, the section is a rectangle envelope, 18 beams keep their box, and no licensed CI file has structural framing. Revit 2024, and 2026 and 2027 since RE-341: Autodesk's rst_basic and rac_advanced saved by 2026 and 2027 draw their 2024 saves' beams (345 along their axes and 9 along it on rst_basic, 29 and 8 on rac_advanced, Measure run 41988011289, head 1d5bbf03), none scored against a Revit export of a 2026 or 2027 file, and no 2026 or 2027 held-out model holds an IfcBeam, so the reader has run only on two Autodesk samples saved from earlier releases, never on a natively authored 2026 beam; tools/re/bodies_across_saves.py holds them to the 2024 save. Revit 2025 since RE-345: the same two samples saved by 2025 draw their 2024 saves' beams, 29 along their axes and 8 along it on rac_advanced and 345 and 9 on rst_basic (391 beams, each equal to the 2024 save's in class, GlobalId, storey, placement, volume and vertices; Measure run 42091457764, head 830a4d94), and **no Revit export checks a 2025 beam**: the 28 Revit 2025 models read (puzzbobb's 24 and RE1's four) hold no beam, so the reader has run only on two Autodesk samples saved from 2024, and the same-project check cannot catch an error the 2024 save shares.",
"user_impact": "Beams, joists and girders export along their own axes instead of as boxes around them, so a diagonal beam is a beam, not a slab of the bay it crosses. Since RE-103 a steel beam whose type stores an I section is that I (IfcIShapeProfileDef), flanges across and web upright: 377 of Snowdon Towers' 942 framing elements, and on all 271 its VIM export can score, Revit's own mesh has the section's corners, flange tips and web faces where rvt-rs puts them. Channels, angles, joists and concrete beams keep their box along the line. Since RE-104 a structural column whose type stores an I section is that I turned to the column's own X axis: all 40 of Snowdon Towers' steel columns, and Revit's own mesh on all 24 its VIM export can score. Since RE-105 each of those 417 members is written with an IfcMaterialProfileSetUsage whose IfcMaterialProfile pairs its type's material with its I. Since RE-221 a column whose type is a square hollow section is that section, rounded corners and all (IfcArbitraryProfileDefWithVoids over IfcIndexedPolyCurves, as Revit writes it), read from its family's parameters b, Ht, t and kr: Revit's body on all 79 such columns of the BIM4LCA office as built and 55 at building permit."
},
{
"id": "element-record-pipe-cylinders",
"area": "elements",
"name": "Pipes as cylinders from their connector entries and record box (RE-131)",
"status": "partial",
"evidence": "partition_pipe_axes::pipe_body / best_pipe_body / scan_pipe_bodies; partition_schema_mvp::attach_pipe_axes (PIPE_AXIS_* fields); ifc::export_content pipe_cylinder_solid and PIPE_AXIS_BODY_SOURCE; probes/examples/probe_re131_pipe_sections.rs; tools/re/pipe_bodies_vs_ifc.py; reports/element-framing/RE-131-pipe-cylinders.md",
"notes": "A pipe's two ends are connector entries in its partition: a u64 element, a u32 connector index, the u32 1 and three f64 (model ft). The entry's element is the pipe itself or the element connected at that end (pipe 442026's two ends are keyed by two fittings placed 0.1413 ft beyond them), so an entry is found by where its point falls in the pipe's box. The record box gives the outside radius by cylinder-box inversion (jakobhirn-bit, Discussion #112): every axis that is not nearly the pipe's own must give the same radius (to 0.002 ft), and the box rebuilt from the cylinder must be the record box on all six sides (to 0.002 ft), or the pipe keeps its box. Exported as a PlacedExtrusion over IfcCircleProfileDef, BodySource partition_pipe_axis. Measured on GitHub's runners (Measure run 36723473598) against Revit's own IFC on the MIT RE1 models: 69 of 69 pipes (Mechanical 6, Plumbing 63) are circle-profile extrusions with Revit's radius, axis ends and length to 0.00001 ft; main drew every one as a box and had the right axis for 23 of the 69 (21 of Plumbing's 63, 2 of Mechanical's 6). No other model's IFC changes. Revit 2024 (#869): the BIM4LCA office's 12 pipes, on both its as-built and building-permit files, are circle-profile extrusions with Revit's radius, axis ends and length to 0.00001 ft (Measure run 40146906605; Revit writes their profile as four arcs, which tools/re/pipe_bodies_vs_ifc.py reads), and their 24 ports sit at their ends within 0.01 ft with Revit's axis. A 2024 pipe has no inner diameter read, so it writes no InvertElevation rather than one taken from its axis alone. Status is partial: Revit 2024 and 2025 only (jakobhirn-bit reads the same entries on 2026, on files that cannot run in CI), every measured pipe runs along a principal axis so sloped pipes rest on the rebuild proof and not on an oracle, and ducts and pipe fittings keep their boxes.",
"user_impact": "Pipes export as round pipes along their own axes, with Revit's radius and length, instead of boxes: all 69 of RE1 Mechanical's and Plumbing's (Revit 2025) and all 12 of the BIM4LCA office's (Revit 2024)."
},
{
"id": "element-record-mep-connections",
"area": "elements",
"name": "Ports and port-to-port connections of ducts, pipes, fittings and family instances (RE-138, RE-141, RE-169, RE-197, RE-212)",
"status": "partial",
"evidence": "partition_connector_pairs::scan_connector_pairs and scan_fitting_pairs; partition_schema_mvp::attach_connector_pairs (connector_element_field and connector_index_field); native_connectors::symbol_port_indices, port_type_of_domain and port_flow_direction_of_domain; ifc::export_content IfcEntity::PortConnection and IfcEntity::Port; ifc::step_writer IfcDistributionPort, IfcRelNests and IfcRelConnectsPorts; probes/examples/probe_re138_connector_pairs.rs; probes/examples/probe_re141_connector_anchors.rs; probes/examples/probe_re141_list_scan.rs; probes/examples/probe_re197_connector_directions.rs; tools/re/connector_pairs_vs_ifc.py; tools/re/ports_vs_ifc.py; tools/re/port_places_vs_ifc.py; reports/element-framing/RE-138-connector-pairs.md; reports/element-framing/RE-141-fitting-joins.md; reports/element-framing/RE-197-port-types-and-directions.md; probes/examples/probe_re212_connector_data.rs; tools/re/port_directions_vs_ifc.py; tests/family_instance_ports.rs; reports/element-framing/RE-212-port-flow-directions.md",
"notes": "A duct's or pipe's object lists its connectors' joins after its RbsCurveConnectorManager anchor, as counted lists of two references (the curve's connector and the one joined: a u64 element, a u32 connector index, the u32 1). A join is written in two blocks; the earlier block stores the curve's own connector index inverted, so a list in the later block is read as stored and one in the earlier block inverted when no later list gives the join. RE-141: a fitting's joins are written in the same list form with the fitting as the first reference, and are found by the list alone anywhere in a partition (a fitting's own record holds only the ascending ids it refers to, with no connector index; the pipes' connector managers are not in the leading record chain). A fitting's list is written once with its own connector index as Revit numbers it (a tee's are 1, 2 and 3), where a duct's or pipe's earlier copy is inverted. Every duct and pipe written as a distribution element has a port at each end (B54), and a family instance one for each connector of its symbol, cable tray and conduit ones aside (RE-169); every port is nested in its element with an IfcRelNests, one per element, as Revit's own IFC4 export nests them, a proxy's too (B83, B84). RE-197: a port's PredefinedType is its connector's domain (DUCT, CABLE or PIPE; a duct's or pipe's DUCT or PIPE) and NOTDEFINED for an undefined domain, as Revit's IFC4 export types it, and a connector of a domain Revit's exporter gives no direction, all but HVAC and piping, is SOURCEANDSINK (revit-ifc ConnectorExporter). RE-212: an HVAC or piping connector's direction is the Flow Direction its family sets in the connector's parameters or, where the family leaves it bidirectional, the one Revit calculated for the instance's connector, and a duct's or pipe's is its calculated one; those ports are named InPort_, OutPort_ or Port_ by it and described Flow, as Revit's export names them, and every one of the RE1 models' 463 ports has Revit's FlowDirection. SystemType, the connector's system classification, is not read. Measured on GitHub's runners (Measure run 39261416282) against Revit's own exports: all 73 of RE1 Mechanical's port-to-port connections and all 126 of Plumbing's are written, with none and 2 not in Revit's export, and every one of Revit's 150 and 260 ports, each tied to its element, with no schema finding; on the BIM4LCA office all 67 ports have Revit's PredefinedType and 43 its FlowDirection, and all 53 of RE1 Electrical's are SOURCEANDSINK, as in Revit's export. No port takes a direction Revit's export does not give it. Status is partial: every port's SystemType and an electrical connector's description, the Flow=Source or Flow=Sink Revit's exporter writes, are not read (#834). #869: a port joined to a placed duct or pipe port takes that port's point and Z axis, as Revit's export places every port joined to a segment's: within 0.01 ft of Revit's on all 118 such ports of RE1 Plumbing and all 59 of RE1 Mechanical, axes as Revit's on 108 and 53 and opposite on 10 and 6. Every other family-instance port is placed at its connector: the m_trf of its m_arrConnectorData entry in the symbol that draws the instance (InstanceInfo.m_symbolId, RE-215), whose m_or is the point and the third column of whose m_3x3 is the Z axis, through the instance's transform (RE-87). On Revit 2025 all 53 such ports of RE1 Electrical, 29 of Mechanical and 18 of Plumbing are within 0.01 ft of Revit's, with Revit's axis (Measure 40116733274), and on Revit 2024 all 43 of the BIM4LCA office's (Measure 40141465973, scored in each file's own site frame, since Revit writes the office's site at its shared coordinates); taking the type's symbol instead put 9 of Plumbing's and 2 of Mechanical's up to 0.81 ft off, since fittings sized per instance have symbols of their own.",
"user_impact": "Ducts, pipes, fittings and family instances carry IfcDistributionPort connections: all 73 of Revit's export's connections on RE1 Mechanical and all 126 on Plumbing, with every one of Revit's 150 and 260 ports. Each port is typed PIPE, DUCT or CABLE as Revit types it (all 67 of the BIM4LCA office's), and an electrical port is SOURCEANDSINK, as Revit writes it. A pipe's ports are placed at its ends, with their Z axis along it (#847): all 124 Revit writes on RE1 Plumbing's pipes are within 0.01 ft of Revit's, each with Revit's axis now that its flow direction is read (RE-212). A duct along a model axis has its ports placed the same way (all 62 of Revit's on RE1 Mechanical's ducts and pipes, each with Revit's axis). Every port of the RE1 models has Revit's FlowDirection, and HVAC and piping ports Revit's InPort_/OutPort_ name and Flow description (RE-212); SystemType is not written (#834). A port joined to a placed duct or pipe port, a family instance's included, takes that port's point and axis (#869): all 118 such ports of RE1 Plumbing and all 59 of RE1 Mechanical are within 0.01 ft of Revit's, their axes as Revit's on 108 and 53. Every other family-instance port on Revit 2024 and 2025 is placed at its connector: all 53 on RE1 Electrical, 29 on Mechanical and 18 on Plumbing (2025), and all 43 on the BIM4LCA office (2024), are within 0.01 ft of Revit's, with Revit's axis."
},
{
"id": "element-record-roof-outlines",
"area": "elements",
"name": "Roof and ceiling outlines from their sketch lines, sketch lines' exact recorded ends, and sloped roofs as their planes (Revit 2024 and 2025; floors', ceilings' and slabs' outlines also on 2026 and 2027)",
"status": "partial",
"evidence": "partition_schema_mvp::sketch_plan_profiles / attach_roof_profiles; element_record_plan_profiles::plan_profile_from_lines; partition_beam_axes::scan_bounded_lines; probes/examples/probe_re50_roof_profiles.rs; reports/element-framing/RE-50-roof-outlines.md; partition_roof_slopes::edge_slope / scan_edge_slopes; partition_schema_mvp::attach_roof_slopes / roof_slope_from_fields; ifc::export_content::roof_slope_solid (BodySource partition_roof_slope); ifc::body_geometry::sloped_slab_mesh; reports/element-framing/RE-56-roof-slopes.md; partition_beam_axes::scan_sketch_curves / first_sketch_curve / arc_values_at; element_record_plan_profiles::arc_points; probes/examples/probe_re96_sketch_arcs.rs; reports/element-framing/RE-96-sketch-arcs.md; element_record_plan_profiles::scan_sketch_curve_lists; probes/examples/probe_re97_sketch_curve_lists.rs; reports/element-framing/RE-97-sketch-curve-lists.md; partition_schema_mvp::SKETCHED_PRODUCT_CLASSES; reports/element-framing/RE-98-ceiling-outlines.md; partition_schema_mvp::attach_shaft_voids / shaft_outlines; element_record_plan_profiles::loop_within / loops_disjoint / add_voids_to_fields; partition_element_records::OST_SHAFT_OPENING; probes/examples/probe_re99_shaft_openings.rs; reports/element-framing/RE-99-shaft-openings.md; partition_beam_axes::CIRCLE_TAG / first_circle / scan_sketch_circles; reports/element-framing/RE-100-sketch-circles.md; partition_roof_slopes::edge_slope_in / arrow_heights / scan_arrow_heights / fascia_depth / scan_fascia_depths / scan_rafter_cuts; partition_schema_mvp::roof_slopes_from_fields / roof_rafter_cut_from_fields / roof_fascia_depth_from_fields; partition_beam_axes::scan_sketch_bounded_lines; ifc::export_content::roof_planes_solid; ifc::body_geometry::envelope_slab_mesh; probes/examples/probe_re199_roof_edge_slopes.rs; tools/re/roof_bodies_vs_ifc.py; reports/element-framing/RE-199-roof-planes.md; partition_beam_axes::scan_sketch_splines; partition_schema_mvp::attach_extrusion_roofs; ifc::export_content::roof_extrusion_solid; probes/examples/probe_re211_extrusion_roofs.rs; tools/re/extrusion_roofs_vs_ifc.py; reports/element-framing/RE-211-roof-by-extrusion.md; partition_schema_mvp::roof_arrow_planes_from_fields; ifc::export_content::roof_arrow_planes_solid; ifc::body_geometry::envelope_slab_mesh_split; probes/examples/probe_re307_arrow_roofs.rs; reports/element-framing/RE-307-roofs-sloped-by-several-arrows.md; RE-345 Revit 2025 arcs: tools/re/bodies_across_saves.py, reports/element-framing/RE-345-2025-beams-landings-arcs.md",
"notes": "A roof's OST_SketchLines records carry the roof's ElementId as their owner reference, as a floor's do (RE-25), and close into its plan outline under the same box solve. A sketch line's element data also carries the bounded line record RE-49 reads for beams (04 00 08 01, start and end parameters, origin, unit direction), so its exact ends are known. Where the box solve does not close an element, its lines' recorded ends are chained into loops, provided every line is level with both ends in its own record's box and every end is shared by exactly two lines; otherwise the element keeps no profile. Profiles that closed before are unchanged, except that an element whose box-solved outline uses a line that reads as an arc, a quarter arc whose ends are two corners of its box, is read from its lines' curves instead (RE-96 §4, #824): the BIM4LCA office's roof 1461758 then has Revit's outline, 61 of the office's 63 slab outlines (59 at building permit) within 0.01 ft of Revit's. Measured on Snowdon Towers Architectural (local only) per Tag against the upward-face plan area of Revit's own IFC4 geometry (IfcOpenShell 0.8.5): 13 of 20 roofs carry an outline (none did), 6 equal to Revit's area, 5 equal per layer (Revit writes layered roofs as stacked layer solids) and 2 larger (5.4% and 34.7%, cut in Revit's geometry); every roof outline's plan box is its record box. Slabs rise from 117 to 132 of 199 with an outline (149 since RE-96, below); the 15 added are 11 equal (4 outright, 7 per layer) and 4 larger by 0.2% to 3.0%, the shaft-opening residual earlier outlines also show. RE-56: each roof sketch line's data carries its edge's slope angle (9:12 by default) and flags (00 00 01 00, or 01 01 01 00 on an edge that defines the slope, followed by -rise/run); a roof type's layers follow its name and u32 0. A 2024 roof with exactly one defining edge is drawn rising from it at its slope with its type's thickness square to the slope, as an IfcFacetedBrep, only when that reproduces its record box height within 1e-4 ft: on the Autodesk tutorial house (local only) the one sloped roof, 1:12 over 20.458 ft with a 1.25 ft type, gives 2.9591938797 ft against the recorded 2.959193880 ft. RE-199 (puzzbobb, #870): on Revit 2025 the same edge block holds at +0x3b how far the edge's plane is raised rather than -rise/run, a sketch line's data holds its segment as on 2024, and a Sketch lists its curves as RE-97 found; a roof with several defining edges is drawn as its edges' planes, each held to its straight-skeleton wedge, the eave set by the shallowest edge; a slope arrow's SlopeCurveData (tail and head heights, angle, set by height or by slope) slopes a roof with no defining edge; a 2025 ProfileRoof's rafter cut (parameter -1001710) and fascia depth are read, and a two-cut is cut level at its eave. Each body is drawn only where it reproduces the record box height within 1e-4 ft. On puzzbobb's 23 Revit 2025 models (R2025_Models.zip, Apache-2.0, Measure -f r2025=true, run 39602093604) 18 of the 19 roofs in Revit's exports match Revit's body, every vertex within 0.001 ft and the volume within 1e-4 (main: 0 of 19); the 19th is a roof by extrusion (#883). RE-211 reads a 2025 roof by extrusion's sketch, a clamped B-spline (or lines) in a vertical plane that is the roof's top, offsets it square by the type's thickness for the underside, cuts both ends plumb and runs it across the record box, kept only where it reproduces the record box to 0.001 ft: on the R2025 model 11_RoofByExtrusion all 1,187 of Revit's vertices are within 0.001 ft of the section and its volume is 1.00015 times Revit's (Measure run 40003971692). On Autodesk's samples (no Revit export) rac_advanced's slope-arrow roof is drawn in its 2024 and 2025 saves, its three 15-degree hips are read on 2025 but fail the record-box check and stay level, and 29, 4 and 1 more elements of rac_advanced, rac_basic and rst_basic 2025 take their sketch outline. Status is partial: roofs by extrusion outside Revit 2025 (only one, on 2025, is measured), hip roofs over a T or U footprint (#884), a square two-cut with a fascia, and roofs sloped some other way (Snowdon's 2112673 has no defining edge but is sloped in Revit's export) stay level plates of their record box's height; a 2024 roof with several defining edges takes the RE-199 path but none is measured (#885); cuts are not subtracted, 7 roofs keep their box, and the recorded ends are read on Revit 2024, 2025, 2026 and 2027 only. On 2025 since RE-345 a sketch line's arcs are read too (the Sketch curve lists and recorded ends already were): rac_advanced's floor 139803 (one arc of radius 11.48 ft), roof 201262 (an arc of radius 30 ft) and ceiling 147534 (a half circle) then equal the 2024 save's, where the 2025 save drew their arcs as chords (24 vertices against 170 on the floor; Measure runs 42056591627 (arcs off) and 42091457764), and no Revit export checks any of it: the 25 models with Revit's own 2025 exports (puzzbobb's 24 and RE1 Architecture) hold no floor, ceiling or roof whose sketch holds an arc and no shaft opening, and their exports are byte for byte main's. On 2026 and 2027 (RE-341) the recorded ends, arcs and Sketch curve lists are read as on 2024 and 2025, for floors, ceilings and slabs, held to the same project's 2024 save and not scored against a Revit export;a roof there takes neither reader and keeps the record-box solve alone, and its slope is not read (RE-341 section 5): drawn as an outline at the box's full height a sloped roof is a guess, rac_advanced's sloped roof is a record box on 2026 and 2027 (48.77 m3, Measure run 42091457764) where its 2024 and 2025 saves draw it from its slope (5.33 m3; the 2025 save drew 12 triangles before RE-345, with the roof's arc read as a chord), and no scorer compares a 2026 or 2027 roof with Revit's export. RE-96: a sketch line's curve can be an arc in RE-75's layout without the u64 1 that marks a wall's arc; it counts where every point of it, drawn as chords within 0.0005 ft, lies in the line's record box and the record does not also hold as a line, and an outline with an arc is kept only where it spans its element's record box within 0.001 ft. On Snowdon Towers 17 more slabs carry an outline (132 to 149 of 199): 14 within 0.1% of Revit's upward-face area, 2 half of it (Revit writes each as two solids) and 1 0.8% larger (a tessellated face set in Revit's export); slabs within 0.1% go from 73 to 87. RE-97: a Sketch element's data names the sketched element at +77 and lists its curves (u32 n, n x (u64 id, u32 key), keys rising, with gaps where curves were deleted); where a sketch's list differs from the lines whose owner reference names the element (55 of 447 on Snowdon Towers), the list is the membership, and the outline is kept only where it spans the element's record box. On Snowdon 176 of 199 slabs and all 20 roofs carry an outline (149 and 13 before); slabs within 0.1% of Revit's upward-face area go from 89 to 102 and roofs from 7 to 10 (plan_profiles_vs_ifc.py now takes every piece with one Tag together, which re-scores main from 87 to 89). RE-98: ceilings take their sketch's outline through the same path. Measured on each element's top surface (Revit writes a layered ceiling as one stacked solid per layer, each with the outline): 66 of Snowdon Towers' 68 ceilings within 0.1% of Revit's area (50 before, the rectangles their box already drew), and all 6 of RE1 Architecture's (Revit 2025, 5 before). RE-99: shaft openings (OST_ShaftOpening, -2000996) are sketched as floors are, their sketches holding the two crossing diagonals Revit draws in plan besides the boundary; without those, 8 of Snowdon's 9 shafts close, and each is cut as a void from the one-piece floors, roofs and ceilings within its height that hold it strictly inside: 7 elements on Snowdon, all closer to Revit's area (2 slabs now exact). A shaft on an element's edge, which Revit cuts as a notch, is not cut. Measured on each element's top surface, 150 of Snowdon's slabs are within 0.1% of Revit's area. RE-100: a sketch line that is a full circle is stored in the arc layout under tag 04 00 08 00 with both angles 0; shaft 903725 is one, and read it cuts its round void from 5 more elements, taking Snowdon's slabs within 0.1% of Revit's area to 154. Shaft openings are cut on Revit 2024 only (RE-345, Griffin 2026-11-05): the two shafts of rac_advanced cut nothing in its 2024 or its 2025 save, so the same-project check could not catch a bad cut on a later release, whose floors, ceilings and roofs stay whole while the export counts the shafts (shaft_opening_not_cut); RE-341 had turned the cut on for 2026 and 2027. RE-307: a roof with no defining edge and several slope arrows (Revit 2025) gets, for each arrow, the boundary line its tail lies on and square to, and is drawn as one plane per arrow, the underside level with the base along its line and the top a plane's own T / cos(theta) above it, each surface counting a plane within its own wedges and a top not cut at its edge's line: on puzzbobb's 20_T_U_Roof (Revit 25.0.2's IFC4 export) the T, roof 4149, is Revit's body (32 vertices within 3.2e-06 ft, 436.7078 ft3 against 436.7074), where it was the outline over the record box (4,426.4 ft3). Only Revit 2025, arrows set by their heights, a plumb cut and a fascia depth read as 0 are drawn. The U, roof 5941, stays its record box: Revit slopes its two long outer walls along the arms alone, and a roof with a sloped edge that a reflex edge's extension meets inside it, beside a sloped neighbour at a convex corner, the configuration the U shows, is not drawn either, though only the U is measured.",
"user_impact": "Roofs and more floors export with the shape of their sketch instead of the rectangle around it, and sloped roofs with their slopes: sheds, gables, hips and slope arrows."
},
{
"id": "element-record-stair-treads",
"area": "elements",
"name": "Stair runs drawn as their steps, from the run's sketch, its run type and its end setting (Revit 2024, 2025, 2026 and 2027)",
"status": "partial",
"evidence": "partition_stairs::run_sketch / run_type_at / scan_run_types / scan_run_lines / run_side_profile / run_ends_at / scan_run_ends / monolithic_side_profile; partition_schema_mvp::attach_stair_run_bodies (STAIR_RUN_* fields) and stair_run_body_from_fields; ifc::export_content STAIR_RUN_BODY_SOURCE; ifc::entities::SolidShape::PlacedExtrusion in step_writer and body_geometry; probes/examples/probe_re52_stair_treads.rs; probes/examples/probe_re92_run_ends.rs; tools/re/stair_runs_vs_ifc.py; reports/element-framing/RE-52-stair-treads.md; reports/element-framing/RE-92-stair-run-ends.md; native_stairs::native_runs and partition_schema_mvp::attach_native_stair_run_bodies (Revit 2025); probes/examples/probe_357_native_runs.rs; tools/re/stair_bodies_vs_ifc.py; tools/re/run_types_vs_ifc.py; reports/element-framing/RE-217-stair-runs-2025.md; native_stairs::native_spiral_runs and partition_schema_mvp::attach_spiral_run_bodies (SPIRAL_RUN_* fields, spiral_run_body_from_fields); ifc::export_content SPIRAL_RUN_BODY_SOURCE; ifc::entities::ProfileDef::IndexedPolyCurve and SolidShape::Compound in step_writer and body_geometry; probes/examples/probe_357_spiral_runs.rs and tools/re/spiral_runs_vs_ifc.py; Revit 2026 and 2027: tools/re/save_pair_bodies.py, tools/re/bodies_across_saves.py, reports/element-framing/RE-341-2026-2027-beams-stairs-sketches.md",
"notes": "A straight run's element data holds its plan sketch as bounded line records (04 00 08 01) at its base elevation: two boundary lines from the first riser to the last, then a line across the run at each riser. The run type its reference list names (OST_StairsRuns type definition) has a serialised object 01 00 00 00 + u64 id with tag db 0f at +0x47, structural depth, tread thickness, riser thickness and nosing length as f64 ft at +0x59, +0x69, +0x71, +0x79, flags monolithic / treads / risers / slanted risers at +0xbd..+0xc0, a flag at +0xb5 set on the one type whose treads run under the riser above, then its name. With the stair's riser height (RE-47) the run's side view is extruded across it as an IfcExtrudedAreaSolid with a stated Position. Measured on Snowdon Towers (local only) against Revit's IFC4 and a VIM: 34 of 43 runs drawn; the 30 steel-pan runs equal Revit's geometry to 1e-5 ft; the 4 with upright risers square the nosing Revit shapes with a nosing profile, and one runs its first riser short of Revit's below a landing. RE-92: a run's data holds the StairsRun fields in schema order, seven f64 (bottom elevation, top elevation, extend below base, extend below tread base, run width, stringer widths), u32 top riser index, then flags centre mark, begin with riser, end with riser; it is read where the bottom elevation and width equal the sketch's. End with riser is 0 on exactly the three runs with one riser line more than risers; such a run's last tread runs to the last riser line. Monolithic runs with slanted risers are drawn as one body with one riser fewer than riser lines, the underside the type's structural depth square to the pitch below the inner corners, cut by the floor. 38 of 43 runs drawn; the 4 added equal Revit's geometry but for the upright run's nosing edge. Riserless and spiral runs keep their record box. Run type names equal the type part of Revit's ObjectType on all 49 exported flights. RE-217 (Revit 2025): the byte anchors are absent, so a run's sketch, riser height and ends are read by member name from its native records (StairsRun m_actualRunWidth, m_bottomElevation, m_beginWithRiser, m_endWithRiser; one StairsTreadInfo per tread, m_origin, m_actDepth, m_runDirProj, m_riserDir, m_runType), its construction from its StairsRunType record, and its type from its element record's reference list as on 2024, which equals Revit's flight type on all 75 runs measured (the R2025 stair models and both BIM4LCA office files). On puzzbobb's R2025 models 13 and 14 each flight's volume equals Revit's (4.4903 and 4.4289 ft3) and every vertex of Revit's body lies within 2e-6 ft of rvt-rs's surface; Revit's mesh adds a vertex pair at each riser. A run with treads and no risers, no nosing and ending with a riser is drawn as its separate treads, one solid each (an IfcTriangulatedFaceSet of their prisms), from its riser line to the next, its top at its riser's height and the tread thickness deep (RE-217 section 9): model 15's flight is Revit's, 4.449648 ft3 and every vertex within 2.3e-6 ft; Snowdon's riserless type has a 3 in nosing shaped by its nosing profile family and keeps its box. The spiral run (17), monolithic, keeps its record box. A monolithic run with upright risers and no nosing is drawn as one with slanted risers, since its risers run up the riser lines either way (RE-217 section 7): model 16's flight has Revit's volume with every Revit vertex on rvt-rs's surface, and so do 34 of the BIM4LCA office's 35 flights (Revit 2024), once a monolithic run's underside is cut at its StairsRun.m_extendBelowBase below its base where it starts at its stair's base (m_baseRiserIndex 0) and not at all where it starts on a landing (RE-217 section 8, read by member name on both releases); the office's spiral run is drawn as its 18 treads (RE-217 section 11): each tread's StairsTreadInfo holds the spiral's centre (m_origin, at the tread's top) and its radii and angles (m_bndBox), and each is an IfcExtrudedAreaSolid of an IfcIndexedPolyCurve with two arcs about the centre, the radial line at its riser line and a line parallel to the next riser line at the type's nosing length beyond it, its type's tread thickness deep, as Revit writes it: volume 4.540283 ft3 against Revit's 4.540287 and every Revit vertex within 0.00075 ft of rvt-rs's surface. Spiral runs are drawn on Revit 2024, with treads and no risers, not monolithic; one with a nosing only mirrored and climbing clockwise, as measured. Snowdon Towers (local only) is not re-measured since that rule. Revit 2024 and 2025. Revit 2026 and 2027 since RE-341: runs are read from their native records as on 2025, and their shape (the flight's predefined type) and stair property sets and quantities with them. Autodesk's rac_advanced 2026 and 2027 draw 10 runs that equal their 2025 saves', rac_basic's 2 are its 2025 save's, and rst_basic's one is its 2024 save's (the contributor's local pairs, bodies by ElementId; tools/re/bodies_across_saves.py holds the 2026 and 2027 runs to the 2025 save, which reads runs from native records as they do, because the 2024 save's byte-anchor reader finds 5 of rac_advanced's 10 runs and 1 of rac_basic's 2); in Revit's own held-out 2026 and 2027 exports one stair flight each leaves the record-box set and 15 more property values and 2 quantities are equal to Revit's (counts, Measure run 41988011289, head 1d5bbf03). Spiral runs (2024) and stair names (2025) are not read on 2026 and 2027.",
"user_impact": "Stairs export and display as steps instead of a box the height of the whole stair."
},
{
"id": "element-record-landing-slabs",
"area": "elements",
"name": "Monolithic stair landings drawn as their slab, from their own outline lines, their top and their type's thickness (Revit 2024 only); tread landings (not monolithic) drawn as their tread (Revit 2024 to 2027)",
"status": "partial",
"evidence": "native_stairs::native_landings; partition_stairs::scan_landing_lines; partition_schema_mvp::attach_landing_slabs and landing_outline (LANDING_BODY_BOTTOM_FIELD, LANDING_BODY_TOP_FIELD, LANDING_OUTLINE_SOURCE); ifc::export_content LANDING_SLAB_BODY_SOURCE; probes/examples/probe_re214_landing_outlines.rs; tools/re/landing_outlines_vs_ifc.py; tools/re/stair_bodies_vs_ifc.py; tools/re/plan_profiles_vs_ifc.py; reports/element-framing/RE-214-landing-slabs.md; native_stairs::native_tread_landings and partition_schema_mvp::landing_tread_body_from_fields (LANDING_TREAD_* fields); ifc::export_content LANDING_TREAD_BODY_SOURCE; probes/examples/probe_824_landing_loops.rs; RE-345 Revit 2025: reports/element-framing/RE-345-2025-beams-landings-arcs.md",
"notes": "A landing's element data holds bounded lines at its top, with gaps where its flights meet it; joined into chains and bridged straight across the gaps they are Revit's outline. Its top is StairsLanding.m_baseElevation, and its type is the one OST_StairsLandings type definition its element record names (RE-28), its stairs' landing type on all 22 BIM4LCA office landings. A monolithic type (StairsLandingType.m_hasMonolithicSupport) gives the slab's thickness, m_thickness, which is Revit's main underside. Measured on the BIM4LCA office (Measure run 40156315852): all 21 monolithic landings on each file drawn as their slab where they were their 12.5 to 14.2 ft record box; their top and outline Revit's; plan_profiles_vs_ifc slabs within 0.01 ft of Revit's outline 40 to 60 of 63 as built, 38 to 58 at building permit. Revit's underside also follows a flight's soffit where the flight meets the landing, which is drawn flat: the slabs are 100.4% to 104.7% of Revit's volume. A landing whose type is not monolithic but has a tread taken from its runs (m_hasTread, m_useSameTriserAsRun) is that tread (RE-214 \u00a77): the CurveLoop of GLines and GArcs at its top in its StairsLanding record, extruded down its stair's run type m_treadThickness, written as an IfcIndexedPolyCurve; the office's 3058084 is then Revit's body (1.462462 ft3 in both, every vertex within 0.0000022 ft; Measure 40181002275). Any other landing that is not monolithic keeps its box. Revit 2024, the release measured. On Revit 2025, 2026 and 2027 (RE-341, RE-345) only tread landings (not monolithic) are drawn: rac_advanced's 5 are its 2024 save's on each, none scored against a Revit export of a 2025, 2026 or 2027 file (the 28 Revit 2025 models read, puzzbobb's 24 and RE1's four, hold no tread landing and no landing slab; Measure run 42091457764, head 830a4d94), held to the 2024 save by tools/re/bodies_across_saves.py, which cannot catch an error that save shares. A monolithic landing stays its record box there, because its outline lines are read through scan_run_data, which reads 2024 only (STAIR_DIMENSIONS_SUPPORTED_REVIT_VERSIONS): rac_basic's one monolithic landing slab, which the 2024 save draws, is a box on 2025, 2026 and 2027, counted as left as a box.",
"user_impact": "Stair landings export as slabs about 1 ft thick at their own level, with Revit's outline, instead of boxes the height of the storey. On Revit 2025, 2026 and 2027 only tread landings are drawn; a monolithic landing stays its box."
},
{
"id": "element-record-wall-layers",
"area": "elements",
"name": "Walls drawn as their compound layers in their materials' shading colours (glTF and viewer, Revit 2024 and 2025)",
"status": "partial",
"evidence": "partition_materials::scan_material_appearances / appearance_at; partition_compound_structure::scan_type_layers / find_layers / scan_wall_flips; partition_schema_mvp::attach_wall_layers and element_layers_from_fields; ifc::IfcModel::element_layers; ifc::body_geometry::layered_extrusion_meshes; ifc::gltf per-layer nodes; probes/examples/probe_re53_wall_layers.rs; tools/re/wall_layers_vs_ifc.py (rvt-gltf GLB against Revit's IFC4 per-layer solids); reports/element-framing/RE-53-wall-layers.md",
"notes": "A material's object (01 00 00 00 + u64 id, tag 28 0a on 2024 and 6b 0a on 2025 at +0x47) holds, in its first ff x 8 frame, transparency, four pattern COLORREFs, the shading COLORREF and shininess; colour and transparency equal Revit's IFC surface style on 123 of 123 materials matched by name across Snowdon Towers, Core Interior, RE1 Architecture, Projeto1 and teste_export_2025. A wall, floor, roof or ceiling type's own element data holds a u32 layer count (framed by ff ff ff ff and tag a6 10 on 2024 / 0e 11 on 2025, or u32 k, k x 2d 00, u32 0 on 2025 floors and ceilings) and 37-byte layers: f64 width, u64 material or by category, u64 deck, u32 function; Snowdon 42 of 42 types give Revit's constituent sequence, Core Interior 4 of 4, RE1 its wall, floors and ceiling. A wall's data holds, after ff ff ff ff 01 00 00 00, its location line, a word and a flip flag; set puts the exterior right of the location line (RE-49's bounded line), on all 416 Snowdon walls whose outer layers Revit's IFC places measurably apart. The glTF export cuts the wall's body into one band per layer where the layers add up to its thickness within 0.02 ft. Measured end to end on Snowdon Towers (local only): rvt-gltf draws 883 of the 1,054 walls whose layers are read; against Revit's IFC4 per-layer solids (IfcOpenShell 0.8.5), every layer centre is within 0.001 ft on 851 of 862 comparable walls and within 0.126 ft on all (the 11 are one soffit type whose stud layer Revit cuts back), and 1,368 of 1,368 compared layer colours equal Revit's surface style colours. Status is partial: 165 Snowdon walls whose body is not as thick as their layers are drawn whole (#358); floors, roofs and ceilings are not drawn in layers; Revit 2025 walls are drawn in layers since RE-55, but no 2025 oracle wall has a layer whose material is unique, so their layers are measured only through the same house saved in 2024 (reports/element-framing/RE-55-wall-lines-2025.md); the IFC export writes these layers as IfcMaterialLayerSetUsage since RE-58 (row ifc-material-layer-sets); no licensed CI file has a 2024 wall with a coloured layer.",
"user_impact": "In the viewer and exported glTF, walls show their construction: each layer as a band in its material's colour instead of one grey block."
},
{
"id": "element-record-slab-layers",
"area": "elements",
"name": "Floors, roofs and ceilings drawn as their layers stacked top first in their materials' colours (glTF and viewer, Revit 2024 and 2025)",
"status": "partial",
"evidence": "partition_schema_mvp::attach_slab_layers (SLAB_LAYERS_FIELD) and element_layers_from_fields; ifc::ElementLayers::stacked; ifc::body_geometry::stacked_extrusion_meshes; ifc::gltf per-layer nodes; tools/re/slab_layers_vs_ifc.py; probes/examples/probe_re53_wall_layers.rs; reports/element-framing/RE-57-slab-layers.md",
"notes": "A floor, building pad, roof or ceiling with a type (RE-44) gets its type's layers (RE-53; roof types framed behind their name, RE-56), top first, where they add up to its record box's height within 1e-4 ft; the glTF export cuts its extruded body into one prism per layer from the top down. Measured end to end against Revit's own IFC4 exports (IfcOpenShell 0.8.5): Snowdon Towers (local only) 236 compared slabs with every layer's bottom and top within 1.4e-6 ft and 358 of 358 colours equal; 2024_Core_Interior 68 of 68 floors within 3.4e-6 ft, 69 of 69 colours; RE1 Architecture's 8 floors and ceilings (2025) cannot be measured by height because Revit styles each body with one material, and their 8 colours equal Revit's in its layer order. Status is partial: slabs whose layers do not add up to their box (tapered insulation, floors with taller boxes) and sloped roofs stay whole. The IFC export writes these layers as IfcMaterialLayerSetUsage since RE-58 (row ifc-material-layer-sets).",
"user_impact": "In the viewer and exported glTF, floors, roofs and ceilings show their build-up: finish, structure and insulation as coloured bands."
},
{
"id": "ifc-material-layer-sets",
"area": "ifc",
"name": "Material names by ElementId, and IfcMaterialLayerSetUsage for layered walls, floors, roofs and ceilings (Revit 2024 and 2025)",
"status": "partial",
"evidence": "partition_materials::name_at / scan_material_names (material_name_frame_tag, material_name_end_tag, NAME_PARAMETER); partition_schema_mvp::attach_wall_layers / attach_slab_layers (layer names); ifc::material_layer_sets_from_layers and material_layer_set_usage; ifc::IfcModel::material_layer_usages; ifc::step_writer IFCMATERIALLAYERSETUSAGE; ifc::scene_graph::PanelLayers; probes/examples/probe_re58_material_names.rs; tools/re/layer_sets_vs_ifc.py; reports/element-framing/RE-58-material-layer-sets.md; reports/element-framing/RE-61-system-family-names.md; ifc::layer_materials_without_layer_sets (RE-88), entities::MaterialConstituentSet names, tools/re/wall_materials_vs_ifc.py, reports/element-framing/RE-88-wall-materials-without-layer-sets.md; partition_materials::scan_category_material (CATEGORY_MATERIAL_FRAME, RE-91), reports/element-framing/RE-91-category-material.md; partition_materials::native_category_material (RE-206), probes/examples/probe_re206_category_styles.rs, reports/element-framing/RE-206-category-styles-and-nested-visibility.md",
"notes": "A material's name is in its own object (RE-53's 01 00 00 00 + u64 id, class tag at +0x47): in its own name field after two to four zero u32s; or, where that field holds parameter entries first (strings i64 id + u32 n + UTF-16, integers i64 id + u32), as the one u32 n + UTF-16 ending at the first ff ff ff ff 17 0c (2024) or 6b 0c (2025) past the tag; or in a framed string (ff ff ff ff 49 01 / 5c 01) or an i64 -1001203 entry further on. Copies that disagree, and names read for two materials, are dropped. Named: Snowdon Towers 220 of 220, 2024_Core_Interior 86 of 86 (RE-125: a name kept after a run of parameter entries, closed by 8 zero bytes, a u64 ElementId and 0xff x8), the Revit 2026 flowbim.ee house 148 of 148, RE1 Architecture 69 of 69, Projeto1 and teste_export_2025 114 of 114, the MIT tutorial house 171 of 171 in 2024 and 2025. Every named material Revit's own export styles by that name has Revit's colour for it, 174 of 174. The IFC export writes a type's layers as IfcMaterialLayerSet (one per type name and layer sequence; each layer its material and thickness) and each element's IfcMaterialLayerSetUsage: floors, roofs and ceilings AXIS3 NEGATIVE from their top, walls along the local axis their exterior faces, exterior layer first; only where the body is an extrusion whose extent across the layers equals their sum within 1e-4 ft. Measured end to end (IfcOpenShell 0.8.5) against Revit's own exports: layer names Revit's, in Revit's order, on 3,321 of 3,322 Snowdon layers, 89 of 89 Core Interior and 37 of 37 RE1; whole sets on Revit's body within 0.001 ft on 1,196 of 1,207 Snowdon elements (the 11 are RE-53's soffit walls whose stud layer Revit cuts back), 403 of 403 Core Interior (88 before RE-91), 15 of 15 RE1. RE1's 2025 export writes its own 4 layer sets, and rvt-rs writes the same 4 with the same thicknesses in the same order; Revit's own usage disagrees with its own body on RE1's 6 ceilings and 2 floors, and rvt-rs follows the body. Status is partial: sloped roofs, walls drawn whole (#358) and slabs whose layers do not add up to their box get no layer set; Snowdon 1924356 and 8 of Core Interior's family materials are unnamed; releases before 2024 read no names and keep the string heuristic for the IFC's material list, which on 2024 and 2025 is the file's named material records (#34); family instances' materials are their own entry (RE-82, RE-200 to RE-206). RE-61 (2026-09-24): each set is named Family:Type as Revit names it; Revit stores no system family name, and a type with compound layers is a Basic Wall, Floor, Compound Ceiling, Basic Roof or Pad by its category (partition_schema_mvp::layered_system_family); set names equal the Family:Type of Revit's element names on 1,210 of 1,210 Snowdon elements, 403 of 403 Core Interior (88 before RE-91) and 15 of 15 RE1, whose own four layer sets carry the same names. RE-88: Revit's export associates a wall's materials by its type's layers alone, one layer its IfcMaterial and several an IfcMaterialConstituentSet of the layers, exterior first, a material's k-th occurrence named ' (k)' (143 of 143 and 823 of 824 Snowdon walls with a layer set). A wall whose body is not a layer set (tapered, curved, cut, profiled) now gets that association where its layers and their names are read: 95 of Snowdon's 111 walls without one, all Revit's (59 constituent sets, 36 materials), walls whose data does not place them included (their type's layers, no exterior side); the rest have a layer taking its category's material, which Revit writes 'Default Wall' and is not read (15), or are in-place (1). Core Interior: 4 of 360 walls get Revit's material; its other 356 walls' layers take the category's ('Default Wall'). RE-91: the document's object styles hold each category's material (i64 BuiltInCategory, ff x8, u32 1, ff x8, u64 material; Revit 2024). Where the Walls entry is set, a wall layer that takes its category's material takes it: all 360 Core Interior walls carry Revit's material (356 'Default Wall', none before). Snowdon Towers and the MIT house leave the entry unset (0), and what Revit writes then is not read. RE-206 (2026-10-21): where the entry is unset or not read (Revit 2025 and later), the category's material is the one its GStyleElem graphics styles name (GStyle.m_materialElemId): Walls 'Default Wall', Floors 'Default Floor', Roofs 'Default Roof' on Snowdon Towers; its 16 such walls and the 117 walls of the R2025 models now carry Revit's 'Default Wall' (tests/element_materials.rs::r2025_walls_take_their_category_material). An IfcSpace is associated with no material in the default export, because IFC4's IfcRelAssociatesMaterial.AllowedElements takes none; rvt-ifc --revit-set-placement keeps the material Revit's export associates with each, and that output breaks the rule as Revit's does (42 spaces on each BIM4LCA office file, 2 on each terrain file; Griffin, 2026-11-05: valid IFC4 by default, Revit's behind the flag; #1430).",
"user_impact": "Exported IFC carries each wall's, floor's, roof's and ceiling's build-up (every layer's material and thickness, placed on the element) for quantity take-off and energy tools, and the viewer lists a selected element's layers."
},
{
"id": "element-record-wall-centreline-bodies",
"area": "elements",
"name": "Wall bodies from their centreline at their type's thickness (Revit 2024 and 2025)",
"status": "partial",
"evidence": "partition_compound_structure::wall_orientation / scan_wall_orientations; partition_schema_mvp::attach_wall_layers (m_wall_axis_*, m_wall_type_thickness) and wall_axis_from_fields; ifc::export_content::wall_centreline_body (BodySource partition_wall_centreline); tools/re/wall_bodies_vs_ifc.py (rvt-gltf GLB against Revit's IFC4 bodies); reports/element-framing/RE-54-wall-bodies.md; partition_compound_structure::scan_wall_lines (WALL_LINE_SUPPORTED_REVIT_VERSIONS); reports/element-framing/RE-55-wall-lines-2025.md; partition_compound_structure::scan_wall_join_partners, element_record_wall_joins::butt_joins (m_wall_join_*_reach / _wall / _through; JoinReachStart / JoinReachEnd, JoinStartWallElementId / JoinEndWallElementId, JoinStartRunsThrough / JoinEndRunsThrough), scene_graph::element_info_panel joins; element_record_wall_joins::layer_reaches (m_wall_join_*_layer_reaches), ifc::export_content::layered_wall_profile (BodySource partition_wall_centreline_layer_joins), body_geometry::clip_ring_to_band, probes/examples/probe_re71_layered_joins.rs, tools/re/wall_layer_joins_vs_ifc.py, reports/element-framing/RE-71-layered-wall-joins.md, probes/examples/probe_re70_wall_join_lists.rs, tools/re/wall_join_lists_vs_ifc.py, reports/element-framing/RE-70-wall-join-lists.md; element_record_wall_joins::tee_join, probes/examples/probe_re73_tee_joins.rs, tools/re/wall_tee_joins_vs_ifc.py, reports/element-framing/RE-73-wall-tee-joins.md; element_record_wall_joins::angled_layer_edges / angled_tee_edges (m_wall_join_*_layer_edge_reaches), tools/re/wall_angled_joins_vs_ifc.py, reports/element-framing/RE-74-angled-wall-joins.md; partition_beam_axes::bounded_arc_at / scan_first_bounded_arcs, partition_compound_structure::scan_wall_arcs, partition_schema_mvp::WALL_ARC_FIELDS / wall_arc_from_fields, ifc::export_content::wall_arc_outline (BodySource partition_wall_arc), probes/examples/probe_re75_wall_arcs.rs, tools/re/wall_arcs_vs_ifc.py, reports/element-framing/RE-75-curved-walls.md; partition_compound_structure::wall_type_face_angles / scan_wall_type_face_angles (WALL_FACE_ANGLES_FRAME), partition_schema_mvp::WALL_EXTERIOR_FACE_ANGLE_FIELD / wall_taper_from_fields, ifc::export_content::tapered_wall_body / tapered_wall_solid (BodySource partition_wall_tapered_section), probes/examples/probe_re86_tapered_walls.rs, tools/re/tapered_walls_vs_ifc.py, reports/element-framing/RE-86-tapered-walls.md; partition_compound_structure::wall_face_angles_frame (WALL_FACE_ANGLES_FRAME_2025), probes/examples/probe_re213_wall_face_angles_2025.rs, reports/element-framing/RE-213-tapered-walls-2025.md; RE-222 native T joints and orientation: native_walls::native_walls and ::tee_reach, partition_schema_mvp::attach_native_tee_reaches, probes/examples/probe_wall_curves.rs, probes/examples/probe_wall_native_orientation.rs, probes/examples/probe_wall_type_layers.rs, tools/re/wall_ends_list.py, tools/re/wall_curve_ends_vs_ifc.py, reports/element-framing/RE-222-wall-native-joins.md; RE-223 T-joint cores: native_walls::NativeWall::shells, element_record_wall_joins::WallLine::shells and tee_join, probes/examples/probe_wall_type_core.rs, reports/element-framing/RE-223-wall-tee-cores.md; RE-267 wall tops: native_walls::WallRecords::top_cutters, partition_schema_mvp::WALL_TOP_CUTTERS_FIELD / wall_top_cutters_from_fields, ifc::export_content::wall_tops (BodyHeightSource wall_top_cut_at_covering_floor), probes/examples/probe_1067_native_dump.rs, tools/re/wall_top_cover_vs_ifc.py, reports/element-framing/RE-267-wall-top-cover.md; RE-320 stepped wall tops: native_walls::WallRecords::pair_only, partition_schema_mvp::WALL_TOP_PAIR_ONLY_FIELD / wall_top_pair_only_from_fields, ifc::export_content::wall_tops (BodyHeightSource wall_top_stepped_at_covering_floor, TopCoverElementIds), body_geometry::plan_outline, reports/element-framing/RE-320-stepped-wall-tops.md; RE-322 corner ends: element_record_wall_joins::corner_joins and CornerEnd, native_walls::NativeWall::join_types, partition_schema_mvp::attach_wall_corner_reaches, probes/examples/probe_re322_wall_corners.rs, tools/re/wall_corner_ends_vs_ifc.py, reports/element-framing/RE-322-wall-corner-order.md; RE-340 embed hosts: ifc::saved_meshes::attach_scoped_with_control (embed_hosts, raise_embed_host), native_wall_cuts::wall_cut_steps, probes/examples/probe_1385_wall_saved_mesh.rs, probes/examples/probe_1385_cut_partners.rs, tools/re/wall_stub_bodies_vs_ifc.py, reports/element-framing/RE-340-embedded-wall-stubs.md; RE-336 wall bases: native_walls::WallRecords::base_cutters, partition_schema_mvp::WALL_BASE_CUTTERS_FIELD / wall_base_cutters_from_fields, ifc::export_content::wall_tops::cut_wall_bases (BodyBaseSource wall_base_sloped_at_covering_floor and wall_base_cut_at_covering_floor, BaseCoverElementId, BaseCoverRefusal), ifc::body_geometry::between_surfaces_mesh, tools/re/slab_bodies_vs_ifc.py, reports/element-framing/RE-336-sloped-footings.md; RE-337 wall ends: ifc::export_content::wall_tops::extend_wall_ends (BodyEndSource wall_end_stepped_to_joined_walls, EndCoverElementId, BodyEndRefusal), reports/element-framing/RE-337-wall-ends-at-the-base-wall.md; RE-348 end join order: native_walls::EndJoins (JoinEndGStep.m_realJoined, the VWallDriver.m_pCrv curve), partition_schema_mvp::wall_end_joins_from_fields (m_wall_curve, m_wall_end_joins_start and m_wall_end_joins_end), ifc::export_content::wall_tops::read_end, strips_of and followed_wall, probes/examples/probe_1410_wall_end_steps.rs, reports/element-framing/RE-348-wall-end-join-order.md; RE-349 base covered in part: ifc::export_content::wall_tops::covered_pieces and base_cut_piece (BodyBaseSource wall_base_cut_at_floor_covering_in_part and wall_base_sloped_at_floor_covering_in_part, BaseCoverRefusal partly_covered_plan_not_read), reports/element-framing/RE-349-wall-base-covered-in-part.md",
"notes": "The bounded line a wall's data stores (RE-49) is its centreline whatever its location-line setting: Revit's IFC4 body lies exactly half the type's layer sum (RE-53) either side of it on 964 of Snowdon Towers' 1,054 walls, all with 1 in the word after the setting; none of the 23 with 0 or 2 is centred. A 2024 wall with word 1 is built as that rectangle where the record box does not already give it: an axis-parallel wall keeps RE-26's trimmed run and keeps its box when the box is thinner than the type (a cut wall); an angled wall is the rectangle its box closes on (1e-4 ft), or runs joint to joint unless its box exceeds that rectangle's by more than 2 x max(T, 1 ft). Measured end to end on Snowdon Towers (local only) with rvt-gltf against Revit's IFC4 bodies (IfcOpenShell 0.8.5): angled walls' faces within 0.001 ft on 75 of 102 (0 before) and ends on 13 (1 before); axis-parallel faces on 927 of 976 (918 before); per wall 71 better, 1,003 unchanged, 4 worse; walls drawn in layers 967 (883 before). Core Interior is unchanged (IFC byte-identical but for timestamps). Status is partial: angled walls' ends at joints are not modelled (Revit butt-joins 115 of 156 end faces at two-wall joints), cut, profiled and word 0 walls keep their box (word 2 walls are tapered, drawn since RE-86), and releases before 2024 have no location line read. On Revit 2025 (RE-55) the same fields read the same on all 50 walls of a house saved in 2024 and 2025; against Revit's own 2025 exports, RE1 Architecture's 7 and Projeto1's 1 axis-parallel walls stay exact and 2 of teste_export_2025's 3 angled walls, drawn as boxes up to 38 ft off before, have Revit's faces and ends (the third is the wall that export shows in a later state, RE-44). RE-70 reads which wall runs through a butt join from the walls' own join lists (07 00 00 00, a per-document tag, 02 00 00 00, a zero u32 on 2025, a count and u32 + u64 ElementId + u32 entries): where two centrelines end at one point, the wall naming the other reaches its far face and the named one stops at its near face. On Snowdon Towers this agrees with every clean joint in Revit's IFC4 bodies (194 perpendicular and 18 angled ends, 2 undecided, none contradicted), and on five 2024 and 2025 files with the record box at 1,110 axis-parallel ends (47 undecided, 2 contradicted, both irregular in Revit's body). Ends take it only where both walls have a single layer: Revit cleans layered joins layer by layer (631 of 667 multi-layer ends irregular, 0 of 158 single-layer). Snowdon's walls with both of Revit's ends go from 338 to 346 axis-parallel, 9 better and none worse; Core Interior, RE1 and the MIT house are unchanged. Layered joins, angled joins at other than a right angle and T junctions keep their ends. Every end the join lists decide, layered or not, names its partner wall and whether it runs through in the IFC and in the viewer's element panel: 825 ends on 600 of Snowdon's 1,078 walls, 236 on 185 of Core Interior's 360 (since RE-322 an end at a corner of three or more walls names one only where a single perpendicular wall decides it, and a mitre none). RE-71 draws layered joins layer by layer: counted from the outside of the corner, layer i of the through wall reaches the outer edge of the partner's layer i and layer i of the stopping wall its inner edge. It is applied where both walls show the same layer functions in the same order from the corner and share base and top, 528 Snowdon ends, of which 521 are right in every layer (1,382 of 1,402 layer ends); the body is then an IfcArbitraryClosedProfileDef staircase. Snowdon walls with both of Revit's ends: 516 of 976 axis-parallel (346 before) and 18 of 102 angled (13); GLB layer ends matching Revit's body 3,925 of 5,634 (3,078). Six Snowdon ends Revit draws as clean butts, which no field read separates (the join-list entry words and k were checked): 16 Snowdon layer ends get worse. RE1's one layered joint is a clean butt too, but RE1's export (IFC2X3 CV2.0, Revit 2026.2) writes each wall as one IfcRectangleProfileDef extrusion and cannot show layered ends; against it one wall's end gets worse. RE-73 draws T joints, where a wall's end lies part way along one other perpendicular wall's centreline at least half its width from that wall's ends: counted from the face it meets, each layer passes the other wall's layers of a larger function number and stops at the first of an equal or smaller one, and a single-layer wall stops at the face. On Snowdon 280 of 313 measured T ends are right in every layer (960 of 1,025 layer ends); walls with both of Revit's ends 675 of 976 axis-parallel (516 before) and 18 of 102 angled (unchanged); GLB layer ends 4,290 of 5,634 (3,925). 16 Snowdon T ends are clean stops at the face, which nothing read separates (wall types, the record box, RE-26's trims, the join lists, heights and layer materials were checked): 13 Snowdon walls lose an end they had. RE1's three T ends are clean stops in its export, which writes each wall as one rectangle; against it 3 of RE1's 7 walls lose an end. Core Interior's 202 T ends are right and its bodies unchanged; each now names the wall it stops against. RE-74 applies RE-70's, RE-71's and RE-73's joins where walls meet at 45 to 135 degrees, each layer ending where its two edges meet the other wall's line (a slanted IfcArbitraryClosedProfileDef edge). Revit draws Snowdon's 82.5 to 114.5 degree corners this way and none of its 14 L ends at sharper corners (7.5, 24.5 degrees) or shallower bends (148 to 172.5 degrees). Snowdon walls with both of Revit's ends: 34 of 102 angled (18 before), 689 of 976 axis-parallel (675); every angled L join drawn right along every layer edge (48 edges), 18 of 22 angled T joints (187 of 195 edges); GLB layer ends 4,394 of 5,634 (4,290); one wall worse (its interior finish). The other local files are byte-identical. RE-75 reads a curved wall's location arc: the RE-49 record with u64 1 before its tag (0 for a line) holds start and end angle, unit X and Y axes, radius and centre. On Snowdon's 24 walls with an arc axis in Revit's export, centre and radius match within 0.001 ft; each is drawn as the ring sector R +/- T/2 (IfcArbitraryClosedProfileDef, chords within 0.0005 ft, BodySource partition_wall_arc): faces within 0.001 ft on 23 (0 before), ends within 0.625 ft on all 48 (untrimmed at joins), median footprint overlap 0.95 (0.03 before). wall_bodies_vs_ifc.py scores walls with an arc axis by radius and angle as their own kind. RE-86 reads a wall type's three face angles (after u32 2, eight zero bytes, f64 0.7 and a count of 3 on Revit 2024; twelve zero bytes on 2025, RE-213) and takes a wall whose orientation word is 2 as tapered where its type stores [0, a, 0], 0 < a < 45 degrees: on Snowdon every such wall Revit tapers leans its exterior face by a (10 degrees), wider at the base, with its interior face vertical and the type's thickness about its line at the top. Each is drawn as that trapezoid extruded along its line (BodySource partition_wall_tapered_section), checked against the record box as a vertical wall T + H tan(a) thick on the line moved towards the exterior: 19 of the 20 walls Revit tapers within 0.001 ft of its body across the wall at five heights and the 20th within 0.052 ft (none within 0.1 ft before); GLB angled walls with both faces within 0.001 ft 91 of 94 (75), 24 walls better and none worse; every other local file byte-identical. RE-213: on Snowdon saved by Revit 2025 the same 19 of 20 within 0.001 ft across (0 before), 24 GLB walls better and none worse, every other 2025 file byte-identical. Slanted walls (word 0, their angle in the wall's own data) keep their box. Since RE-222 a wall's end where another wall meets it with its middle stops half that wall's thickness short, read from the wall's native record (Revit's end on 315 of the BIM4LCA office's 396 such ends as built, against 289 for the join lists), and a wall its partition data gives no orientation takes the native word and flip: the office as built has 428 of 607 walls with both ends within 0.001 ft of Revit's (412 before) and 377 of 589 at building permit (374). Since RE-223 a layered wall's core runs through the other wall's layers outside its core at a T joint, from the type's native CompoundStructure: 482 of 607 as built and 422 of 589 at building permit. Since RE-322 a corner of three or more walls is read from the order the record lists the walls in, and a mitre of two single-layer walls ends on the line through its corners: 510 of 607 as built and 430 of 589 at building permit. Since RE-267 a wall's top is cut at the underside of the floor, roof or footing its top join or a cut pair names, where that element is drawn as a plain extrusion, its underside lies between the wall's base and top and its outline covers the whole of the wall's plan, clear of its holes and openings: on the BIM4LCA office 64 of the 65 tops Revit cuts as built and 70 of 70 at building permit are then Revit's (Measure run 41092512565), no other wall's base or top moves on any model, and the exports of Core Interior, RE1 Architecture and the R2025 models are byte-identical. Since RE-320 a wall such an element covers in part is drawn stepped: the wall's own plan up to the lowest underside and, over the part of the plan the elements do not cover, convex pieces up to the next underside or the wall's top (49 walls as built, 46 at permit). rvt-rs's top is then Revit's over the whole plan on 583 of 607 walls as built (544 before) and 571 of 589 at permit (530 before), the full-height area it draws where Revit cuts falls from 1915.8 to 238.2 ft2 as built and from 1888.1 to 38.1 ft2 at permit, and no wall that was equal moved. An element that only a cut pair names (never the top join) cuts the top only where it reaches it: three walls as built whose slab ends 0.984 ft below their top are left whole, as Revit leaves them. The one wall as built that Revit cuts although 0.0243 ft2 of its plan lies outside the floor, inside an abutting wall, keeps its full height, as do the walls whose layers Revit ends at different heights. A cut or stepped wall gets no Height, which Revit's export omits on 2 of the cut walls as built and 4 at permit, on 6 of the 49 stepped walls as built and on 3 of the 46 at permit. A wall that embeds a curtain wall (WallEmbedWallGStep) is drawn from the mesh Revit saved for it where that mesh starts at least 0.5 ft above the wall's base, which is where Revit has cut away the end stubs the curtain wall does not span and raised the wall's base (RE-340): the lowest vertex of the saved mesh is Revit's lowest point to within 0.001 ft on 113 of 113 such walls of the BIM4LCA office as built and at building permit, and the cut partners' records are not a signal (every raised host's stubs lie inside its partners' boxes, and so do those of three hosts Revit leaves whole). Of the 14 hosts Revit raises, 6 as built and 8 at permit, all are drawn from their mesh and every base is Revit's (Measure run 41973316830): 12 of the 14 meshes are Revit's body, and the two of 2177212 are 1.0% under it in volume, a strip 0.114 ft shorter than Revit's. A wall with an opening hosted in it, a Tag shared with another entity, a base cut at a floor (#1384) or a mesh that did not decode whole keeps its body, and the rule applies on Revit 2024 to 2027 only (a Revit 2023 or earlier wall record gives no embed step), measured on the Revit 2024 office files alone. RE-336 (#1384): a wall whose base join names one floor or footing that covers its whole plan is cut at that element's top, level or along the plane of its shape-edited corners, as a solid between that top and the wall's own. On the BIM4LCA office 12 of the 14 Basement walls Revit raises as built (the 4 on level floors and 8 of the 10 on sloped footings; 12 of 16 at permit) then have Revit's lowest point (598 of 607 walls with Revit's base and top as built, from 586; 577 of 589 at permit, from 565); no wall's top moved and no other model's wall moved. RE-337 (#1396) and RE-348 (#1410, #1409): a wall with an edited elevation profile (a WallProfileOpening voids it) that is a plain rectangle along a model axis, drawn from its record box and with join trims, has an end drawn, at each height of the wall, to the face of the first wall of JoinEndGStep.m_realJoined of that end (the walls Revit joins there, in the order its record lists them) that stands at that height (a plain rectangle, a layered profile, or one whose top a floor cut in steps, read by its pieces up to its own top), in place of the face of the Level_01 wall its record's join names, which overlaps the wall by 0.66 ft of 9.5. The wall is its own plan to its top and one column from its base for each distance the end reaches beyond the next (BodyEndSource wall_end_stepped_to_joined_walls; EndCoverElementId; JoinTrimStart and JoinTrimEnd stay the record's), and the cut of its base (RE-336, RE-349) must still resolve over the longer plan. The order rule rests on 4 walls in one project (8 ends), of which only the 4 as-built ends depend on the order (3 orderings, fitted after about four alternatives had been tried), counted by exported.wall_ends_order_dependent, on its own release list (Revit 2024): the order of m_geomJoined, the last wall that stands and the least ElementId each give a different end from Revit's on at least three of them. An end whose joined walls are not all read, whose top is not known, that do not meet the end or stand over the wall's whole height, whose face is inside the record's box or that would reach further at a greater height than below is kept; it carries one BodyEndRefusal (counted in exported.wall_end_refusals and logged as wall_end_extension_refused: joined_wall_not_read, joined_wall_top_not_read, joined_wall_does_not_meet_the_end, joined_walls_do_not_reach_the_wall_height, joined_wall_face_inside_the_wall, joined_wall_faces_overhang_the_lower_end, base_cut_lost_on_extended_plan, base_not_cut_over_the_extended_plan, base_solid_not_made_over_the_extended_plan, wall_stands_in_the_added_end) only where the faces of the joined walls read before the refusal show the end short of or past them, and otherwise only a count (exported.wall_end_reads_unmarked, which also holds end_join_curve_not_at_the_box_end and end_join_list_not_read, never marked), since a marker on a wall that already has Revit's end says the rule failed where nothing needed doing; joined_wall_face_inside_the_wall is measured and marked (2 walls at permit), end_join_curve_not_at_the_box_end and joined_walls_do_not_reach_the_wall_height were seen on 2 walls each (the office as built, Snowdon Towers Architectural), the others have no measured instance. A wall with no join trim is left, and a rule that did not ask the record's joins drew a Snowdon Towers soffit wall 0.1016 m longer than Revit's. On the BIM4LCA office (Measure 42101944733, 006f5f98 against main), walls 2057668, 2057670, 2058499 and 2058501 take it as built and at permit and have Revit's lowest point (2058499 and 2058501 at permit were 0.044 ft off) and Revit's end at every height (no point of their plan rows above Revit's); their volume is 0.209 ft3 over Revit's as built and 0.207 at permit, which is the far end's sloped top that the profile does not reach (#1473), not the ends; 2056705 and 2056770 at permit keep their ends, which Revit cuts back above 182.087 ft and this does not. RE-349 (#1411): where no element a wall's base join names covers the whole of its plan and one covers part of it, the base is cut at that element's top over the covered part (the convex pieces of the plan inside its outline) and the rest of the plan stands from the wall's own base (BodyBaseSource wall_base_sloped_at_floor_covering_in_part or wall_base_cut_at_floor_covering_in_part, BaseCoverRefusal partly_covered_plan_not_read where the covered part is not read); a wall whose base join names an element that covers the whole plan is decided by those alone. Measured on 2 walls in one file (2058499 and 2058501 as built, Measure 42099826920 at c413f382): Revit's lowest point and end, and a volume 0.147 ft3 under Revit's, the same as wall 2057670's to 3e-5 ft3 (the same end, so the same omitted step and far-end stub); the level top, a partial cover with no end extension and a clockwise or concave ring have no measured wall. No other wall's body in either office file changes, and no other model takes the rule: in the unfiltered run 42111477633 (e5ff94f4, 111 exports) no other export has a base cut in part, and in the verdict run 42119702779 (2272c31c, 68 exports) only the two office files differ from main.",
"user_impact": "Angled walls export and display as walls of their real thickness along their line instead of as the box around them, and more walls show their layers."
},
{
"id": "revit-global-ids",
"area": "ifc",
"name": "Revit's own IFC GlobalIds for elements, rooms and storeys, rebuilt from Global/History and Global/ElemTable",
"status": "partial",
"evidence": "revit_global_ids::EpisodeHistory / revit_ifc_global_id / revit_global_ids; ifc::IfcModel::global_ids (RevitGlobalIds); tests/revit_global_ids.rs against 2024_Core_Interior_slim.ifc and the four RE1 exports (CI tier 2); probes/examples/probe_re48_revit_global_ids.rs; reports/element-framing/RE-48-revit-global-ids.md; RE-108 (Revit 2023): revit_global_ids::RECORD_EPISODE_OFFSET_28, tools/re/global_ids_vs_ifc.py, reports/element-framing/RE-108-global-ids-2023.md; RE-220: revit_global_ids::stored_global_ids, RevitGlobalIds::{project, site, building}, probes/examples/probe_878_stored_guids.rs, probes/examples/probe_878_project_guids.rs, tools/re/stored_guids_vs_ifc.py, tools/re/project_guids_vs_ifc.py, reports/element-framing/RE-220-stored-global-ids.md",
"notes": "Global/History lists every editing episode's GUID newest first (u32 count at +0x0e, a u32-counted table at +0x66, then the count again and count entries of a Windows-order GUID and the byte 0x28); a 40-byte Global/ElemTable record holds its element's episode number at +0x18, whose GUID is entry count-1-episode. The GlobalId is that GUID with the record's first ElementId XORed into its last 32 bits (an element whose id has since changed, RE-41, keeps its first), in IFC base-64. Per Tag against Revit's own exports, every element rvt-rs exports that Revit's holds has Revit's GlobalId: Core Interior 854 of 854, RE1 Architecture/Mechanical/Plumbing/Electrical 73/73/123/12, teste_export_2025 8, Projeto1 2, Snowdon Towers 5,945 of 5,945 (local only), with no duplicate GlobalId in any export. Rooms take the same rule (Core 116 of 116, RE1 11 of 11), and a storey takes its Level's (Core 15 of 15, Snowdon 18 of 18 since RE-51). Revit's own synthesised parts (stair components, a ramp's flight, extra slab pieces) have GlobalIds of Revit's making and are not written by rvt-rs; a Tag carried by several rvt-rs entities gives the rebuilt GlobalId to the first only. Revit 2023 and earlier (28-byte ElemTable records) keep generated GlobalIds, as do openings, further pieces of an element, relationships and property sets. RE-220 (#878): the project, site and building take the GlobalIds the file stores, which Revit's export writes: under IFC_PROJECT_GUID, IFC_SITE_GUID and IFC_BUILDING_GUID (-1019002, -1019004, -1019003) on BIMcollab's Revit 2015 example, and as an untagged triple related as revit-ifc's fake ElementIds -16, -15 and -14 relate them (site = project XOR 2, building = project XOR 1) on both BIM4LCA office files: 3 of 3 on each where 0 were. A storey takes the IFC_GUID value its Level's id stands twice before, 58 bytes apart: BIMcollab's 5 of 5 storeys, where none were. A file that stores none keeps generated project, site and building GlobalIds: their base GUID is none of the elements', the history's or BasicFileInfo's (measured negative). Since #400 a generated GlobalId is a SHA-256 of a fixed namespace, the document's Unique Document GUID and the entity's own identity (ElementId and piece, filling element, participants), never its position in the file: Snowdon Towers exported before and after RE-75's curved walls keeps all 20,149 GlobalIds (7,740 before #400). Status is partial: Revit 2023 and earlier, the project, site and building of a file that stores none, and storeys whose Level is not recovered keep generated GlobalIds. Where it applies it is exact against Revit's own exports of two releases (Core Interior 2024; RE1 2025), CI-gated.",
"user_impact": "An IFC file from rvt-rs and Revit's own IFC of the same model name every element, room and storey with the same GlobalId, so diffs line up and BCF issues, clash results and federated links carry over between them."
},
{
"id": "ifc-type-objects",
"area": "ifc",
"name": "IFC type objects and IfcRelDefinesByType for every element named Family:Type",
"status": "partial",
"evidence": "ifc::IfcModel::element_type_ids; ifc::RevitGlobalIds::types; step_writer type_entity_for; tools/re/type_objects_vs_ifc.py; reports/element-framing/RE-110-type-objects.md",
"notes": "RE-110 (2026-09-28): every element rvt-rs names Family:Type whose Revit type it reads (RE-28, RE-38, RE-44, RE-109) is typed through IfcRelDefinesByType by one IFC4 type object per Revit type: the occurrence's IFC4 type entity (IfcWallType, IfcDoorType, IfcColumnType and so on; openings, spaces, reinforcing bars and railings are not typed), named Family:Type, Tag the type's ElementId, PredefinedType the occurrence's, GlobalId the one the type's UniqueId gives (RE-48, RE-108). Per Tag, against every element Revit's own export types that rvt-rs exports: Core Interior 854 of 854 typed with Revit's name, Tag and entity; Snowdon Towers Architectural 5,803 of 5,812 typed, all 5,803 with Revit's name (local only); RE1 Architecture 72 of 73 with Revit's name; the Revit 2023 projects Exemplo_data 37 of 37 and modelo_bim 37 of 37 with Revit's type Tag since RE-112, their names differing only by the system family's language. Differences, all measured: the system family name is English (RE-63) where the Portuguese exports write Parede basica; Revit tags a curtain panel type with a panel's own id (Snowdon 462); Revit's IFC4 writes plumbing fixtures as IfcFlowTerminal with IfcDistributionElementType; and Revit's exporter often writes several type objects for one Revit type - one per instance, whose GlobalId is that instance's with bit 0x08 of byte 10 flipped (Core 164 column types), or others whose GlobalIds are not stored in the file - so type GlobalIds agree on Core 438 of 854 typed elements and Snowdon 2,816 of 5,803. rvt-rs writes one type object per Revit type and does not guess the split. Status is partial: type objects carry no property sets or representation maps, and 2023 layers are not written as layer sets. RE-286 (2026-10-31): a type object carries its entity's common set as Revit's IFC4 exports write it on the type itself: the type's FireRating, LoadBearing for the structural column and framing categories, and a stair or flight type's dimensions; 34 of the BIM4LCA office's 182 type values as built and 29 of 154 at permit, none different. No IsExternal on a type object: Revit's 24.0.5 and 25.0.2 exports write it, its newer ones (RE1 Architecture's 26.2, the held-out models') do not. A type whose PredefinedType is USERDEFINED names itself in ElementType, which IFC4's CorrectPredefinedType asks and which Revit's export leaves empty on the same type objects (measured on the BIM4LCA office, 2026-11-05: its own export breaks that rule on them), and an occurrence whose PredefinedType is USERDEFINED with no ObjectType read is written without a PredefinedType (#1430).",
"user_impact": "IFC exports group elements under the same type objects Revit's export names, so type-based schedules, filters and quantity takeoffs in IFC tools work on rvt-rs output."
},
{
"id": "element-record-revit-class",
"area": "elements",
"name": "Each record-backed element's Revit class, from the schema's definition ordinal (RE-76)",
"status": "partial",
"evidence": "formats::schema_classes (the Formats/Latest grammar, whole stream since #410); PartitionElementRecord::class_tag (+0x4a); partition_schema_mvp::attach_revit_classes; probes/examples/probe_re76_schema_class_tags.rs; reports/element-framing/RE-76-schema-class-tags.md",
"notes": "A class's serialization tag is its definition ordinal in the file's own schema (12 for the first, one more per definition, top-level or inline), and an element record's u16 at +0x4a is its class under that numbering. The grammar reads the whole schema on 2016, 2024, 2025 and 2026 samples (3,792 to 4,690 classes). Every record of ten categories resolves on Core Interior, RE1 Architecture and Snowdon Towers: walls SWall, ArcWall, FaceWall; floors Floor; rooms RoomElem; roofs ProfileRoof; stairs StairsElement; families FamilyInstance or, for type symbols, FamilySymbol. Snowdon's 32 ArcWall records are exactly the 32 walls RE-75 found storing an arc. Status is partial: SchemaTable.tag and the Global/Latest walker still use the u16 after each class name (#154).",
"user_impact": "Every exported element carries RevitClass, so curved walls, face-based walls, in-place families and type symbols can be told apart in the IFC and the viewer."
},
{
"id": "saved-graphics-meshes",
"area": "geometry",
"name": "Family-instance bodies from the meshes Revit saved for display, opt-in (RE-78)",
"status": "experimental",
"evidence": "src/research/native_saved_scene.rs and the native_* reader from #255 (rosejn); src/ifc/saved_meshes.rs; rvt-ifc/rvt-gltf --saved-meshes; tools/re/saved_meshes_vs_ifc.py; tools/re/mesh_bodies_vs_ifc.py (shape against Revit's body, in Measure); reports/element-framing/RE-78-saved-graphics-meshes.md",
"notes": "Each body that is only its element record's bounding box is replaced by the element's saved display mesh (Fine detail), written as IfcTriangulatedFaceSet. Per element world box against Revit's own IFC export, within 0.01 ft (Measure run 41850769925, --saved-meshes, at e024f03c): Core Interior 138 of 138 doors and windows and RE1's four Revit 2025 models 228 of 228; Snowdon Towers 3,332 of 3,736 (the boxes: 1,138; RE-78, a local run not re-run since). Windows mostly differ (2 of 68 exact on Snowdon: Revit's export draws parts the saved mesh does not), as do 30 members 13.33 ft low and light fixtures 0.58 ft taller. Aggregate wholes keep their parts. By shape (tools/re/mesh_bodies_vs_ifc.py, every tested vertex of each body within 0.001 ft of the other's surface, Measure run 41850769925): Core Interior 138 of 138; the BIM4LCA office 1,554 of 1,650 scored as built (all 269 windows, 260 panels, 199 concrete columns, 68 furniture, 50 appliances, 43 light fixtures and 40 fire terminals; 265 of 269 doors, 34 of 47 sanitary terminals, none of 78 waste terminals, whose circles Revit's own tessellation makes miss in the default one) and 1,638 of 1,738 at building permit; RE1's four Revit 2025 models 148 of 228. A mesh that is not exact is mostly part of the body, its own vertices on Revit's surface, and nothing in the file found so far tells it from a complete one. RE1 Plumbing's 54 scored pipe fittings, cone-faced transitions included, are meshes of the true surface. Its 30 elbows and 8 transitions are 1.08 to 1.32 of Revit's volume, because Revit's own export of them is a polyhedron of 6 to 10 sides round the pipe and two segments along a bend, whose every vertex lies on the mesh; its 10 tees and 4 closet bends are 1.11 to 1.17, with some of Revit's vertices at their junctions 0.006 to 0.02 ft off the mesh (RE-311). Experimental: opt-in, 37 s and a 111 MB IFC on Snowdon.",
"user_impact": "Doors, windows, furniture and fixtures can be exported in their real shape instead of a box."
},
{
"id": "family-extrusion-bodies",
"area": "geometry",
"name": "Family-instance bodies from their family's own extrusions, opt-in (RE-327)",
"status": "experimental",
"evidence": "src/research/native_form_geometry.rs; src/ifc/family_extrusions.rs; rvt-ifc --family-extrusions; probes/examples/probe_re327_family_extrusions.rs; tools/re/family_extrusion_bodies_vs_ifc.py and tools/re/mesh_bodies_vs_ifc.py (Measure); reports/element-framing/RE-327-family-extrusions.md",
"notes": "A family file's ExtrusionElem, CurveElem and SketchPlane records are read without the project index; the sketch's lines are chained into loops, placed in the plane's frame and swept between the extrusion's two offsets. Against the mesh Revit saved for each form, 24 of 24 extrusions of the family corpus (12 releases) and 6,172 of 6,172 with a complete mesh in Autodesk's 58 sample projects (Revit 2015 to 2027) match within the report's section 4 criterion (79 of them with the normal reversed by a rule found on those 79 and not held out); 164 forms are not built (137 ellipses, 26 open loops, 1 up-facing flipped plane). The export draws an instance from them, as IfcExtrudedAreaSolid over IfcIndexedPolyCurve profiles, where they reproduce its own saved mesh (vertices within 1e-4 ft, surface samples within 1.1e-3 ft, volumes within the arcs' chord loss and 0.01%): an arc is written as the arc, whatever its radius (#1366), in the form Revit 24.0.5's IFC4 export gives it. Measured against Revit's own on Core Interior, RE1 and the BIM4LCA office files, at `34750454` (Measure runs 41884078892 and 41884639625, RE-331 §9.1): 335 bodies are replaced (Core Interior 37, each office file 129, each terrain file 11, RE1 Architecture 8, Electrical 8, Mechanical 1, Plumbing 1), where the 0.12 ft rule of #1352 replaced 66 and kept 269; 251 of them are scored by `mesh_bodies_vs_ifc` (the 42 per office file written as `IfcSpace` are scored by `space_profiles_vs_ifc`), and all 251 hold \"ref on ours\", both directions within 0.001 ft and the volume within 0.01%: 187 are decided by the fine tessellation, the bar for a body both files write as true curves (the arcs: 78 in each office file, 11 in each terrain file, 6 in RE1 Electrical and 1 in RE1 Architecture, and 2 circles of 0.12 ft or less), and 64 by IfcOpenShell's default one; 6 of the 53 exports move against `main`'s (the office files, the terrain files, RE1 Architecture and Electrical), each only by the bodies the rule kept, none held-out, and no row that passed on `main` fails. At `aaa38de8`, before the flat-arc rule, the first arc run had 250 of the 251 within the default tessellation's bar, the one that did not being a count mismatch between its default tessellation of Revit 26.2's IFC2X3 circle profile (27 chords) and of two half arcs of it (28) (run 41805333248, RE-327 §11) (RE-327 section 11). Revit 2024 to 2027 only, measured on 2024 and 2025: an earlier file has no instance transform that reads. Opt-in; the default export (no flag) is byte-identical to `main`'s on 34 of 34 models, hash for hash (run 41884073888; 111 of 111 at the earlier heads). The reported 85 of 86 extrusions of one family is a Revit 2014 file outside the native releases, so it is not reproduced.",
"user_impact": "Furniture, fixtures and equipment whose families are plain extrusions can be exported as extrusions instead of a triangle mesh, with their arcs."
},
{
"id": "elem-table-owner",
"area": "elements",
"name": "Owner ElementId per Global/ElemTable record",
"status": "experimental",
"evidence": "elem_table::ElemRecord::owner_id; tests/elem_table_corpus.rs owner_ids_are_declared_element_ids (Einhoven 338 of 2,614, Core Interior 22,368 of 26,425, every value declared); reports/element-framing/RE-31-elemtable-owner-field.md; #152 frame: probes/examples/probe_re31_owner_frame.rs, reports/element-framing/RE-31-elemtable-owner-field.md §6",
"notes": "The field the layout detector anchors on (u32 at +0 on the 28-byte layout, u64 at +4 on the 40-byte one) is an ElementId when not all 0xFF, and it closes the record before the frame it opens: the table's records start at 0x06 and end with their owner (#152, reported by STE1200). Read that way, the element's own partition reference list names the owner on 21,072 of 21,074 records on Core Interior and 1,574 of 1,574 on Snowdon Towers (86.6% and 92.4% with the frame's own field), and no record names itself (304 and 1,342 did). By category the named element is the curtain wall for curtain mullions, panels and grids (16,703 on Core Interior) and the model group for grouped walls, rooms, columns and doors (1,182). The table's first record, at 0x06, is not parsed, so its owner (ElementId 17 on family files) is not reported. Not used by the IFC export: the reference export writes no curtain-wall aggregation or group to hold it to.",
"user_impact": "rvt-elem-table and the library report, per ElemTable record, which element it belongs to; the IFC export does not use it yet."
},
{
"id": "element-record-door-window-host-binding",
"area": "elements",
"name": "Door and Window host-wall binding from Revit 2024 partition element records",
"status": "verified",
"evidence": "partition_element_records::decode_reference_list + partition_schema_mvp::opening_instances_from_records; tests/iter_elements_typed.rs::core_interior_2024_door_window_host_wall_binding compares the emitted (host wall, opening) pairs against the reference export's own IfcRelVoidsElement + IfcRelFillsElement chain and requires exact set equality (138/138, 0 wrong, 0 missing); the magnetar-2024-core-interior-slim OctetProof verdict carries relations.IFCRELFILLSELEMENT inside the claimed surface, where rvt-rs, IfcOpenShell 0.8.5 and IFClite 7.1.1 emit byte-identical 138-pair sets",
"notes": "Scope is two BuiltInCategories (OST_Doors, OST_Windows), one release band (Revit 2024) and one recorded edge. The carrier is a counted reference list that follows the element record's bounding box: a u32 length at +0x88 and that many u64 slots at +0x8c. The host is the slot immediately before the record's own ElementId, accepted only when it is one of the 360 ElementIds the RE-21 instance rule selects as exported walls, so a wrong read fails closed instead of inventing a host. Measured on 2024_Core_Interior.rvt: 273 of 273 door/window records give the correct host, and the emitted IfcRelFillsElement pair set equals Revit's own exactly - 138 of 138, no wrong host, no missing pair, no extra pair. Three fixed-shape readings were rejected and are recorded in RE-23: u64 at +0xac is right on 186 of 273 records, u64 at +0xa4 on 81, and 'the last two slots are (host, self)' on 192 - the list length varies (6 on every door record, 18 on every window record, up to 101 elsewhere) and 81 door records continue past their own id with a trailing type-symbol slot. The predecessor read is not a category discriminator: 528 of 638 wall records also have a wall predecessor, which is why the rule is applied only to the two categories RE-21 already identifies by BuiltInCategory. Emission is the IFC4 chain Revit uses - IfcOpeningElement (bodied with the door/window's own record bounding box, placed on the element's placement, not a wall-relative cut) plus IfcRelVoidsElement and IfcRelFillsElement. The opening's Tag repeats the filling element's, which is what the reference export does on all 138. The export's other 63 IfcOpeningElement - 42 in slabs, 20 in shading devices, 1 unfilled wall penetration - are not recovered: rvt-rs emits no opening that is not filled by a recovered element. This is not evidence for any other category or release. Outside that scope, on Snowdon Towers (2024, local only), the slot before the record's own id gave Revit's host for 107 doors and windows. The list is in ascending ElementId order, so since RE-85 the host is the nearest exported wall the list names below the record's own id, then above it, skipping curtain walls: 192 of the 194 doors and windows Revit fills an opening for take its host and the other 2 another wall Revit also cuts; Core Interior stays 138 of 138 (#439). Since RE-83 the opening is cut to the host wall's depth: within 0.25 ft of Revit's opening on all 138 Core Interior openings. Since RE-84 a door or window whose type draws no geometry (a type value block with no geometry-material map) is written as its opening alone, voiding its host with no filler, as Revit writes it: 48 of 48 such elements on Snowdon Towers, Core Interior and RE1 Architecture are opening-only in Revit's export.",
"user_impact": "Doors and windows come out of a Revit 2024 project as IFC4 fills of a real host wall, so a viewer subtracts the opening from the wall and shows the door in it - matching Revit's own export relationship for relationship."
},
{
"id": "element-record-slab-plan-profile",
"area": "elements",
"name": "Slab plan profile from Revit 2024 OST_SketchLines element records",
"status": "partial",
"evidence": "element_record_plan_profiles::plan_profiles_from_sketch_line_records wired through partition_schema_mvp::slabs_from_partition_category_records; reports/element-framing/RE-25-slab-plan-profiles.md; partition_schema_mvp::sketch_plan_profiles (RE-50 recorded ends, RE-95 zero-length lines); probes/examples/probe_re95_zero_length_sketch_lines.rs; tools/re/plan_profiles_vs_ifc.py; reports/element-framing/RE-95-zero-length-sketch-lines.md; gated by tests/iter_elements_typed.rs::core_interior_2024_slab_plan_profiles (all 100 record-backed plates resolve a profile; the 20 28-vertex rings with a void are exactly the export's IFCSHADINGDEVICE Tag set); partition_beam_axes::scan_first_records (Copies::Current for sketch scans); partition_schema_mvp::current_sketch_records; element_record_plan_profiles::sketch_curve_list_copies / scan_sketch_curve_lists; probes/examples/probe_824_sketch_lists.rs; probes/examples/probe_824_slab_arcs.rs; reports/element-framing/RE-216-current-instance-copies.md; RE-336 shape-edited floors: partition_schema_mvp::attach_slab_uncut (SlabShapeEditGStep: m_slab_top_plane, m_slab_shape_unread), ifc::export_content::floor_slope_solid (BodySource native_slab_shape_edit), tools/re/slab_bodies_vs_ifc.py, reports/element-framing/RE-336-sloped-footings.md",
"user_impact": "A Revit 2024 floor slab exports with the polygon its sketch actually encloses - including its voids - instead of the bounding rectangle, so a courtyard ring comes out as a ring.",
"notes": "Scope is one BuiltInCategory (OST_SketchLines, -2000045), one release band (Revit 2024), one recorded edge, and only the plates the RE-22 instance rule already recovers. The join is exact and byte-anchored: the last slot of the second counted reference list at +0x88 names the sketched element, and the 3688 sketch-line records on 2024_Core_Interior.rvt name 126 owners including all 80 exported IFCSLAB and all 20 exported IFCSHADINGDEVICE ids. No geometry takes part in the join. The reconstruction is a closure rule over the recorded segment bounding boxes, not a fit: a box degenerate on one axis contributes its endpoints, every other box is placed only when exactly one pair of still-open vertices fits it, and an ambiguous segment, a vertex that does not finish at degree 2, an unused edge, a zero-extent box or a loop under three vertices rejects the whole element. Measured against Revit's own export (IfcOpenShell 0.8.5, project plan frame, cyclic sequences with orientation normalised, tolerance 1e-3 ft per vertex): 80 of 80 slab profiles exact across 122 loops - 80 outer plus 42 rectangular voids - worst vertex deviation 1.563e-12 ft, and 2.842e-14 ft re-measured on the emitted IFC after the metre round-trip. 42 perimeter plates emit IFCARBITRARYPROFILEDEFWITHVOIDS (26-vertex outer ring, one rectangular void) and 38 emit IFCARBITRARYCLOSEDPROFILEDEF. Status is partial rather than verified because that agreement is measured and regression-gated but is not a field of either OctetProof claimed surface: no witness compares profile geometry, so this has not met the two-independent-witnesses bar in docs/verification-protocol.md. The 20 exported IFCSHADINGDEVICE are plates whose 57 sketch-line boxes include one of zero extent and 21 diagonals with no axis-parallel anchor, which the box closure declines. RE-95: the zero-extent record is a zero-length segment with no bounded line whose point ends two of the others; left out, the other 56 lines' recorded ends (RE-50) close each plate into a 28-vertex ring with one void, and all 20 equal Revit's outline (upward-face area 0.00% off, every vertex within 0.001 ft, tools/re/plan_profiles_vs_ifc.py). The pre-RE-25 plan-loop scan is a measured dead end here: 2317 closed plan-polyline candidates across all eight inflated partitions, none with the plan bounds of any recovered plate, and no ordered vertex run of the export's polygon anywhere in the file at any stride. Walls, doors, windows and columns still carry the record bounding box; base/top Level ElementId binding stays open (#86). This is not evidence for any other category or release. A sketch of several separate loops is several pieces, each with the voids inside it; the exporter writes each further piece as another element with the element's Tag and a ':2', ':3' name suffix, as Revit's export does (#331): on Snowdon Towers (local only) the five such slabs match Revit's pieces. Loops that cross give no profile. Where a sketch line's, a sketch curve list's or the slab record's copies in several partitions disagree, the copy in the current partition is taken (RE-216 §8): the BIM4LCA permit file's slabs 1384047 and 1474132 then have Revit's outline, 61 of 63 slabs within 0.01 ft (Measure 40181361898). RE-336 (#1384): a floor whose corner vertices are shape-edited (SlabShapeEditGStep) and lie in one plane, with one outline loop and a record box the plane reproduces, is drawn as the slab between that plane and one thickness lower: the BIM4LCA office's 8 such floors, as built and at permit, have Revit's volume within 0.01% and every vertex within 3.5e-6 ft of Revit's body. Floors with interior or edge vertices, creases or corners out of one plane keep their box and carry SlabShapeRefusal (Snowdon Towers Architectural has 17 such floors, roofs and ceilings, the Structural 1 and each save of rac_advanced 1, not scored for want of a redistributable Revit IFC4 export)."
},
{
"id": "element-record-wall-join-trim",
"area": "elements",
"name": "Wall body from Revit 2024 element records: run cut back by the joins the record names, plus thin-axis thickness",
"status": "partial",
"evidence": "element_record_wall_joins::joined_walls and ::join_trims wired through partition_schema_mvp::wall_instances_from_records; reports/element-framing/RE-26-world-coordinate-residuals.md and reports/element-framing/RE-29-join-reference-list.md; gated by tests/iter_elements_typed.rs::core_interior_2024_wall_join_trimmed_bodies (360 of 360 walls resolve, 322 take a trim), ::core_interior_2024_wall_joins_are_named_in_the_reference_list and the pinned ObjectPlacement x Position composition of wall 20800 in tools/ci/ifc_schema_arity.py",
"user_impact": "A Revit 2024 wall exports at the length its joins actually leave it, with the wall's real thickness, instead of the untrimmed centreline-to-centreline box - and the join partners are read out of the file rather than inferred from geometry alone.",
"notes": "Scope is one BuiltInCategory (OST_Walls, -2000011), one release band (Revit 2024), one recorded edge, and only axis-parallel walls - every wall on this file is axis-parallel, and a box with no distinguishable thin plan axis is declined. Three measured facts back it. First, the box's thin plan extent is the wall's thickness: on the newest frame of each element it equals the nominal thickness of the IfcWallType Revit's export assigns on 360 of 360 walls. Second, every non-zero delta between the box and Revit's Axis polyline over all 720 wall ends is exactly 0.25, 0.3333 or 0.75 ft - half of the 6-inch, 8-inch and 18-inch wall thicknesses on the file - and zero everywhere else, so an end is cut by half the thickness of the perpendicular recovered wall whose centreline lands on it. Third, since #274 (RE-29) a candidate must additionally be NAMED in this record's counted reference list at +0x88, and is tested for reach against its own cut-back run rather than its recorded one. All inputs are recorded bounding boxes and nothing is fitted; candidates disagreeing about their thickness decline the whole element, and a trim that would collapse the run declines it too. Measured against Revit's own export (world axis-aligned bounding box, max of the two corner deltas, tolerance 1e-3 ft; RE-26 used IfcOpenShell 0.8.5, RE-29 used tools/re/ifc_world_aabb.py, which reproduces every RE-26 table exactly): 336 of 360 walls exact at RE-26 and 351 of 360 after RE-29, up from 27 before either; correct wall ends 689 -> 703 (membership) -> 711 of 720; mean residual 0.2701 -> 0.0220 -> 0.0081 ft. Per element 15 walls improve, 345 are unchanged and 0 regress. Status is partial, not verified, for two reasons. The 9 ends still wrong are all over-trims at one side of a TRUE L CORNER - two walls whose runs both stop at the other's centreline with nothing continuing past, where Revit cuts exactly one of the pair. Two such corners exist on this file (one repeated on eight storeys) and no feature in the record orders the two sides: the survivor is the thicker wall once and an equal-thickness wall once, the x wall once and the y wall once, the higher ElementId once and the lower once, the longer run once and the shorter once, and the prologue flag words do not order them consistently either. The solver keeps cutting both rather than guessing, so the residual is recorded and pinned rather than hidden. And no witness compares body geometry, so this has not met the two-independent-witnesses bar in docs/verification-protocol.md. This models Revit's join cleanup on top of a carrier it does read; it does not read the per-pair butt/mitre decision itself. Emitted product counts, relations, storeys and the diagnostics sidecar are unchanged. This is not evidence for any other category or release.; RE-127 (2026-09-28): the joined-wall lists decide the 9 remaining ends, 720 of 720 ends and 360 of 360 walls exact"
},
{
"id": "element-record-column-type-symbol",
"area": "elements",
"name": "Column section and join-cut body from Revit 2024 element records",
"status": "partial",
"evidence": "partition_element_records::PartitionElementRecord::type_symbol_reference and element_record_column_cuts::{difference_box, column_cut_boxes} wired through partition_schema_mvp::column_instances_from_records; reports/element-framing/RE-26-world-coordinate-residuals.md and reports/element-framing/RE-29-join-reference-list.md; gated by tests/iter_elements_typed.rs::core_interior_2024_column_type_symbol_join (256 of 256 columns join to symbol 5755) and ::core_interior_2024_column_join_cut_plan_extents (the cut plan rectangles reproduce Revit's own body-extent histogram exactly: 176 x 2.0x2.0, 38 x 1.6667x1.6667, 20 x 1.75x1.6667, 18 x 1.4167x1.6667, 4 x 2.0x1.6667 ft)",
"user_impact": "A recovered column's profile is the one its family type declares, and its body is the prism minus the walls that cut it, so a column that Revit trims where a wall passes through it no longer exports oversized.",
"notes": "Scope is one BuiltInCategory (OST_Columns, -2000100), one release band (Revit 2024) and one recorded edge. The type join is exact and byte-anchored: the last slot before the record's own ElementId in the counted reference list at +0x88 that is itself an OST_Columns record carrying placement kind 0xffff8000 (the type-symbol envelopes of RE-21 section 5). All 256 exported columns have exactly one candidate before their own id and it is 5755 (Column_Sqaure : 24 inch x 24 inch), which is the IfcColumnType.Tag Revit's own export writes for every one of them. The join ships with a fail-closed guard: the type section and the instance plan envelope must agree to 1e-6 ft or the join is dropped and the element keeps its envelope with ProfileResolved false. RE-26 left the body residual open - 176 of 256 columns were world-exact and the 80 that were not had a body Revit cuts inset from the full prism, which no section can produce. #274 (RE-29) closes it from the same +0x88 list: a column record names the walls that cut it, and the exported body is the record prism minus the UNTRIMMED record prisms of those walls - 256 of 256 exact at a worst residual of 9.4e-13 ft and a mean of 0.0000 ft, against 176 of 256 at 0.5833 ft / 0.1217 ft before, with 80 improved, 176 unchanged and 0 regressed. Substituting the join-trimmed wall runs scores 190 of 256, so a wall runs its full recorded length into a column it cuts. element_record_column_cuts::difference_box is fail-closed: it answers only when the surviving material fills its own bounding box exactly by volume, which on this file is true on every one of the 80 columns whose box shrinks and false on every one of the 69 interior slots, Ls and crosses, so a decline never emits material Revit removed and the emitted solid is never larger on any axis than what Revit kept. Status stays partial because the section is still only the symbol's bounding box and the cut is still a box difference rather than a recovered solid, and because no witness compares profile or body geometry - the OctetProof claimed surface scores counts and relations, not shapes. The one emitted count that moves is IFCPROPERTYSINGLEVALUE 9231 -> 9311, the new JoinCutWallCount provenance row per cut column; BodySource becomes partition_element_record_join_cut on those columns. This is not evidence for any other category or release."
},
{
"id": "element-record-wall-type-join",
"area": "elements",
"name": "Wall type record and the wall to IfcWallType join from Revit 2024 element records",
"status": "partial",
"evidence": "rvt::partition_type_records::{type_definition_ids, unique_type_reference}; reports/element-framing/RE-28-wall-type-records.md; gated by tests/iter_elements_typed.rs::core_interior_2024_wall_type_record_join and ::core_interior_2024_material_record_family; recorded in the walls and materials rows of both magnetar count manifests (tests/fixtures/project-counts/2024-core-interior-slim.json and 2024-core-interior.json)",
"user_impact": "None yet in the exported file. The join is available to library callers; it is deliberately not written onto the emitted wall, because adding a property would move the committed witness observation hashes.",
"notes": "Scope is one BuiltInCategory (OST_Walls, -2000011), one release band (Revit 2024) and one recorded edge. A Revit wall TYPE has the bbox-less RE-24 record shape - the 88-byte prologue and the ff ff ff ff ab 05 marker at +0x50 with no bounding box - and a third value of the RE-21 placement-kind word at +0x42, 0xffff8080, alongside a counted slot list starting at +0x56 that names the record's own id. Eight OST_Walls records carry that shape on 2024_Core_Interior.rvt (ids 1710, 1711, 3897, 11356, 17328, 17337, 17339, 17341); Revit's own export writes four of them as IfcWallType and never places the other four, so the record set is a superset by construction and is NOT used as an IfcWallType recovery on its own. What is measured is the join: every one of the 360 exported wall instance records names exactly ONE of the eight in its +0x88 reference list - never zero, never two - and it is the IfcWallType.Tag the export assigns, 360 of 360 with no wrong answer and no miss, against 356 of 360 for RE-26's positional references[1] read. The recovered distribution equals the export's own IfcRelDefinesByType distribution exactly: 129 / 127 / 100 / 4. That also settles RE-26 section 9 and #240: the four 18-inch Basement walls read 1851 at references[1] because the list is ascending and 1851 (a record of category -2009014, not a wall type) sorts first - an index artifact, not a second id space or a type-graph indirection. Status is partial, not verified, for two reasons. First, nothing is emitted: no IFC entity, property or relation changes, tests/fixtures/synthetic-project.ifc is byte-identical, every committed OctetProof observation and verdict is untouched, and no count in either manifest moves. Second, no witness scores a wall-to-type relation, so this has not met the two-independent-witnesses bar in docs/verification-protocol.md. Separately and explicitly NOT claimed: compound layer thicknesses. A 128 KiB sweep centred on each of the four exported wall-type records finds 0 runs of consecutive f64 summing to that type's nominal width, and the paired reference export is a ReferenceView_V1.2 file carrying 0 IfcMaterialLayerSet, 0 IfcMaterialLayer and 0 IfcMaterialLayerSetUsage, so #88's layer-thickness criterion has no oracle on this artifact and can be neither met nor refuted here. No layer set is emitted and none is invented. This is not evidence for any other category or release. Since RE-44 (#322) the join feeds the export: each wall carries its type's name as the TypeName property, equal to Revit's on 360 of 360 walls here, and the same join holds on Revit 2025 (RE1 Architecture). Since RE-110 each wall is typed by an IfcWallType of its type through IfcRelDefinesByType (see ifc-type-objects)."
},
{
"id": "element-record-room-recovery",
"area": "elements",
"name": "Room recovery from Revit 2024 OST_Rooms partition element records",
"status": "verified",
"evidence": "partition_element_records::OST_ROOMS + partition_schema_mvp::rooms_from_partition_category_records + partition_room_parameters::scan_room_parameters; tests/iter_elements_typed.rs::core_interior_2024_room_instances_names_and_envelopes scores the recovered set, names, numbers and Level bindings against Revit's own full-project export (116/116 on every one, tolerance 0); tests/fixtures/project-counts/2024-core-interior-slim.json gates diagnostics.exported.by_ifc_type.IFCSPACE at 116 tolerance 0 with rooms_spaces status known; RE-101 outlines: partition_room_boundaries::room_outline, probes/examples/probe_re101_room_solids.rs, tools/re/plan_profiles_vs_ifc.py --class IfcSpace (area and outline, 116/116 on Core Interior), tools/re/room_areas_vs_vim.py (45/54 on Snowdon Towers), tests/rvt_schedule_cli.rs::core_interior_schedules_match_the_measured_counts (every Core Interior room has an area); and the magnetar-2024-core-interior-slim OctetProof verdict now carries entity_counts.IFCSPACE inside the claimed surface, where rvt-rs, IfcOpenShell 0.8.5 and IFClite 7.1.1 agree exactly",
"user_impact": "A Revit 2024 project's rooms come out as IfcSpace with their real Revit name and number, on the storey Revit puts them on, at the right place in plan and at the right floor-to-ceiling height - instead of a handful of name-only rows with a placeholder body. Since RE-101 the body is the room's own outline, not its bounding box, wherever the solid Revit stores for the room closes. Each IfcSpace is named as Revit's export names it: Name the room number, LongName the room name (Core Interior 116, RE1 Architecture 11, Exemplo_data 9 equal to Revit's pair; Snowdon Towers 54 against its VIM), with the ElementId as the ElementId property; a room without a number keeps the Name Room-<ElementId>. Every IfcSpace says what it is in RvtElementRecordGeometry.SpaceKind (#1437): room, area, mep_space or family_instance (any other element that its Export to IFC As writes as a space), from the Revit class of its record and not from its outline source; tools/re/space_kinds_vs_ifc.py checks it on every export Measure and CI make. No mep_space is written today: rvt-rs reads no Revit Space from a file's partition records, which says what it writes and not what the files hold.",
"notes": "Scope is one BuiltInCategory (OST_Rooms, -2000160), one release band (Revit 2024) and one recorded edge. The category was measured rather than assumed: a brute scan of all 23470 decodable element records on 2024_Core_Interior.rvt histogrammed every BuiltInCategory present and scored each one's #211 instance-rule selection against the 116 room ElementIds the reference export carries in IfcSpaceType.Tag; OST_Rooms selects 116 and they are exactly that set (FP 0, FN 0) and no other category intersects it at all. The number, name and host Level come from the room's own parameter block, anchored on the owning ElementId with a confirmation copy at +0x3c, the Level at +0x44, the number's UTF-16LE length prefix at +0x1f5 and the name's 8 bytes past the end of the number - the same owner-at-a-fixed-offset framing RE-22 uses for the IFC Export As override, read forward instead of backward. It accepts 116 of the 26425 ids Global/ElemTable declares and they are exactly the rooms; every room is framed twice and no pair disagrees; recovery is all-or-nothing per room. Scored against Revit's own export: 116 of 116 names equal IfcSpace.LongName, 116 of 116 numbers equal IfcSpace.Name. Storey containment is exact too - all 116 bind through the RE-27 Level reference, each of the ten Levels named maps to exactly one IfcBuildingStorey, and the parameter block's own Level slot agrees on 116 of 116. The body is the record's bounding box, which is not a placeholder here: measured on the emitted IFC against the export's swept areas in world coordinates, the plan envelope is exact on 116 of 116 (worst 1.640e-06 ft, the writer's six-decimal metre rounding) and the vertical extent is exact on 116 of 116 (worst 1.421e-14 ft). The boundary polygon came later (RE-101, 2026-09-28). RE-29 had measured that 76 of the 116 boxes equal their room's polygon in area and 40 over-state it, and that no partition holds the polygon's vertices as a packed run. The vertices are indeed not stored, but the faces they bound are: the room's partition holds its solid (u64 room id + 04 90 08 00, then planar faces 04 00 08 00 with a uv box at +20, origin at +86 and unit directions at +110 and +134). The vertical faces that reach the room's floor give plan edges that close into the outline, read from the partition of the exported record and kept only where their extent equals the record's box within 0.001 ft. Every Core Interior room then takes Revit's own exported area within 0.1% and its outline within 0.01 ft (116 of 116, against 76 of 116 for the box), all 11 RE1 Architecture rooms (Revit 2025) keep theirs, and 45 of Snowdon Towers' 54 rooms take the area the VIM export of its 2027 edition gives (10 of 54 for the box); 2 more differ from that later edition by 0.5% and 0.25% while their areas are stored verbatim in the 2024 file, and 7 whose solids do not close at the floor keep their box. Such rooms carry ProfileResolved true and ProfileSource partition_room_solid_faces, and rvt-schedule's room schedule gives their area. Revit 2023 stores the same solid with ff ff ff ff between the ElementId and the tag (RE-102): all 9 rooms of Exemplo_data then take Revit's own area and outline (6 of 9 for the box). RE-117 (2026-09-28): a room's number and name are the parameter entries -1006901 (ROOM_NUMBER) and -1006900 (ROOM_NAME) just past its data object, with ids as wide as the release's ElementIds, and they now take precedence over RE-29's block: every room carries Revit's number and name on Core Interior (116, unchanged), Snowdon Towers (54 against its VIM export, where the block named 1, wrongly), RE1 Architecture (11, 2025) and Exemplo_data (9, 2023). See reports/element-framing/RE-29-room-instance-and-envelope.md, reports/element-framing/RE-101-room-solids.md, reports/element-framing/RE-102-room-solids-2023.md and reports/element-framing/RE-117-room-names.md. This is not evidence for any other category or release."
},
{
"id": "element-record-areas",
"area": "elements",
"name": "Revit 2015 to 2027 Areas from their partition chain records, as IfcSpace, with a proven body",
"status": "experimental",
"evidence": "partition_area_records::areas_from_partition_chain_records (OST_Areas chain records, RE-21 instance words, the one recovered Level each record names, RE-117 number and name entries, the latest partition's copy, RE-40 design options); ifc::export_content area_property_set; category_map Area -> IFCSPACE .SPACE.; probes/examples/probe_re191_area_records.rs and tools/re/area_spaces_vs_ifc.py; tools/re/room_names_vs_ifc.py (number, name and storey of each space by GlobalId); reports/element-framing/RE-191-areas.md; partition_area_boundaries::Arrangement::face_at (the region of an Area's scheme lines on its Level around its point), partition_area_records::area_bodies (AREA_POINT_OFFSET, the Level above, the declared boundary lines all read), ifc::export_content::area_body_from_decoded (BodySource partition_area_boundary_lines, SpaceOutlineSource area_boundary; BodySource native_area_plan_topology and SpaceOutlineSource area_plan_topology where the plan topology gives the region, area_plan_topology_unchecked on Revit 2025 to 2027 and on an Area drawn from lines whose partition copies disagree, partition_area_records::area_unchecked), probes/examples/probe_re317_area_boundaries.rs, tools/re/area_boundaries_vs_ifc.py, tools/re/space_profiles_vs_ifc.py, reports/element-framing/RE-317-area-boundaries.md, partition_area_records::Layout and NARROW_POINT_OFFSET (the 32-bit chain records of Revit 2015 to 2023), probes/examples/probe_re324_area_records_32bit.rs, reports/element-framing/RE-324-areas-2015-2023.md, partition_area_boundaries::Arrangement::new (free ends carried on to the lines that name them, connectors; AreaFace.joined), partition_area_records::GroupArrangement (lines off the axes refuse only the Areas they touch), ifc::export_content::SPACE_OUTLINE_AREA_BOUNDARY_JOINED, ifc::export_content::SPACE_OUTLINE_AREA_PLAN_TOPOLOGY (area_plan_topology), probes/examples/probe_re330_area_line_curves.rs, tools/re/area_joins_vs_ifc.py, reports/element-framing/RE-330-area-joins.md, native_area_regions::area_regions (an Area's loop from Revit's plan topology, its area rule's offsets and arcs, checked against the area Revit saves for the loop and the Area's point), partition_area_records::chain_entries (the entry block some Revit 2025 to 2027 chain records carry before their body), probes/examples/probe_re333_area_plan_topology.rs, reports/element-framing/RE-333-area-plan-topology.md",
"notes": "An Area's chain record carries OST_Areas at +0x12 and no bounding-box marker at +0x50, so the element-record scan never reads it. Its container slot at +0x32 is unset and its placement kind at +0x42 is the placed-instance kind on every Area Revit exports; the record then lists the Area's Level among its ids. Measured on the BIM4LCA office (CC BY-SA 4.0) against Revit's IFC export: as built, 30 Areas and all 30 of Revit's area spaces, number, name and storey equal on 30 of 30; at building permit, 30 placed of 32, the 30 Revit exports, the 2 others carrying 0xffff8020 and not in Revit's export. Revit writes each as IfcSpace .SPACE. with an IfcSpaceType of its own, Pset_SpaceCommon.Reference and Pset_SpaceCommon.IsExternal false, which rvt-rs writes (IsExternal since RE-193); Pset_SpaceHeaterTypeCommon.Reference and Qto_SpaceBaseQuantities.Height are not read. Its body (RE-317) is the region that the lines of its area scheme on its Level enclose around its point (two f64s in its data object), its holes the loops directly inside, extruded from its Level up to the Level above it, where both are building stories and no other Level lies between them (the Level's story above is not read): on both office files all 30 Areas are within 0.1% of Revit's area and 0.01 ft of its outline, and an Area whose region a line off the plan axes may change, or whose point lies in no single region they bound, keeps no body, and says why (AreaBodyRefusal, exported.area_body_refusals). Revit 2015 to 2023 (RE-324) write the same record with u32 ElementIds: the category 14 bytes after the record's ElementId, the design option, container and placement words 12, 16 and 24 bytes after it, two counted lists of u32 ElementIds (the Level, scheme and two boundary lines among them), the point 35 bytes after the 01 00 00 00 . ElementId header of the Area's element data, and the boundary lines as 32-bit element records. Measured on Autodesk's rac_advanced of 2015 to 2023 (25 Areas each) and rst_basic of 2016 to 2023 (1 each) against the same project's 2024 save: number, name, Level, scheme, named lines and placement equal on every Area of every save, the point and the 127 (17) boundary lines equal on the 2022 and 2023 saves, and the reader's output identical to 2024's on every rst_basic save, and on the 2022 and 2023 rac_advanced saves for the 16 bodies it draws (RE-330; the 9 other Areas are written by 2024 with a refusal and not written by 2015 to 2023); the 2015 to 2021 rac_advanced saves hold an earlier state of the model (16 north-edge lines 0.0246 ft off, one Area's point as far), where the 2021 save holds both. On 2015 to 2023 an Area is written only where its region and body are proven, and the others are counted in the diagnostics (skipped, area_without_proven_body): the first rule, writing every placed Area, wrote spaces Revit's export lacks on a held-out project (RE-324 section 6), whose cause is not measured (revit-ifc's SpatialElementExporter makes no space for an Area with no enclosed boundary, a hypothesis). RE-330 adds the lines' joins: a free end is carried on to the farthest perpendicular line that names it and is named by it, and two parallel lines that stop at the same place are joined by a connector; a line off the plan axes is left out with its box and refuses only the Areas whose region it touches. 16 of rac_advanced's 25 Areas are drawn on every save but 2021, those whose outline needed a join saying SpaceOutlineSource area_boundary_joined. The only external check of the joined Areas is an IFC2X3 export of rac_advanced from the three.js repository, by a build of Revit 2021's exporter whose string ends 'IU alternativa 21.0.0.383' (publisher not established), showing the project's 2015 to 2020 state, against which the joins were read off and then scored (in-sample): the 16 Areas drawn on the 2020 save are within 0.1% in area and 0.01 ft in outline of it, with none written that it lacks; the 2022 and 2023 saves are also checked against the 2024 save's reader; no Revit IFC4 export of these Areas exists, and the export is never used to remove a value or to settle a disagreement between exporters. No wall bounds any Area it draws. The held-out project is a regression check, quoted by counts. RE-333 reads Revit 2025 to 2027 too and puts Revit's plan topology first, an Area drawn from it saying SpaceOutlineSource area_plan_topology: the loop Revit computed for the Area, each area boundary line moved by its area rule's offset (m_schemeSegments) and arcs drawn, checked against the area Revit saves for the loop (PlanCircuit m_area) and the Area's point; where it is not read the region is the lines' arrangement with its joins, where it is read and fails a check of its own the Area has no body, and a group of lines that cannot be read as a whole (a non-primary design option, a stray height, a copy that names another Level or scheme or lies at another height, a missing line) gives no region of either kind. A group whose lines have copies that differ only in place (the 2021 save of rac_advanced) gives the plan topology's region alone, marked area_plan_topology_unchecked (#1434). Where both readers give a region they must be the same one, else the Area has no body (area_regions_disagree). Revit 2025 to 2027 and the recorded Autodesk 2024 Snowdon Towers samples are written against no Revit export, labelled (Griffin, 2026-11-05, Ship, labelled, then Same-project gate): the loop drawn equals the area stored in the file for it and, on 2025 to 2027, the same project's 2024 save gives the same Areas, which every Measure run of the samples that holds the four saves checks (tools/re/areas_across_saves.py: GlobalId, number, name, storey, outline source, body area, top surface, height and lowest vertex; other than 25 Areas or 25 bodies on a save, an Area with no storey or a missing save fail; a narrower sample_years checks nothing and prints a notice; the failure blocks landing by the landing rule); the seven held-out Revit 2025 to 2027 models write no Area, so they test nothing here. Counts measured on 5008247d (Measure run 42017400629), vertex-level figures on the archived head e9124b3a. 2008 to 2014 are not read, and a 2015 Area that names a design option is left out (2015 reads no option sets).",
"user_impact": "Gross, net and office areas a Revit 2024 model defines come out as IfcSpace with Revit's GlobalIds, numbers, names and storeys, so an export consumer sees the same area spaces as Revit's export lists; their bodies are the area outlines Revit draws, where the Area's boundary lines prove one, and absent where they do not. On a Revit 2015 to 2023 model the area spaces whose boundary lines prove a body come out the same way, and the others are not written."
},
{
"id": "record-level-storeys",
"area": "elements",
"name": "Revit 2024 Level names and elevations from partition Level records",
"status": "verified",
"evidence": "partition_level_records::scan_partition_levels + ifc::apply_partition_level_storeys; on 2024_Core_Interior.rvt the fifteen standalone OST_Levels records each own exactly one name/elevation parameter block, and all fifteen (name, elevation) pairs equal an IfcBuildingStorey Name/Elevation in both paired Revit exports - Basement 2 -40, Basement 1 -20, Level 1 0, Mez 1-2 15, Level 3/4/4 - Wall Layouts 1/2/3 at 31/46/61, Level 6..13 at 76/91/106/121/136/151/166/185.5 ft, no wrong elevation, no missing storey, no extra storey; tests/fixtures/project-counts/2024-core-interior*.json gate diagnostics.exported.storey_count at 15 tolerance 0 with levels status known, and both OctetProof verdicts carry entity_counts.IFCBUILDINGSTOREY and storeys.IFCBUILDINGSTOREY inside the claimed surface, where rvt-rs, IfcOpenShell 0.8.5 and IFClite 7.1.1 emit byte-identical fifteen-pair sets",
"notes": "Scope is one BuiltInCategory (OST_Levels), one release band (Revit 2024) and one recorded edge. A Level record carries the same 88-byte element-record prologue but no bounding box - it ends at +0x56 where a column record's bbox would start - so it is decoded by its own reader, anchored on the 6-byte ff ff ff ff ab 05 marker at +0x50 and gated on the leading ElementId being declared in Global/ElemTable. Which of the 75 OST_Levels records on this file is a Level element is the same #211 instance test used for walls and columns: no container reference at +0x32, placement kind 0xffffef7f at +0x42. That selects exactly 15. The name and elevation come from a parameter block whose owner slot is a u64 at value-0x47, followed by a 56-byte 0xff sentinel run, three zero bytes and the u32 UTF-16 length; the elevation is an f64 in feet 55 bytes past an 8-byte marker (05 00 00 00 48 02 00 00) searched forward from the end of the name, repeated 153 bytes later, and both copies must agree. The run between name and marker is variable (347 bytes for fourteen levels, 363 for Basement 2), which is why the marker is searched rather than assumed. Fail-closed twice: a level with no accepted block emits nothing, and the whole recovery is discarded unless every Level record owns exactly one block and no two levels share an elevation - a partial recovery is never emitted as a smaller building. The names are asserted because the file states the pairing (the block is keyed by the Level's own ElementId), not because they were joined by rank; #213's rank join is what this replaces. Recovering a Level's own ElementId is not the same as binding a Floor or a Room to one - level-elementid-storey-bind stays unsupported (#86 / RE-20). Storey containment measured on this storey set was 801 of 872 elements when it landed and is 853 of 872 after #219 / RE-27 bound the record-named Level; see record-level-reference-storey-bind. This is not evidence for any other category or release.",
"user_impact": "A Revit 2024 project exports with its real Level names and heights - Basement 2, Mez 1-2, Level 13 - instead of elevation-derived labels, and every storey the project has is present rather than only the ones with a column standing on them."
},
{
"id": "record-level-storeys-2025",
"area": "elements",
"name": "Level names and elevations on every Revit 2024 and 2025 project, and the storeys they make",
"status": "partial",
"evidence": "partition_level_records::elevation_marker / record_marker / decode_name_block_at_with / find_name_blocks_with / decode_record_at_with / owned_level_ids / scan_partition_levels; tests/level_names.rs against the four RE1 exports (CI tier 2); probes/examples/probe_re51_level_names.rs; reports/element-framing/RE-51-level-names.md; RE-118: partition_level_records::building_story_after / BUILDING_STORY_ANCHOR, ifc::apply_partition_level_storeys, probes/examples/probe_re118_building_story.rs, tools/re/storeys_vs_vim.py, reports/element-framing/RE-118-building-story.md",
"notes": "RE-24's name block (owner ElementId at name-0x47, a 56-byte 0xff run, three zero bytes, u32 length, UTF-16 name) holds every Level's name and elevation on Snowdon Towers (2024) and the RE1, Projeto1 and teste_export_2025 models (2025), where it opens the Level's element data. The elevation marker is 05 00 00 00 and a per-release u16 (0x0248 on 2024, 0x025d on 2025); four plan extents follow and the elevation is 55 bytes past the marker. RE-24's last two marker bytes were the first extent's low bytes, zero on Core Interior's round extents. The confirming copy is the one preceded by the same 24 bytes as the first (153 bytes on on Core, 161 on Snowdon, 246 and 181 on RE1). Level frames in the second prologue take their partition record's id (RE-35), and a Level whose block names another element after its own id is not a storey. Measured against Revit's own exports: every storey written has Revit's name, elevation and GlobalId on Snowdon Towers (18 of 18, local only), each RE1 model (2 of 2, CI), Projeto1 and teste_export_2025 (2 of 2, local only) and Core Interior (15 of 15, unchanged); on Snowdon 3,379 of 3,380 elements are contained in Revit's storey, on RE1 Architecture 14 of 14. RE-118 (2026-09-28): a Level keeps Revit's Building Story setting past its name (the first ff x 8 · 00 01, an f64, a u64 ElementId, then 1 or 0), exact against the Building Story parameter of Snowdon Towers' VIM export on all 18 architectural and 19 structural Levels and 1 on Core Interior's 15 and RE1's 2; only a building story becomes a storey, and a 01 pad byte before the name length no longer refuses a Level, so Snowdon's structural model has its 12 building stories as storeys, names and elevations the VIM's, with 208 of the 210 elements on them in their storey; elements on its 7 non-story Levels are in the building, since no export says where Revit's IFC puts them. Status is partial: Revit 2023 Levels come from RE-107.",
"user_impact": "Projects saved in Revit 2024 and 2025 export and display their storeys with the Level names the team uses (L2, R1, Parking) at the right heights, with the same GlobalIds as Revit's own export, and elements sit on the storey Revit puts them on."
},
{
"id": "record-elevation-storey-bind",
"area": "elements",
"name": "Storey elevations and containment from Revit 2024 element-record bounding boxes",
"status": "verified",
"evidence": "element_record_storeys + ifc::apply_element_record_storeys; on 2024_Core_Interior.rvt the 256 OST_Columns records carry 11 distinct base elevations (0, 31, 46, 61, 76, 91, 106, 121, 136, 151, 166 ft) and all 11 equal an IfcBuildingStorey.Elevation in the paired Revit export, measured with IfcOpenShell 0.8.5; IfcRelContainedInSpatialStructure 1 -> 11 with 794 of 872 elements bound after #212 (all 256 columns, all 132 doors, 355 of 360 walls, 51 of 100 record-backed plates), measured on the commit before #218 replaced the storey source",
"notes": "Elevations only. The join is elevation equality within 1e-3 ft and fails closed on both a miss and an ambiguity, and the storey set is derived this way only when the recovered Level rows carry no elevation of their own. It does not recover which named Level sits at an elevation - 12 name candidates against 11 measured elevations is not a pairing, and a rank join mislabels (Level 6 at 91 ft where the export puts Level 7) - so storeys are labelled 'Elevation N ft'. Level ElementId binding stays unsupported (#86 / RE-20). Scope is Revit 2024 partition element records: only OST_Columns *supplies* elevations, a restriction measured in RE-21 (doors 11 of 11 also land on storeys, walls 12 of 13 - they add -40 ft at the cost of one non-storey elevation - and windows 0 of 6, because a window base is a sill height). Every record-bodied element *binds* to the column-derived set by exact match. The export's other four storeys (-40, -20, 15, 185.5 ft) carry no column record and are not recovered. Re-measured in RE-22 (#212): plates bind by their record TOP face, not their base — Revit hangs a floor below the level that hosts it, so 0 of 40 distinct slab base elevations is a storey elevation while 51 of 100 plates have a top that equals one, every one of them the storey Revit's own export assigns. Slab records are still not an elevation *source*: their 26 distinct top elevations would add -40 ft and 185.5 ft (two of the four storeys this recovery misses) at the cost of 13 values that are not storey elevations, each 0.1667 ft below a real one, so STOREY_ELEVATION_SOURCE_TYPES stays IFCCOLUMN alone. Superseded as the primary storey source on 2026-08-30 by record-level-storeys (#218, RE-24), which reads the Revit Level elements themselves and recovers all 15 storeys with their names; this path now runs only when no Level records are recoverable, and the binding half it contributes is unchanged.",
"user_impact": "Columns from a Revit 2024 project land in storeys at their real elevations instead of all defaulting to the first storey; the storeys are labelled by elevation, not by Revit Level name."
},
{
"id": "record-level-reference-storey-bind",
"area": "elements",
"name": "Storey containment from the Level ElementIds a Revit 2024 or 2025 element record names",
"status": "verified",
"evidence": "element_record_level_refs::unique_level_reference + ifc::apply_record_level_reference_storeys; on 2024_Core_Interior.rvt the counted reference list at +0x88 names exactly one of the fifteen recovered Levels on 121 of 146 OST_Floors, 267 of 320 OST_Doors, 206 of 1487 OST_Walls, 6 of 7 OST_Windows and 1 of 2 OST_BuildingPad placed instances, and on 0 of 463 OST_Columns, which all name two; over the 537 elements the #212 / #213 elevation join also answers, the two joins agree 537 of 537 with 0 disagreements; emitted storey containment 801 -> 969 of 970 building elements after #90 / RE-29 added the 116 rooms (853 of 872 when this landed) (IFCSLAB 44 -> 80 of 80, IFCSHADINGDEVICE 10 -> 20 of 20, IFCWINDOW 0 -> 6 of 6), gated by tests/iter_elements_typed.rs::core_interior_2024_storey_containment_is_evidence_backed; RE-59: element_record_level_refs::named_levels / base_constraint_level + partition_schema_mvp::resolve_base_constraint_levels (m_constraintLevelIds, LevelBindSource partition_element_record_base_constraint); probes/examples/probe_re59_base_constraint_levels.rs; tools/re/storeys_vs_ifc.py; reports/element-framing/RE-59-base-constraint-levels.md; the same test now gates 970 of 970; RE-60: element_record_level_refs::level_at_or_below + partition_level_records::scan_level_objects + partition_schema_mvp::resolve_hosted_levels (m_referenceIds; LevelBindSource partition_element_record_host / partition_element_record_level_object); probes/examples/probe_re60_hosted_levels.rs; reports/element-framing/RE-60-hosted-levels.md; RE-68: partition_schema_mvp::resolve_base_at_level / resolve_remaining_levels; element_record_level_refs::elevation_band_level; probes/examples/probe_re68_remaining_levels.rs; tools/re/storeys_vs_ifc.py --any-copy; reports/element-framing/RE-68-remaining-storeys.md; LevelBindSource partition_element_record_plumbing_level_object (RE-68 §6)",
"notes": "Scope is Revit 2024 partition element records, and the join is stated by the file rather than inferred: the host Level is a plain ElementId slot in the same counted list RE-23 reads for a door's host wall. Fail-closed three times over. A record that names no Level, or two or more, resolves to nothing and keeps whatever the elevation join gives it - a Revit column or wall carries a base and a top constraint and both are in the list, with nothing in the bytes saying which slot is which, so 344 of 344 OST_Columns records and 432 of 638 OST_Walls records that name a Level at all are declined. The id set the uniqueness test runs against is deliberately the broader one (every standalone OST_Levels record, not only the fifteen the RE-24 name / elevation recovery validates), so a Level the full recovery would drop still makes a record ambiguous; the binding half then uses only the validated fifteen, and a named Level outside them binds nothing. This is NOT the #86 / RE-20 typed level bind: level_bind.rs binds a typed Floor or Room through an m_level_id schema field, that field is still unrecovered, and level-elementid-storey-bind stays unsupported. On a release or file where partition_element_records or partition_level_records decline, the level-id set is empty and nothing changes - verified unchanged on the 2023 Einhoven sample. The reference side is measured for the rooms only (#90, RE-29): each of the ten Levels the 116 room records name maps to exactly one IfcBuildingStorey of the full-project export, and it is the storey that export aggregates the room into, 116 of 116. The rest are measured by RE-59 below. Elements with no recovered storey are now contained in the IfcBuilding rather than in storey[0], which had put 71 elements - some at 185 ft - into Basement 2 at -40 ft. See reports/element-framing/RE-27-level-reference-storey-bind.md. RE-59 (2026-09-23): a record naming exactly two Levels names its base and top constraint in no fixed order (lower first on 452 of Snowdon's 650 and 194 of Core Interior's 493), and its base constraint - the higher of the two at or below the record's base, else the lower; declined when they share an elevation - is the storey Revit's own IFC export contains it in on 650 of 650 Snowdon Towers, 482 of 482 Core Interior and 7 of 7 RE1 Architecture records. With it, measured per element against Revit's IfcRelContainedInSpatialStructure (a part takes its aggregate whole's storey; tools/re/storeys_vs_ifc.py): Core Interior 854 of 854 in Revit's storey (970 of 970 building elements bound through their own Level: 488 naming one, 482 naming two; the last unbound wall now bound); Snowdon 5,612 same (3,975 before), 294 on no storey (1,931 before; the 294 name no Level), 45 different (45 before); RE1 34 same and 0 on no storey (7 before), its other 39 contained by Revit in rooms; the MIT tutorial house 1 element on no storey (230 before). Records naming three or more Levels stay unresolved. RE-60 (2026-09-24): for a record naming no Level, a railing takes the Level of the one stair or ramp it names (Revit's storey on 73 of 74 Snowdon railings), and any other element takes the Level carried by the objects it names (01 00 00 00 + u64 id + u64 Level id; 6,435 on Snowdon) only where that is also the highest Level at or below its base (Revit's storey on 161 of 161; each reading alone is wrong on 38 and 8 light fixtures). Snowdon: 5,805 in Revit's storey, 102 on no storey, 44 different (one new: railing 1646280). RE-68 (2026-09-24, measured on Snowdon Towers against every copy Revit writes): a stair or ramp with no Level whose base sits exactly at one Level takes it, so a multistory stair's railings follow it; an element takes the Level of the one element of its own class its record names (the parts of a nested light fixture); slab edges, light fixtures, wall sweeps, generic models, hardscape and stairs take the Level their base gives, within a band that picks the Level just above within 0.25 ft, the Level at or below from 0.5 ft, and none in between. Snowdon elements on no storey 102 -> 5 (4 plumbing fixtures, which follow their Level object, and 1 slab edge in the band's closed part), 97 placed, 0 wrong. RE-68 §6 (#369): a plumbing fixture takes the Level its Level objects carry on its own, whatever its base gives (Revit's storey on 4 of 4 on Snowdon; for light fixtures, slab edges and wall sweeps that Level alone is wrong on 73 of 214, so they still need it to agree with their base). Snowdon: 5,949 in Revit's storey, 1 on no storey (slab edge 2060948), 1 on another (railing 1646280); the other local files are byte-identical.",
"user_impact": "A Revit 2024 project exports with its floor plates, shading plates and windows on the Revit Level that hosts them, instead of unplaced because a plate hangs two inches below its level and a window sits at its sill height above it; and an element whose storey is unknown is visibly unplaced in the building rather than silently filed under the lowest basement."
},
{
"id": "schema-field-wall",
"area": "elements",
"name": "Schema-field Wall decode (non-ArcWall)",
"status": "unsupported",
"evidence": "RE-19 negative on magnetar corpora; unchanged by RE-21",
"notes": "No fail-closed schema-field Wall / 2024 ArcWall envelope suitable for production decode beyond the gated 2023 ArcWall path. RE-21/#211 recovers Wall instances from a different carrier (the partition element record's BuiltInCategory field, see element-record-instance-recovery); the schema-field mechanism this row names is still unsolved, and diagnostics keep reporting schema_field_wall_instances as unsupported.",
"user_impact": "Arbitrary walls are not recovered as typed Walls."
},
{
"id": "typed-door-window",
"area": "elements",
"name": "Typed Door and Window discrimination from the ArcWallRectOpening index",
"status": "unsupported",
"evidence": "RE-19: no reliable Door vs Window discriminator in the opening-index bytes; unchanged by RE-21 and RE-23",
"notes": "RE-21/#211 recovers Door and Window *instances* and RE-23/#222 binds them to their host wall, both from the partition element record (see element-record-instance-recovery and element-record-door-window-host-binding). Neither touches the carrier this row names: the 2024 ArcWallRectOpening index bytes still hold no Door vs Window discriminator and no host claim, and its rows still surface only ElemTable-confirmed related ids. RE-19's negative stands.",
"user_impact": "Opening-index rows are not turned into typed Doors or Windows, and carry no host claim of their own."
},
{
"id": "level-elementid-storey-bind",
"area": "elements",
"name": "Floor/Room storey bind via Level ElementIds",
"status": "unsupported",
"evidence": "RE-20: proximity scans noise-dominated. Its premise that Level is absent from Formats was an artifact of the 64 KB schema scan: the whole schema carries Level (class 2422 on Revit 2024, #410). Storeys are bound from element records instead (record-level-storeys, record-level-reference-storey-bind)",
"notes": "Bind plumbing stays fail-closed / corpus-idle. Floors/Rooms remain Unassigned by evidence.",
"user_impact": "Scene-tree storey grouping for Floors/Rooms stays Unassigned."
},
{
"id": "aparameter-host-joins",
"area": "parameters",
"name": "AProperty* host parameter joins",
"status": "unsupported",
"evidence": "Production iter_elements / Global/Latest candidate scans; #35 idle on magnetar corpora",
"notes": "The Global/Latest AProperty* carriers are still not joined to host elements. Parameters are read from the native records instead (native-element-parameters, RE-207): the viewer's info panel lists a selected element's (#35) and its Parameters row counts the values written to the IFC property sets.",
"user_impact": "Element parameters are not exposed as a completed feature."
},
{
"id": "ifc4-export-real-projects",
"area": "ifc",
"name": "IFC4 export from real Revit project files",
"status": "partial",
"evidence": "Synthetic fixtures validate; 2023 ArcWall IfcWall + partition Level/Floor/Room/Material emission; 2024 record-backed IfcWall / IfcDoor / IfcWindow / IfcColumn / IfcSlab / IfcShadingDevice with placement, envelope solid, measured slab thickness, recovered slab plan profiles (IfcArbitraryClosedProfileDef / IfcArbitraryProfileDefWithVoids) and storey containment; rvt-ifc --mode / --diagnostics",
"notes": "Correct writer path exists. Real-file typed inputs remain incomplete. Scaffold success is not typed conversion.",
"user_impact": "Valid IFC scaffold and narrow typed subsets; not general RVT-to-IFC."
},
{
"id": "csv-schedules",
"area": "ifc",
"name": "Element and room schedules as CSV (rvt-schedule, viewer, Python)",
"status": "partial",
"evidence": "tests/rvt_schedule_cli.rs (tier-1 shape; 2024_Core_Interior 970 elements / 360 walls / 132 hosted doors / 6 windows / 256 columns / 116 rooms); viewer Playwright download test",
"notes": "One row per element the IFC export writes, on the storey it puts it on (the elements schedule), or per room, so coverage is the decode coverage as the export writes it: typed rows on every release whose element records are read (Revit 2023 to 2025; 2015 to 2022, 2026 and 2027 experimentally), scaffold-only elsewhere. Unknown values are empty cells. A room's area is its outline's where the room's stored solid was read (RE-101) or its solid's faces close as the walk reads them (RE-316), and empty where the room keeps its box or its outline is approximate (stored_solid_approximate).",
"user_impact": "A spreadsheet of walls, doors, windows, columns, slabs and rooms without Revit, on files whose elements decode."
},
{
"id": "converter-grade-rvt-ifc",
"area": "ifc",
"name": "Converter-grade production RVT-to-IFC",
"status": "unsupported",
"evidence": "docs/status.md; ROADMAP out-of-scope until corpus-proven typed elements + geometry",
"notes": "Explicit non-claim (COR-001). Do not advertise rvt-rs as a production Revit IFC converter.",
"user_impact": "Use Revit/API exporters or wait for MVP milestones when evidence lands."
},
{
"id": "browser-viewer",
"area": "viewer",
"name": "Zero-upload browser viewer",
"status": "partial",
"evidence": "GitHub Pages; WASM no-network import gate; File Status / storey grouping; viewer/tests/parameters-row.spec.ts (the info panel's saved parameters against rvt-elements on Einhoven and Core Interior)",
"notes": "Geometry and export readiness reflect decoded coverage. Synthetic fixtures are scaffold-only. Selecting an element lists its saved parameters (RE-207, #35) beside the property sets the export writes, read for that element in a worker of its own, bundled into the page, with no request and not at the open: instance and type parameters apart, a nameless one by its id with the reason it has no name (#255), and a said-so state for a release outside Revit 2015 to 2027, for one of 2015 to 2022 (experimental), for an element with none and for a read that failed. A selection is read on its own only while the page holds at most 1 GiB of wasm memory, which is as far as a read has been measured, and is otherwise read when asked.",
"user_impact": "Useful local inspection without upload, down to an element's saved parameters."
},
{
"id": "stream-level-writer",
"area": "writer",
"name": "Stream-level CFB writer / patch",
"status": "partial",
"evidence": "Always-on gen-fixture + MIT empty.rfa patch corpus; optional Autodesk matrix",
"notes": "Controlled stream replacement only. Not semantic Revit editing.",
"user_impact": "Useful for forensic/stream patches, not model authoring."
},
{
"id": "semantic-revit-editing",
"area": "writer",
"name": "Semantic Revit field-level editing",
"status": "unsupported",
"evidence": "ADR-002 semantic write API gate",
"notes": "No stable semantic write API until decoder/validation evidence is strong enough.",
"user_impact": "Do not expect round-trip model edits."
},
{
"id": "python-package",
"area": "bindings",
"name": "Python package (rvt)",
"status": "partial",
"evidence": "CI wheel builds; pytest; maturin/pyo3 bindings",
"notes": "Useful for metadata/schema automation. Same honesty bounds as the Rust core.",
"user_impact": "Scriptable inspection; not a full converter SDK."
},
{
"id": "inspect-cli",
"area": "cli",
"name": "User-facing rvt-inspect CLI",
"status": "partial",
"evidence": "rvt-inspect human + JSON; export readiness; diagnostics sidecar fields",
"notes": "Support triage without Revit internals. Reports align with this matrix.",
"user_impact": "Clear health / coverage / next-steps for a single file."
},
{
"id": "community-corpus-scaffold",
"area": "validation",
"name": "Community corpus open/schema/scaffold IFC check",
"status": "partial",
"evidence": "docs/corpus-hunt-2026-04-21.md: 222/223 real files pass open → schema → scaffold IFC",
"notes": "Proves container/schema/scaffold health. Does not prove typed element recovery.",
"user_impact": "Confidence in open/inspect on public samples; not conversion proof."
},
{
"id": "export-source-coverage",
"area": "diagnostics",
"name": "Measured export source-coverage fractions (A10)",
"status": "partial",
"evidence": "src/ifc/mod.rs SourceCoverageDiagnostics::measure; docs/export-diagnostics.md",
"notes": "A10: exported/geometry fractions measured from diagnostics counts; decoded_element_fraction divides by the distinct ElementIds Global/ElemTable declares, only when walker ≤ that count (fail closed otherwise); the header element_count it used before 2026-09-22 is a per-release constant. Not converter-grade completeness.",
"user_impact": "Diagnostics sidecar reports honest measured fractions when denominators exist; otherwise unset/null."
},
{
"id": "native-element-parameters",
"area": "parameters",
"name": "An element's saved parameters, named by the file's definitions, in rvt-elements and Python (RE-207)",
"status": "partial",
"evidence": "elements::parameters::saved_parameters_lossy / SavedParameters::entries_for over research::native_element_parameters::read; native_parameter_definitions::project (ParamDefFamType as ElementId); rvt-elements and rvt-py decoded_elements; tests/element_parameters.rs (RVT_NORDIC_LCA_DIR, RVT_PROJECT_CORPUS_DIR/r2025); viewer/tests/parameters-row.spec.ts (the viewer's `savedParameters` binding against rvt-elements on Einhoven and Core Interior); probes/examples/probe_re207_element_parameters.rs; probes/examples/probe_re281_parameter_pairs.rs; tools/re/element_parameters_vs_ifc.py; reports/element-framing/RE-207-element-parameters.md; reports/element-framing/RE-281-native-admission.md",
"notes": "Revit 2023 to 2027 files, and Revit 2015 to 2022 ones experimentally (RE-281). Each element's parameters are read from its native record (native_document::extract): its typed parameter sets (m_pParamValueSet*), the family slots of its own FamilyParams (FamilyInstance.m_pInstParams, FamilySymbol.m_pParams) a definition resolves, and the native fields read as built-in parameters. A parameter is named by its definition's m_caption (family, shared, project and global parameters); built-in parameters keep their negative id and no name, since the built-in catalog is not shipped (#255). A family instance's type (m_masterSymbolId) adds the type parameters the instance does not hold; a family parameter whose definition is an instance parameter is taken from the instance only. Values are saved, not evaluated, in internal units, with the SI value of a length, area, volume or angle. Measured against Revit's own IFC4 exports: on the BIM4LCA office (Revit 2024) every parameter named <set>.<property> whose property Revit writes on the element holds Revit's value, 7,606 of 7,606 as built and 7,592 of 7,592 at building permit; the housing on terrain 27 of 27; on the R2025 models a window's FireRating is its type's Fire Rating, 18 of 18. Exports made without Revit's own property sets do not show the other parameters, so their values are not measured. On Revit 2015 to 2022 no export saves a parameter to compare with: Autodesk's sample projects of those releases, read by name, hold the values the same project's Revit 2023 copy gives (932,645 equal and 243 different over 23 projects, the differences being what Revit changed between the saves, RE-281). A parameter whose graph needs the extensible-storage catalogue before Revit 2021, or a 2015 to 2017 VarSketch record, is not read. Not read: a family's built-in slots (a window type's Width and Height), formulas' evaluated values. Nothing new is written to IFC. The browser viewer lists them for a selected element, instance and type apart, through the `savedParameters` binding (rvt-wasm), which is this same read.",
"user_impact": "Scripts, the CLI and the viewer's info panel can read the family, shared and project parameters a Revit 2023 to 2027 model saves on each element and its type (2015 to 2022 experimentally, RE-281), by name, with units."
},
{
"id": "ifc-revit-property-sets",
"area": "parameters",
"name": "Revit's own property sets, one per parameter group, in rvt-ifc --revit-property-sets (RE-210)",
"status": "partial",
"evidence": "ifc::revit_property_sets::attach; IfcModel::type_property_sets (step_writer merges them into the type object's sets); rvt-ifc --revit-property-sets; tests/revit_property_sets.rs (RVT_NORDIC_LCA_DIR, RVT_PROJECT_CORPUS_DIR); probes/examples/probe_re210_revit_property_sets.rs; tools/re/revit_property_sets_vs_ifc.py; reports/element-framing/RE-210-revit-property-sets.md",
"notes": "Revit 2023 to 2027 files, and Revit 2015 to 2022 ones experimentally (RE-281: written there from the saved parameters, not measured against a Revit export with Revit property sets), with the option only. Each element's named saved parameters (RE-207) are written as revit-ifc's Release_25.x.x branch writes them with \"Export Revit property sets\" (ParameterUtil.CacheParametersForElement, PropertyUtil.CreateInternalRevitPropertySets, CreateRealPropertyByType; read and cited, not copied): one set per parameter group, named by Revit's English label for the group (Other for none), the IFC group left out, one parameter per name with its spaces removed in a group; the type's parameters in such sets on its type object, or on its elements with (Type) added where it has none. A Yes/No is an IfcBoolean, an integer with a spec an IfcInteger, a non-empty text an IfcText, a length, pipe or duct size an IfcLengthMeasure, an area, volume, angle (radians) or number its measure, an air flow, HVAC or piping pressure, apparent or electrical power, electrical potential or current an IfcVolumetricFlowRateMeasure, IfcPressureMeasure, IfcPowerMeasure, IfcElectricVoltageMeasure or IfcElectricCurrentMeasure in SI units (declared in the unit assignment when written), a material ElementId the material's name, a family type's '<family> : <type>' (the type's name alone where both are the same). Measured against Revit 2025's export of Autodesk's Snowdon Towers HVAC with Export Revit property sets (local only, not committed): 28,906 of 28,906 properties written (counted per element) are in the set of the same name, on the element or type object of the same Tag, with Revit's value; Revit writes 79,907 more, nearly all built-in parameters. On Snowdon Towers Architectural, 58,346 of 58,733; 369 are in sets Revit names with (Type) on 13 of its type objects, which follows from the order of its export, and 18 are curtain panels' type category, written before RE-210. Measured in CI against Revit 25.0.2's exports with Export Revit property sets of 19 of puzzbobb's Revit 2025 models (Apache-2.0): 2,502 of the 2,646 properties written are Revit's, 126 differ (Revit's export writes a window type's sill height and its nested families' lengths at 1/304.8 squared of their value) and 18, a stringer type's, are in no set Revit writes there; Revit writes 4,403 more, nearly all built-in parameters. Measured against Revit 2024's own export of the BIM4LCA office as built (common sets only): FireExit, written in Identity Data, equals Pset_DoorCommon and Pset_WindowCommon.FireExit on 498 of 498 doors and windows. Not written: built-in parameters (no name, #255), enumerations, other specs, (Type) names on exported type objects; the sets keep rvt-rs's own GlobalIds, not Revit's hashed ones.",
"user_impact": "An export can carry a model's family, shared and project parameters by name, grouped as Revit's own export with Revit property sets groups them."
}
],
"releases": [
{"release": 2008, "project_capability": "element-records-revit-2008-2010", "family_capabilities": []},
{"release": 2009, "project_capability": "element-records-revit-2008-2010", "family_capabilities": []},
{"release": 2010, "project_capability": "element-records-revit-2008-2010", "family_capabilities": []},
{"release": 2011, "project_capability": "element-records-revit-2011-2014", "family_capabilities": []},
{"release": 2012, "project_capability": "element-records-revit-2011-2014", "family_capabilities": []},
{"release": 2013, "project_capability": "element-records-revit-2011-2014", "family_capabilities": []},
{"release": 2014, "project_capability": "element-records-revit-2011-2014", "family_capabilities": []},
{"release": 2015, "project_capability": "element-records-revit-2015-2018", "family_capabilities": []},
{"release": 2016, "project_capability": "element-records-revit-2015-2018", "family_capabilities": ["metadata-partatom-preview", "formats-latest-schema"]},
{"release": 2017, "project_capability": "element-records-revit-2015-2018", "family_capabilities": ["metadata-partatom-preview", "formats-latest-schema"]},
{"release": 2018, "project_capability": "element-records-revit-2015-2018", "family_capabilities": ["metadata-partatom-preview", "formats-latest-schema"]},
{"release": 2019, "project_capability": "element-records-revit-2019-2022", "family_capabilities": ["metadata-partatom-preview", "formats-latest-schema"]},
{"release": 2020, "project_capability": "element-records-revit-2019-2022", "family_capabilities": ["metadata-partatom-preview", "formats-latest-schema"]},
{"release": 2021, "project_capability": "element-records-revit-2019-2022", "family_capabilities": ["metadata-partatom-preview", "formats-latest-schema"]},
{"release": 2022, "project_capability": "element-records-revit-2019-2022", "family_capabilities": ["metadata-partatom-preview", "formats-latest-schema"]},
{"release": 2023, "project_capability": "element-records-revit-2023", "family_capabilities": ["metadata-partatom-preview", "formats-latest-schema"]},
{"release": 2024, "project_capability": "typed-project-elements", "family_capabilities": ["metadata-partatom-preview", "formats-latest-schema"]},
{"release": 2025, "project_capability": "element-records-revit-2025", "family_capabilities": ["metadata-partatom-preview", "formats-latest-schema"]},
{"release": 2026, "project_capability": "element-records-revit-2026", "family_capabilities": ["metadata-partatom-preview", "formats-latest-schema"]},
{"release": 2027, "project_capability": "element-records-revit-2027", "family_capabilities": ["metadata-partatom-preview", "formats-latest-schema"]}
]
}