rvt 0.4.0

Apache-2.0 clean-room reader for Autodesk Revit files (.rvt, .rfa, .rte, .rft) without Revit: metadata, previews and the embedded schema of 2016-2026 files, and typed elements with measured geometry from Revit 2024 and 2025 projects, exported as IFC4, glTF and plan SVG.
Documentation
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
{
  "schema_version": 1,
  "matrix_id": "rvt-rs-support-matrix",
  "reviewed": "2026-09-24",
  "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; checksum_page_framing; fuzz targets; checksum-page strip on Partitions, Global and (#410) Formats/Latest; 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 with 9 to 12 fields per release listed as unclassified; 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": "Decode typed elements from real project files",
      "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": "Narrow fail-closed MVP only. Seven BuiltInCategories on one Revit 2024 edge match Revit's exporter exactly; generic real-project typed extraction is still 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 typed decoder structs",
      "status": "partial",
      "evidence": "elements::all_decoders() (~81); 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.",
      "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) with zero false positives across six 2025 files; 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 and door Revit exported is exported, plus one door Revit's export leaves out. Room names, storeys, export-type overrides and wall types stay 2024-only. 2023 and 2026 are unsupported.",
      "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-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); 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; 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 only.",
      "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; 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); 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; 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-revit-2023",
      "area": "elements",
      "name": "Revit 2023 elements from their partition element records: identity, category and box (RE-81)",
      "status": "partial",
      "evidence": "src/partition_element_records_2023.rs; partition_schema_mvp::recover_2023_records and nested_in_openings; 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, examples/probe_re111_system_types_2023.rs, reports/element-framing/RE-111-system-types-2023.md; RE-112: partition_compound_structure::layer_layout, examples/probe_re112_layers_2023.rs, reports/element-framing/RE-112-layers-2023.md; RE-114: partition_names::ElementDataLayout / element_data_layout, 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, 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, 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, examples/probe_re122_beam_column_refs.rs, 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. 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: names, types, storeys, joins and profiles, design options, parameters, IFC export overrides (4 spread footings Revit writes as IfcSlab come out as IfcFooting). Einhoven (2023, no Revit export) gains 2 walls, 9 curtain panels and 2 windows, unverified.",
      "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; 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. PredefinedTypes are left unset. 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; PartitionElementRecord::design_option; 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 only.",
      "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); examples/probe_re38_names.rs; reports/element-framing/RE-38-family-and-type-names.md; 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); 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; 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); examples/probe_re65_stair_names.rs; reports/element-framing/RE-65-stair-names.md; RE-66: partition_names::find_railing_type_names; 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; 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; 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. 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. 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/partition_type_materials.rs; partition_schema_mvp::attach_type_materials; ifc::material_constituent_sets_from_types; step_writer IfcMaterialConstituentSet; 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, examples/probe_re113_type_materials_2023.rs, tools/re/element_materials_vs_ifc.py, reports/element-framing/RE-113-type-materials-2023.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: counter tops whose map carries a nested appliance's materials, planting Revit writes as <Unnamed>, Core Interior's windows. 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": "family-instance-transforms",
      "area": "elements",
      "name": "Family instances' transforms, and turned instances drawn turned (RE-87)",
      "status": "partial",
      "evidence": "src/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); 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, 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",
      "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.",
      "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 from their type's lengths (RE-93, RE-94, Revit 2024)",
      "status": "partial",
      "evidence": "partition_type_parameters::scan_partition_lengths / family_parameters_named / type_window_openings / type_door_openings; partition_schema_mvp::attach_window_openings / attach_door_openings (FILLER_OPENING_FIELDS) and filler_opening_from_fields; ifc::export_content FILLER_OPENING_PROPERTIES; ifc::filler_type_cut and entities::OpeningCut::z_range_feet; step_writer OverallWidth/OverallHeight; examples/probe_re93_window_openings.rs; examples/probe_re94_door_openings.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.",
      "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."
    },
    {
      "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 / scan_export_parameters / ExportParameters; ifc::category_map::lookup_export_override / predefined_type_for; tests/ifc_export_overrides.rs (CI tier 2); examples/probe_re45_ifc_export_parameters.rs; reports/element-framing/RE-45-ifc-export-parameters.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 to the declared element whose element-data header (RE-44) is the last one before it, at most 0x800 bytes back (0x1ac measured); 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. 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 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), 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); 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; unit tests in partition_stairs, export_content and step_writer; 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.",
      "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 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; unit tests in partition_beam_axes and export_content; examples/probe_re49_beam_axes.rs; reports/element-framing/RE-49-beam-axes.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), 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, 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",
      "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. Status is partial: ends are not trimmed, floor-join cuts are not applied, the section is a rectangle envelope, 17 beams (15 oblique with skewed ends) keep their box, and no licensed CI file has structural framing. Revit 2024 only.",
      "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."
    },
    {
      "id": "element-record-roof-outlines",
      "area": "elements",
      "name": "Roof and ceiling outlines from their sketch lines, sketch lines' exact recorded ends, and shed roofs along their slope (Revit 2024)",
      "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; unit tests in element_record_plan_profiles; 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; examples/probe_re96_sketch_arcs.rs; reports/element-framing/RE-96-sketch-arcs.md; element_record_plan_profiles::scan_sketch_curve_lists; 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; 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",
      "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. 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. Status is partial: hip and gable roofs (two or more defining edges) 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, cuts are not subtracted, 7 roofs keep their box, no licensed CI file has a roof, and the recorded ends are read on Revit 2024 only. 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.",
      "user_impact": "Roofs and more floors export with the shape of their sketch instead of the rectangle around it."
    },
    {
      "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)",
      "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; unit tests in partition_stairs, export_content, body_geometry and step_writer; examples/probe_re52_stair_treads.rs; 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",
      "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. 2024 only.",
      "user_impact": "Stairs export and display as steps instead of a box the height of the whole stair."
    },
    {
      "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; 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; 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; 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",
      "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 219 of 220, 2024_Core_Interior 78 of 86, 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 get no material. 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.",
      "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, examples/probe_re71_layered_joins.rs, tools/re/wall_layer_joins_vs_ifc.py, reports/element-framing/RE-71-layered-wall-joins.md, 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, 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), 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), examples/probe_re86_tapered_walls.rs, tools/re/tapered_walls_vs_ifc.py, reports/element-framing/RE-86-tapered-walls.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 decided end, 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. 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; Revit 2024) 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. Slanted walls (word 0, their angle in the wall's own data) keep their box.",
      "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); unit tests pinned to Snowdon GlobalIds; 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",
      "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 the project, site, building, openings, further pieces of an element, relationships and property sets. 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, 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.",
      "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; 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, class_tag_map 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": "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: 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); 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) plus the unit gates in src/element_record_plan_profiles.rs",
      "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."
    },
    {
      "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, the unit gates in src/element_record_wall_joins.rs including the_surviving_side_of_a_true_l_corner_is_still_over_trimmed, 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."
    },
    {
      "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), plus the unit gates in src/partition_element_records.rs and src/element_record_column_cuts.rs",
      "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 plus the unit gates in src/partition_type_records.rs; 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, 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>.",
      "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": "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); unit tests in partition_level_records; 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, 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); 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); 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; 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": "Honest empty Parameters row until carriers and host joins are proven.",
      "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": "ifc::schedule_csv unit tests; 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 decoded element or room, so coverage is exactly the decode coverage: typed rows on Revit 2024 project files with element records, scaffold-only elsewhere. Unknown values are empty cells. No room area: room bodies are record bounding boxes, not boundaries.",
      "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",
      "notes": "Geometry and export readiness reflect decoded coverage. Synthetic fixtures are scaffold-only.",
      "user_impact": "Useful local inspection without upload."
    },
    {
      "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."
    }
  ]
}