Skip to content

Multi-Discipline BOM Design

Foundation: BBC · DATA_MODEL · BIM_COBOL · MANIFESTO · TestArchitecture

9 disciplines, one compiler. Architectural, structural, plumbing, electrical, fire — each discipline brings its own BOM sub-tree and rules. The compiler enforces all of them through the same pipeline. Same grammar, different vocabularies.

CTFL Review Status (session 33, 2026-03-19)

Last reviewed: 2026-03-19 session 34 — CTFL review: §10.4 H3 blocker added, §10.5 handler witness claims + acceptance criteria added (12 witnesses, 6 auto-fix limits). Open: H1-H6 handlers DESIGNED, NOT IMPLEMENTED. Remaining blockers: AD_Clash_Rule (0 rows → H2), AD_Val_Rule SPACING (0 rows → H3), AD_Val_Rule CONTINUITY (0 rows → H5). See §10.4 for full status matrix.

How discipline-separated BOMs organize extracted buildings and prepare for generative placement

Governing principle: Each construction discipline (ARC, STR, PLB, ELC, FPR...) is a separate BOM sub-tree under its storey. This mirrors real-world drawing sheets (A-101, S-101, P-101, E-101) and construction contracts. The BOM structure is designed once for both extracted and generative modes — extraction populates positions, generative mode populates rules. Same schema, two modes.


1. Discipline Vocabulary

Derived from Terminal extraction (51,088 elements across 9 disciplines) and validated against standard construction drawing sheet conventions.

Code Discipline Drawing Sheet Terminal Count DX Count IFC Classes
ARC Architectural A-series 34,724 183 IfcWall, IfcDoor, IfcWindow, IfcSlab, IfcFurnishingElement, IfcCovering, IfcRailing, IfcStairFlight, IfcRoof, IfcRampFlight
STR Structural S-series 1,429 12 IfcBeam, IfcMember, IfcColumn, IfcSlab, IfcWall
FP Fire Protection FP-series 6,863 IfcFireSuppressionTerminal, IfcAlarm, IfcPipeSegment, IfcPipeFitting, IfcValve, IfcFlowController
ACMV Air Conditioning & Mechanical Ventilation M-series 1,621 IfcDuctSegment, IfcDuctFitting, IfcAirTerminal
CW Chilled Water 1,431 IfcPipeSegment, IfcPipeFitting, IfcFlowTerminal, IfcValve
ELEC Electrical E-series 1,172 IfcLightFixture, IfcElectricAppliance
SP Sanitary Plumbing P-series 979 IfcPipeSegment, IfcPipeFitting, IfcFlowTerminal, IfcValve
LPG Liquefied Petroleum Gas 209 IfcPipeSegment, IfcPipeFitting, IfcValve*
REB Reinforcing Bar S-series (sub) 2,660 IfcReinforcingBar

* Shared IFC classes: IfcPipeSegment, IfcPipeFitting, IfcValve, IfcFlowTerminal appear in multiple disciplines (FP, CW, SP, LPG). Disambiguation requires system_type from IFC property sets — see §5.

DX coarse mapping: DX extraction currently classifies all piping/electrical as MEP (904 elements). Reclassification into PLB/ELC/FPR needed for fine-grained discipline BOMs. SH has 3 CW elements (58 total: ARC+STR+CW).

SH stays flat: No discipline wrapper for proven single-discipline stone. RosettaStone integrity preserved as-is for sanity.


2. BOM Tree Structure — 5 Levels

Mirrors real construction drawing sheet hierarchy: discipline letter + storey number.

L0: BUILDING_DX_STD                      (the project)
│
├── DUPLEX_MEP_TRUNK_STD                  (storey-spanning verticals: risers)
│   ├── PLB_RISER_DX                      (plumbing riser)
│   ├── ELC_RISER_DX                      (electrical riser, if any)
│   └── FPR_RISER_DX                      (fire protection riser, if any)
│
├── FLOOR_DX_L1_STD                       (L1: storey)
│   ├── ARC_DX_L1                         (A-101: discipline BOM)
│   │   ├── room SETs (LIVING, KITCHEN…)  (assembly)
│   │   │   └── wall, door, window, furniture (leaves)
│   │   └── structural-arch (slabs, stairs, railings)
│   ├── PLB_DX_L1                         (P-101: plumbing)
│   │   └── pipe runs, fittings, fixtures
│   ├── ELC_DX_L1                         (E-101: electrical)
│   │   └── conduit runs, receptacles, switches, lights
│   ├── FPR_DX_L1                         (FP-101: fire protection)
│   │   └── sprinkler mains, heads, alarms
│   └── STR_DX_L1                         (S-101: structural)
│       └── beams, members
│
└── FLOOR_DX_L2_STD                       (L2: storey)
    ├── ARC_DX_L2                         (A-201)
    ├── PLB_DX_L2                         (P-201)
    ├── ELC_DX_L2                         (E-201)
    ├── FPR_DX_L2                         (FP-201)
    └── STR_DX_L2                         (S-201)

Terminal at scale (same structure):

L0: BUILDING_TE_STD
├── [per storey]
│   ├── ARC_TE_LXX       (~34,724 elements / N storeys)
│   ├── STR_TE_LXX       (~1,429)
│   ├── FP_TE_LXX        (~6,863)
│   ├── ACMV_TE_LXX      (~1,621)
│   ├── CW_TE_LXX        (~1,431)
│   ├── ELEC_TE_LXX      (~1,172)
│   ├── SP_TE_LXX        (~979)
│   ├── LPG_TE_LXX       (~209)
│   └── REB_TE_LXX       (~2,660)
└── [risers / storey-spanning trunks]

Why 5 levels is correct: A general contractor doesn't hand the whole building to the electrician. He hands him E-101 (Floor 1 Electrical), E-201 (Floor 2 Electrical), and the riser diagram. Three BOM nodes = three scopes of work. Each discipline BOM per storey = one drawing sheet = one subcontract scope. The hierarchy encodes contractual reality, not just element counts. Even FPR with 1 element on a floor gets its own node — fire protection is a separate contract, separate permit, separate inspection.

Storey first, then discipline: The subcontractor works one floor at a time within his trade. He completes Floor 1 electrical, then moves up. He doesn't install all conduits in the building top-to-bottom. Exception: risers (vertical trunks spanning storeys) sit at BUILDING level, not under any floor.


3. M_Product_Category as Discipline Classifier

M_Product_Category (the former M_BomCategory, now aligned with iDempiere naming) serves as the shared catalog classifier. Discipline routing uses AD_Org_ID (integer FK to AD_Org), not string codes:

AD_Org_ID Discipline Drawing Sheet Legacy bom_category
(per tenant) Architectural A-series ARC
(per tenant) Structural S-series STR
(per tenant) Plumbing P-series PLB
(per tenant) Electrical E-series ELC
(per tenant) Fire Protection FP-series FPR
(per tenant) HVAC/Mechanical M-series ACMV
(per tenant) Sanitary Plumbing P-series SP
(per tenant) LPG LPG
(per tenant) Reinforcing Bar S-series (sub) REB

Storey codes (GF, L1, L2, RF, FN, MS, CW) and room types (LI, BD, KT, FR, RE) remain on bom_category as catalog classifiers — they are not disciplines.

The discipline lives on AD_Org_ID, NOT on M_Product. A product is just a product (pipe, conduit, sprinkler head). Which discipline it belongs to is determined by which discipline org its BOM tree sits in. Same product can appear in multiple discipline BOMs — same screw in 50 BOMs (pure iDempiere pattern).


4. Two Classifiers on M_Product — Independent Dimensions

iDempiere teaches us two orthogonal classifiers:

Classifier Lives On What It Means Example
M_Product_Category m_bom (the BOM node) Organizational grouping — which trade PLB, ELC, FPR
M_AttributeSet M_Product (the leaf) Engineering behavior — how to parameterize BIM_Pipe, BIM_Wall

They correlate but don't collapse: - A BIM_Pipe product lives inside a PLB discipline BOM — but could also appear in FPR (fire protection pipes use same fittings). - A BIM_Component product (smoke detector) is discipline-agnostic at the product level — it becomes FPR by living under a FPR discipline BOM.

M_AttributeSet is for generative mode — when a user selects a wall variant (material, thickness) like iDempiere GardenWorld's T-shirt (Size S/M/L × Color Red/Blue). For extracted RosettaStones, there's no selection moment — the IFC file already decided. AttributeSet columns stay NULL during extraction.

Five attribute sets (§11.38, designed for generative future):

M_AttributeSet IsInstance Generative Role
BIM_Pipe 1 (length varies) Cross-section stamp; length = instance attribute
BIM_Conduit 1 (length varies) Same pattern as pipe
BIM_Wall 1 (height varies) Thickness stamp; height/length = instance
BIM_Slab 1 (area varies) Thickness stamp; area = instance
BIM_Component 0 (identical) Every instance is the same (qty on BOM line)

5. YAML Schema v2 — Discipline Classification

5.1 Structure

schema_version: 2

building:
  # ... existing fields (building_type, prefix, storeys, etc.) ...

  disciplines:
    ARC:
      ifc_classes: [IfcWall, IfcDoor, IfcWindow, IfcSlab,
                    IfcFurnishingElement, IfcCovering,
                    IfcRailing, IfcStairFlight, IfcRoof, IfcRampFlight]
      ad_org_id: ARC    # resolved to integer FK at load time

    STR:
      ifc_classes: [IfcBeam, IfcMember, IfcColumn, IfcPlate]
      ad_org_id: STR

    PLB:
      ifc_classes: [IfcPipeSegment, IfcPipeFitting, IfcFlowTerminal, IfcValve]
      filter: { system_type: [Domestic Cold Water, Domestic Hot Water,
                Sanitary, Waste, Hydronic Supply, Hydronic Return] }
      ad_org_id: PLB

    ELC:
      ifc_classes: [IfcLightFixture, IfcElectricAppliance,
                    IfcFlowSegment, IfcFlowTerminal, IfcFlowController]
      filter: { system_type: [Electrical, Telecom, Lightning] }
      ad_org_id: ELC

    FPR:
      ifc_classes: [IfcFireSuppressionTerminal, IfcAlarm, IfcSensor,
                    IfcPipeSegment, IfcPipeFitting, IfcValve, IfcFlowController]
      filter: { system_type: [Fire Alarm, Sprinkler, Fire Suppression] }
      ad_org_id: FPR

    ACMV:
      ifc_classes: [IfcDuctSegment, IfcDuctFitting, IfcAirTerminal]
      ad_org_id: ACMV

    SP:
      ifc_classes: [IfcPipeSegment, IfcPipeFitting, IfcFlowTerminal, IfcValve]
      filter: { system_type: [Sanitary Waste, Storm Drain, Vent] }
      ad_org_id: SP

    LPG:
      ifc_classes: [IfcPipeSegment, IfcPipeFitting, IfcValve]
      filter: { system_type: [LPG, Gas] }
      ad_org_id: LPG

    REB:
      ifc_classes: [IfcReinforcingBar]
      ad_org_id: REB

5.2 Disambiguation via system_type Filter

Some IFC classes (IfcPipeSegment, IfcPipeFitting, IfcValve) appear across multiple disciplines. The filter.system_type disambiguates using IFC property set data (Pset_DistributionSystemCommon.PredefinedType or similar).

Prerequisite: The extraction pipeline must capture system_type from IFC property sets into I_Element_Extraction. This column does not exist yet. Until it does, DX MEP elements can be classified by element_ref string parsing (e.g., "Domestic Cold Water" in the Revit type name) as an interim heuristic.

5.3 Schema v1 Backward Compatibility

Buildings without a disciplines: key (schema_version 1, e.g. classify_sh.yaml) default to single-discipline ARC — no discipline BOM level inserted. SH RosettaStone is untouched.


6. Extracted vs Generative — One Schema, Two Modes

The BOM model is designed once. Extraction populates positions. Generative mode (future) populates rules. Same columns, different fill patterns:

Column Extracted (current) Generative (future)
m_bom_line.dx/dy/dz Copied from IFC (parent-relative) Computed from rules + AABB
m_bom_line.layout_strategy NULL GRID, CEILING_RUN, AXIS_ALIGNED
m_bom_line.z_rule NULL CEILING_OFFSET, WALL_HEIGHT, FLOOR_EMBED
m_bom_line.anchor_face NULL TOP, WALL, FLOOR
m_bom_line.qty 1 (one line per element) N (rule expands to N instances)
m_attribute regulation params NULL max_spacing, coverage_area, regulation_ref

6.1 Generative Pattern Grammars (future reference)

The three-layer decomposition used here — space types (Semantic), adjacency/connectivity (Topological), component positions (Geometric) — is formally defined in Lin's STG Pattern [Lin 2017, Computer-Aided Design and Applications 14(3), DOI: 10.1080/16864360.2016.1240452]. The pattern hierarchy is grounded in Alexander's A Pattern Language [Alexander et al. 1977], where 253 patterns compose hierarchically in the same way that BOM lines recurse from building to leaf component. Empirical evidence that topological analysis can recover building typologies from real BIM models is provided by Bielski et al. [eCAADe 2020, DOI: 10.52842/CONF.ECAADE.2020.2.279]. See SPATIAL_COMPILATION_PAPER.md §2.5 for the full academic treatment.

Three discipline families produce three fundamentally different placement patterns:

ARC = Containment (nested boxes) Room enclosure: walls forming polygon + openings + furniture placed within AABB. Already proven in SH. Pattern = spatial arrangement within a bounding box.

STR = Grid repetition (parametric spacing) Column-beam grid at regular intervals. BOM captures one bay; qty + parametric offset reproduces the grid.

MEP = Topology (directed connection graph) Pipe/conduit runs: source → segment → fitting → segment → terminal device. Pattern = directed connection chain. Tack I/O captures which port connects where.

Examples (illustrative, not current scope): - Sprinkler grid: NFPA 13 Light Hazard → max 4.6m spacing, 2.3m from wall, 200mm below ceiling. Given room AABB, compiler produces head positions. - Conduit ceiling run: NEC-compliant axis-aligned routing, 25mm below slab soffit, 90° turns only, hanger every 1500mm.

These rules slot into the existing m_bom_line columns (layout_strategy, z_rule, anchor_face) and m_attribute overflow table without schema changes.

6.2 Tack I/O for MEP Topology (future)

Current m_bom_line has placement (dx/dy/dz) but not explicit connection ports. For ARC containment, position is sufficient. For MEP topology, the walker needs to know which port of a tee connects to which downstream pipe.

Future columns or m_attribute entries: - tack_in — upstream connection port identifier - tack_out — downstream connection port identifier(s) - connection_type — rigid, flexible, sealed, open

Not needed for extraction (positions are explicit). Required for generative MEP routing where the compiler must chain segments through fittings.

6.2.1 Port-Graph Extraction (S173)

IFC authored connectivity is available via IfcDistributionPort, IfcRelConnectsPorts, IfcRelConnectsPortToElement. Hospital MECH alone has 39,532 ports, 19,766 connections with SOURCE/SINK flow direction and exact world positions (connected ports = 0.0m distance).

Schema (in extracted DB): port_elements (port_guid, element_guid, flow_direction, local_x/y/z) + port_connections (port_a_guid, port_b_guid). Added to extractIFCtoDB.py REFERENCE_SCHEMA. Extraction: TODO.

Rotation proof — at load time, for sampled connected port pairs, reconstruct world position via rot(elem) @ local_port + centre(elem) for both sides; connected ports must meet within 10mm. No IFC needed. See scripts/stress_blender_test.py §PROOF PORT_CONNECT.

RouteWalker reuse — same tables feed RouteWalker.java and MepRouteGeometryTest.java via DB query. Replaces synthetic ad_mep_anchor with authored IFC connectivity.

Full spec: docs/DISC_VALIDATION_DB_SRS.md §1b Port-Graph Enrichment — includes mep_connectivity table, LOD matrix, RouteWalker integration, cross-check gate.


7. Implementation Sequence

Phase 1: DX Discipline Reclassification

  1. Reclassify DX's 904 MEP elements into PLB/ELC/FPR using element_ref heuristic
  2. Update I_Element_Extraction.discipline for DX elements
  3. Verify counts: PLB + ELC + FPR = 904

Phase 2: DX Discipline BOM Generation

  1. Update classify_dx.yaml to schema_version 2 with disciplines: map
  2. Extend IFCtoBOM pipeline to read discipline map and create per-storey discipline BOM nodes (ARC_DX_L1, PLB_DX_L1, ELC_DX_L1, etc.)
  3. Generate DX_BOM.db with discipline-organized BOM tree
  4. Verify: BOM walk reproduces all 1099 elements

Phase 3: Compilation Pipeline

  1. BOM walker traverses discipline BOM level transparently (it's just another m_bom node — no walker changes needed if the tree is correct)
  2. Verify: SH compilation unchanged (no discipline level in SH BOM)
  3. Verify: DX compilation produces same 1099 elements via discipline BOMs
  4. G1-G6 gates GREEN for both SH and DX

Phase 4: Terminal Discipline Structure (Phase B scope)

  1. Terminal already has 9 disciplines in I_Element_Extraction.discipline
  2. Assign storey values (currently "Unknown" for all Terminal elements)
  3. Create classify_te.yaml schema_version 2
  4. Generate TE_BOM.db with 9 discipline sub-trees per storey
  5. Scale proof: 51,088 elements organized into ~N×9 discipline BOMs

Phase 5: Hospital (HO_) — Full MEP Discipline Suite + Route/Walker

Reference: docs/HospitalAnalysis.md — 62,291 elements, 7 discipline IFCs (S136).

Hospital is the first building in the fleet with all four major MEP disciplines at clinical scale: MECH(19,670), SPR(13,490), PLB(9,121), ELE(2,798). It is the primary Route/Walker test model beyond Terminal's FP network.

HO_ Discipline BOM Structure

BUILDING_HOSP_STD
├── [per storey L1–L7A]
│   ├── ARC_HOSP_LXX    (~14,379 / 7 levels)
│   ├── STR_HOSP_LXX    (~2,827)
│   ├── MECH_HOSP_LXX   (~19,670) — HVAC: ducts, pipes, AHUs, FCUs
│   │   ├── MECH_HOSP_ICU_LXX     (positive pressure, HEPA, 25 ACH)
│   │   └── MECH_HOSP_WARD_LXX    (comfort cooling, 6 ACH)
│   ├── SPR_HOSP_LXX    (~13,490) — Sprinkler: mains, branches, heads, valves
│   │   ├── SPR_HOSP_STERILE_LXX  (stainless heads, clean zones)
│   │   └── SPR_HOSP_HELIPAD      (NFPA 15 foam-water, Level 7A only)
│   ├── PLB_HOSP_LXX    (~9,121)  — Plumbing: potable, waste, medical gas
│   └── ELE_HOSP_LXX    (~2,798)  — Electrical: lighting, controls
└── [risers — storey-spanning trunks]
    ├── MECH_RISER_HOSP
    ├── SPR_RISER_HOSP
    └── PLB_RISER_HOSP

Why HO_ Vocabulary ≠ TE_ Vocabulary

Hospital MEP is not generic commercial MEP. The product categories must be distinct:

TE_ product HO_ equivalent Why different
TE_ACMV (airport comfort) HO_MECH_ICU 25 ACH, HEPA, positive pressure — clinical standard
TE_CW (chilled water) HO_MECH_WARD Comfort cooling only; no LPG; medical gas instead
TE_SP (sanitary) HO_PLB_CLINICAL Copper (not galvanised), clinical washbasin spec
TE_FP (standard) HO_SPR_STERILE Stainless heads for sterile zones (NFPA 13 §11)
(no TE equivalent) HO_MED_GAS O₂/N₂/medical air — NFPA 99, HTM 02-01

This is the compiler's demonstrable edge: same IFC classes (IfcFlowSegment, IfcPipeFitting), completely different M_Product_Category vocabulary, resolved at compile time from AD_Org_ID + system_type filter (see §5.2).

Route/Walker Test Coverage — Disciplines Beyond FP

Terminal validated RouteSprinklersVerb for FP only. Hospital extends to all MEP disciplines:

Discipline Route/Walker Test Standard Witness Claim
SPR Head density per floor, zone valve coverage NFPA 13 W-HOSP-FP-1..5 (see HospitalAnalysis.md)
MECH HVAC duct continuity from AHU to terminal ASHRAE 170 W-HOSP-MECH-1: every FlowTerminal (AirTerminal) reachable from FlowSegment trunk
PLB Pipe run connectivity, no dead-end branches HTM 04-01 W-HOSP-PLB-1: every FlowTerminal (washbasin) reachable from PLB riser
ELE Light fixture coverage per floor area MS1525 / HTM 06-01 W-HOSP-ELE-1: fixture density ≥ 1 per N m² per room type
MECH vs SPR Co-routing clearance (HVAC ducts vs sprinkler mains) NFPA 13 §10.2 W-HOSP-FP-4 (AABB overlap < threshold)

MECH and PLB route tests do not require a new verb. They reuse the connectivity-walk pattern from RouteSprinklersVerb: load source-node elements (AHU / riser), walk rel_aggregates tree, assert all terminal nodes reachable. The verb is parameterised by ifc_class_source and ifc_class_sink — same algorithm, different class filter.

Implementation Sequence for Phase 5

  1. classify_hosp.yaml schema_version 2 with discipline block (MECH/SPR/PLB/ELE)
  2. Seed ad_ifc_class_map with HO_* product category overrides
  3. Generate HOSP_BOM.db with discipline sub-trees per storey
  4. W-HOSP-MECH-1: MECH duct connectivity witness (reachability from FlowSegment trunk)
  5. W-HOSP-PLB-1: PLB pipe connectivity witness
  6. W-HOSP-ELE-1: ELE fixture density witness
  7. W-HOSP-FP-1..5: SPR witnesses (head count, zone valve coverage, helipad NFPA 15)
  8. Regression: SH/TE/DX gates GREEN (no discipline vocabulary pollution)

Future: Generative Extension

  1. Add system_type column to I_Element_Extraction (from IFC property sets)
  2. Populate layout_strategy, z_rule, anchor_face on m_bom_line
  3. Populate m_attribute with regulation parameters (spacing, clearance, code ref)
  4. Compiler reads rules + AABB → produces positions (instead of copying from IFC)
  5. Tack I/O for MEP connection topology

8. Design Decisions

D1: Storey first, discipline second. Matches real construction sequencing — subcontractors work one floor at a time within their trade. Exception: risers (storey-spanning verticals) sit at BUILDING level.

D2: Fine discipline split even for small counts. FPR with 1 element on a floor still gets its own BOM node. Fire protection is a separate contract, separate permit, separate inspection. The BOM encodes contractual reality, not element count.

D3: SH stays flat. No discipline wrapper for proven single-discipline RosettaStone. Schema v1 backward compatibility — buildings without disciplines: key default to single-discipline, no extra BOM level.

D4: Discipline on BOM, not on Product. AD_Org_ID carries the discipline (integer FK to AD_Org — see S78). M_Product is discipline-agnostic. Same product can appear in multiple discipline BOMs (iDempiere pattern: same screw in 50 BOMs).

D5: AttributeSet is for generative mode. M_AttributeSet on M_Product defines product variant behavior (pipe length varies, component is identical). Irrelevant for extraction — relevant when the compiler generates placements from rules instead of copying from IFC.

D6: One schema, two modes. m_bom_line columns (layout_strategy, z_rule, anchor_face) and m_attribute regulation params stay NULL for extraction, get populated for generative mode. No schema changes when transitioning from extraction to generation.


9. LOD Assembly — Library Geometry Only

No parametric mesh in pipeline (feedback_no_parametric.md). Every element gets its geometry from component_library.db:

C_OrderLine.family_ref (product_id)
  → M_Product (width, depth, height, ifc_class)
  → component_definitions (attachment_face, orientation, geometry_hash)
  → component_geometries (vertices, faces, normals via geometry_hash)

ASI overrides instance sizing:
  M_AttributeSetInstance → M_AttributeInstance (width_mm, depth_mm, height_mm)
  ASI controls scaling — library LOD provides base shape.

9.1 DocEvent LOD Resolution Chain

When YAML.discipline = DocEvent, the engine resolves default products per space type and area via a 5-table chain spanning ERP.db (steps 1-3) and component_library.db (steps 4-5):

DocEvent processIt() for discipline FP in a BEDROOM (12m²):

Step 1: ad_space_type_mep_bom
  WHERE space_type_id = 'BEDROOM' AND mep_product_id = 'SPRINKLER'
  → qty_normal = 0  (use per_area instead)
  → per_area_normal = 0.07/m²  → qty = ceil(12 × 0.07) = 1
  → placement_rule = 'CEILING_GRID'
  → host_surface = 'CEILING'
  → building_code = 'NFPA 13', code_clause = '8.5.5'

Step 2: ad_element_mep
  WHERE element_type = 'SPRINKLER'
  → ifc_class = 'IfcFireSuppressionTerminal'
  → discipline = 'FP'
  → host_type = 'CEILING'
  → ports = [{"id":"IN","size":0.015}]
  → code_ref = 'NFPA 13'

Step 3: ad_fp_coverage (FP-specific spacing)
  WHERE hazard_class = 'LIGHT'  (from YAML occupancy_class or project default)
  → max_spacing_m = 4.6, min_spacing_m = 1.8
  → wall_distance_m = 2.3
  → max_coverage_m2 = 18.6
  → k_factor = 5.6

Step 4: M_Product (actual product with dimensions)
  Resolved via ad_element_mep_alias cascade (DISC_VALIDATION_DB_SRS.md §5.1):
    P1: ifc_class match → P2: predefined_type → P3: type_class → P4: element_name LIKE
  → product_id, width, depth, height
  → Multiple products may match — select by building_type affinity
    or closest dimensions to room context

Step 5: component_definitions → component_geometries (LOD mesh)
  WHERE name LIKE '%sprinkler%' (matched via product_id → geometry_hash)
  → attachment_face = 'TOP' (pendant) or 'BOTTOM' (upright)
  → orientation = 'PENDANT' or 'UPRIGHT'
  → geometry_hash → vertices, faces, normals (actual mesh)

9.2 Metadata Tables — What Each Contributes

Table Role Key Columns Drives
ad_space_type_mep_bom Default product schedule per room type space_type_id, mep_product_id, qty_normal, per_area_normal, placement_rule, host_surface, building_code HOW MANY + WHERE
ad_element_mep Logical MEP element definition element_type, ifc_class, discipline, host_type, ports, mount_height, clearance WHAT (ifc_class + ports)
ad_fp_coverage FP-specific coverage by hazard class hazard_class, max_spacing_m, max_coverage_m2, wall_distance_m, k_factor SPACING (FP only)
M_Product Physical product with dimensions product_id, width, depth, height, ifc_class DIMENSIONS
component_definitions LOD geometry link + attachment convention name, geometry_hash, attachment_face, orientation LOD MESH + ATTACHMENT
component_geometries Actual mesh data geometry_hash, vertices, faces, normals GEOMETRY

9.3 Quantity Resolution — Fixed vs Per-Area

Mode When Formula Example
Fixed qty qty_normal > 0 AND per_area_normal = 0 qty = qty_normal BATHROOM/TOILET = 1, KITCHEN/SINK = 1
Per-area per_area_normal > 0 qty = ceil(room_area_m2 × per_area_normal) OFFICE/SPRINKLER = ceil(50 × 0.07) = 4
Both zero qty_normal = 0 AND per_area_normal = 0 Not placed in this room type CORRIDOR/OUTLET = 0

9.4 Placement Rule → Verb Mapping

Placement Rule Verb Position Computation
CEILING_CENTER PLACE Room centroid, at ceiling Z
CEILING_GRID TILE / ALONG Grid at spacing from ad_fp_coverage or AD_Val_Rule
WALL_ENTRY PLACE Near door, at mount_height from ad_element_mep
WALL_SPACED ALONG Evenly spaced along longest wall
WALL_BACK PLACE Against back wall, at mount_height
WALL_SINK PLACE Adjacent to sink, at mount_height
WALL_COOKER PLACE Above cooker position
WALL_HIGH MOUNT High on wall (AC point: ~2.3m)
COUNTER_BACK PLACE At counter height, against wall
FLOOR_LOW PLACE Floor level, low point for drainage
AUTO (engine decides) Fallback — centroid or grid based on qty

9.5 Coverage by Space Type (current seed data)

Space Type SPRINKLER LIGHT OUTLET EXHAUST DIFFUSER Code Base
BEDROOM 0.07/m² 1 3 1 NFPA 13 + NEC + MS1525
BATHROOM 1 1 1 GFCI 1 NFPA 13 + NEC + IMC
KITCHEN 1 2 3×20A + 2 GFCI 1 1 NFPA 13 + NEC + IMC
LIVING 0.07/m² 2 4 1 NFPA 13 + NEC + MS1525
OFFICE 0.07/m² 0.1/m² 0.2/m² 1 NFPA 13 + NEC
CORRIDOR 0.05/m² 1 1 NFPA 13 + NEC
ASSEMBLY_HALL 0.07/m² 0.1/m² 6 1 NFPA 13 + NEC

Metadata-driven. Adding a new space type or changing a product count = SQL UPDATE, no Java change.


10. Post-Placement Handlers — Connectivity, Clash, Completeness

After elements are placed (by either {prefix}_BOM pipeline or DocEvent), handler routines run to ensure the placed elements form a valid construction system. These are iDempiere ModelValidator.afterSave() equivalents — they fire after each placement batch, not per-element.

10.1 Handler Cascade

Elements placed (from BOM pipeline or DocEvent)
  │
  ├── H1: CONNECTIVITY handler
  │   │  Ensures every terminal connects to a source via fittings/pipes.
  │   │
  │   │  IFC GROUPING SEMANTICS: IFC's IfcRelConnectsPortToElement and
  │   │  IfcDistributionPort define system topology. The BOM tree mirrors
  │   │  this: DISCIPLINE BOM → RISER (parent) → BRANCH (child) → HEAD
  │   │  (leaf). Parent-child in the BOM IS the connection graph. A
  │   │  disconnected element = orphan node with no parent in its
  │   │  discipline sub-tree. ad_assembly_connector.connects_to names
  │   │  the system network (PLUMBING_STACK, FP_MAIN, etc.) — the BOM
  │   │  tree path from leaf to root must traverse these system names.
  │   │
  │   │  For FP:  BFS from riser → every sprinkler head reachable?
  │   │  For CW:  BFS from supply → every fixture has supply_in?
  │   │  For SP:  BFS from stack → every fixture has waste_out?
  │   │  For ELEC: BFS from panel → every outlet/light has circuit?
  │   │
  │   │  Uses: ad_assembly_connector.connects_to (system graph)
  │   │        ad_element_mep.ports (port definitions)
  │   │        BOM tree Parent_OrderLine_ID (containment = connectivity)
  │   │
  │   │  If disconnected:
  │   │    → Auto-insert connecting pipe/conduit segments (ROUTE verb)
  │   │    → Or flag WARN: "sprinkler_23 unreachable from riser"
  │   │
  │   └── Writes: W_Verb_Node (verb_ref='CONNECT FITTINGS')
  │               W_Validation_Result (tier=1, CONNECTIVITY check)
  │
  ├── H2: NON-CLASH handler
  │   │  Ensures no hard/soft clashes between placed elements and
  │   │  elements from OTHER disciplines already in the BOM.
  │   │
  │   │  For each newly placed element:
  │   │    → ERP-maths clearance against all elements on same storey
  │   │      clearance = centroid_dist - radius_a - radius_b
  │   │    → Check AD_Clash_Rule for discipline pair
  │   │
  │   │  Uses: AD_Clash_Rule (discipline pairs, clash_type, min_distance_mm)
  │   │        M_Product dimensions (cross-section radii)
  │   │
  │   │  If clash detected:
  │   │    → HARD clash: nudge element to nearest clear position
  │   │    → SOFT clash: flag WARN with clearance value
  │   │    → MATERIAL clash: flag WARN with resolution_note
  │   │      ("Add fire collar at penetration point")
  │   │
  │   └── Writes: W_Validation_Result (tier=2, CLASH check)
  │               C_OrderLine.dx/dy/dz updated if nudged
  │
  ├── H3: SPACING COMPLIANCE handler
  │   │  Ensures placed elements meet code spacing requirements.
  │   │
  │   │  For FP:  NN distance between heads ∈ [min_spacing, max_spacing]
  │   │           Wall distance ≥ wall_distance_m (ad_fp_coverage)
  │   │  For ELEC: NN distance between fixtures ≤ max_spacing_mm
  │   │  For outlets: NEC 210.52 — max 1.8m from any point on wall
  │   │
  │   │  Uses: AD_Val_Rule (NFPA13_LH_SPACING, IES_LIGHT_SPACING, etc.)
  │   │        ad_fp_coverage (hazard-class-specific thresholds)
  │   │
  │   │  If spacing violated:
  │   │    → Adjust grid pitch to comply (recalc from processIt formula)
  │   │    → Or insert additional element to fill gap
  │   │    → Flag WARN if adjustment exceeds ±10% of typical_spacing
  │   │
  │   └── Writes: W_Validation_Result (tier=1, SPACING check)
  │
  ├── H4: HOST ATTACHMENT handler
  │   │  Ensures every placed element has a valid host surface.
  │   │
  │   │  IFC GROUPING SEMANTICS: IFC's IfcRelVoidsElement (openings in
  │   │  walls) and IfcRelFillsElement (doors/windows filling voids)
  │   │  encode host relationships explicitly. For MEP, IFC uses
  │   │  IfcRelContainedInSpatialStructure to place elements within
  │   │  their spatial container (storey/room). The BOM tree mirrors
  │   │  this: a CEILING-hosted element sits under a FLOOR node whose
  │   │  AABB defines the ceiling surface. A WALL-hosted element sits
  │   │  under a ROOM node with ad_wall_face defining available faces.
  │   │  Host existence = parent node + face existence in the BOM tree.
  │   │
  │   │  CEILING elements: parent FLOOR node has slab (AABB height > 0)
  │   │  WALL elements: parent ROOM node has ad_wall_face for that face
  │   │  FLOOR elements: parent FLOOR node has ground slab
  │   │
  │   │  Uses: ad_element_mep.host_type
  │   │        ad_space_type_mep_bom.host_surface
  │   │        ad_wall_face (room boundary faces)
  │   │        placement_rules (offset_from_host)
  │   │        BOM tree AABB (parent node dimensions)
  │   │
  │   │  If host missing:
  │   │    → Flag WARN: "light_01 has no ceiling host at Z=2.8m"
  │   │    → Snap to nearest valid host surface
  │   │
  │   └── Writes: W_Validation_Result (tier=1, HOST check)
  │
  ├── H5: VERTICAL CONTINUITY handler
  │   │  For risers/stacks that span storeys: verify X,Y alignment.
  │   │
  │   │  IFC GROUPING SEMANTICS: IFC's spatial containment hierarchy
  │   │  (IfcRelContainedInSpatialStructure, IfcRelAggregates) encodes
  │   │  the storey relationship. When elements sit under their correct
  │   │  IfcBuildingStorey, the absolute Z is inherited from the storey
  │   │  elevation. The BOM tree mirrors this exactly:
  │   │    BUILDING → FLOOR (dz = storey elevation) → DISCIPLINE → LEAF
  │   │  Tack dz on each node is RELATIVE to parent (BBC.md §4).
  │   │  World Z = sum of dz up the tree. This means vertical alignment
  │   │  is a TREE STRUCTURE concern, not a raw coordinate concern.
  │   │
  │   │  What H5 actually checks:
  │   │    → Riser elements exist under correct storey nodes
  │   │    → Same riser's dx/dy is IDENTICAL across storey nodes
  │   │      (only dz differs — inherited from parent FLOOR node)
  │   │    → If dx/dy differs across storeys → tree is malformed
  │   │
  │   │  Uses: AD_Val_Rule WHERE rule_type='CONTINUITY'
  │   │        max_xy_drift_mm per discipline
  │   │        BOM tree parent hierarchy (Parent_OrderLine_ID)
  │   │
  │   │  If drift detected:
  │   │    → Snap riser segment dx/dy to match storey below
  │   │    → Flag WARN if drift > tolerance
  │   │    → Root cause is almost always REPARENT to wrong node
  │   │
  │   └── Writes: W_Validation_Result (tier=3, CONTINUITY check)
  │
  └── H6: COMPLETENESS handler
      │  Ensures the room has all required MEP elements per
      │  ad_space_type_mep_bom schedule.
      │
      │  IFC GROUPING SEMANTICS: IFC's IfcRelAggregates decomposes a
      │  spatial element into its parts. A room (IfcSpace) aggregates
      │  all elements within it. The BOM tree mirrors this: ROOM node
      │  contains all LEAF children. Completeness = counting children
      │  of a ROOM node by mep_product_id and comparing to the schedule.
      │  The spatial container IS the count boundary — no spatial query
      │  needed, just a tree walk of C_OrderLine children.
      │
      │  For each space_type_id × mep_product_id row:
      │    → Count C_OrderLine children under ROOM node
      │      WHERE family_ref resolves to matching mep_product_id
      │    → Compare to qty_normal (or ceil(area × per_area_normal))
      │    → If count < required: flag WARN with missing items
      │
      │  Uses: ad_space_type_mep_bom (the schedule)
      │        BOM tree Parent_OrderLine_ID (room containment)
      │        AD_Org_ID on ROOM node (space_type + discipline lookup)
      │
      │  Example: BATHROOM missing EXHAUST_FAN
      │    → WARN: "BATHROOM requires 1 EXHAUST_FAN per IMC 2021 403.3"
      │
      └── Writes: W_Validation_Result (tier=1, COMPLETENESS check)

10.2 Handler Summary

Common handlers fire for ALL disciplines — both {prefix}_BOM and DocEvent. They are shared cross-cutting checks, like iDempiere's tax calculation that fires on every invoice line regardless of product category.

Handler What Common? Fires After Auto-Fix Tier
H1 CONNECTIVITY Every terminal reachable from source COMMON Each discipline batch Insert connecting segments 1
H2 NON-CLASH No hard/soft clashes across disciplines COMMON Each discipline batch Nudge to clear position 2
H3 SPACING Code-compliant spacing (NFPA, NEC, IES) DocEvent only FP, ELEC batches Adjust grid pitch 1
H4 HOST ATTACHMENT Every element has valid host surface COMMON Each discipline batch Snap to nearest host 1
H5 VERTICAL CONTINUITY Risers/stacks aligned across storeys COMMON After all storeys Snap to match below 3
H6 COMPLETENESS Room has all required MEP per schedule COMMON After all disciplines Flag missing items 1

H1, H2, H4, H5, H6 are common — they validate structural integrity regardless of how elements arrived (BOM pipeline or DocEvent). A pipe from {prefix}_BOM needs connectivity just as much as one placed by DocEvent.

H3 (SPACING) is DocEvent-only because {prefix}_BOM elements already have their spacing baked into the BOM tack positions from extraction. DocEvent computes spacing from rules, so it needs the compliance check.

10.3 Handler → Verb → Metadata Linkage

Handler Verb Used Metadata Read
H1 CONNECT FITTINGS, JOIN ad_assembly_connector, ad_element_mep.ports
H2 CHECK CLASH AD_Clash_Rule, M_Product (cross-section)
H3 CHECK PLACEMENT AD_Val_Rule, ad_fp_coverage
H4 ATTACH, MOUNT, HANG placement_rules, component_definitions.attachment_face
H5 (vertical check) AD_Val_Rule WHERE rule_type='CONTINUITY'
H6 (schedule audit) ad_space_type_mep_bom

All handlers write to W_Validation_Result in output.db. The ambient compliance strip in BIM Designer reads these results to show live status. Handlers that auto-fix also update C_OrderLine.dx/dy/dz (nudge/snap).

10.4 Implementation Status & Preconditions

Status (session 34): H1-H6 handlers are DESIGNED, NOT IMPLEMENTED. Zero handler code exists. The cascade above is the target specification.

Metadata table readiness (ERP.db created session 33):

Table DB Status Seeded? Blocks
ad_space_type_mep_bom ERP.db CREATED (DV001+DV002) YES — 186 rows (41 space types × 12 MEP products) H6
ad_element_mep ERP.db CREATED (DV001+DV002) YES — 12 element types H1, H4
ad_element_mep_alias ERP.db CREATED (DV003) YES — 84 alias rows (4-tier IFC cascade) H1, H4
ad_fp_coverage ERP.db CREATED (DV001+DV002) YES — 4 hazard classes H1, H3
ad_assembly_connector ERP.db CREATED (DV001+DV002) YES — 10 connector rows H1
ad_wall_face ERP.db CREATED (DV001+DV002) YES — 204 rows H4
placement_rules ERP.db CREATED (DV001+DV002) YES — 4801 rows H4
AD_Clash_Rule ERP.db SCHEMA ONLY NO — 0 rows H2 blocked
AD_Val_Rule (SPACING) ERP.db SCHEMA ONLY NO — 0 rows of type SPACING H3 blocked
AD_Val_Rule (CONTINUITY) ERP.db SCHEMA ONLY NO — 0 rows of type CONTINUITY H5 blocked

H3 SPACING blocked: H3 requires both ad_fp_coverage (seeded, 4 rows) AND AD_Val_Rule WHERE rule_type='SPACING' (0 rows). The coverage thresholds exist but the rule engine entry to trigger H3 does not. H3 fires DocEvent-only because {prefix}_BOM elements have spacing baked into tack positions from extraction.

Precondition for TE validation: CLUSTER verb fidelity must improve before handlers can produce meaningful results. Current 29mm max positional error (improved from 29m after F3 sort fix, session 34) may still generate false-positive clash/connectivity/spacing violations at tight tolerances. Handler implementation should follow CLUSTER→exact verb promotion.

Precondition for generative (DocEvent) validation: All metadata tables above must be seeded. H3 SPACING requires ad_fp_coverage + AD_Val_Rule rows. H2 NON-CLASH requires AD_Clash_Rule discipline-pair rows.

10.5 Handler Witness Claims

Each handler requires witness claims BEFORE implementation (CTFL best practice). Implementation is BLOCKED until these claims are written as @Test methods.

Witness Handler What it Proves Acceptance Criteria
W-H1-CONNECT-1 H1 Every FP head reachable from riser via BOM tree path BFS from riser node reaches all IfcFireSuppressionTerminal leaves. Path length ≤ 50 nodes.
W-H1-CONNECT-2 H1 Disconnected element flagged WARN Orphan leaf with no parent in discipline sub-tree → W_Validation_Result(tier=1, result='WARN').
W-H2-CLASH-1 H2 No hard clash between FP and ELEC on same storey ERP-maths clearance ≥ AD_Clash_Rule.min_distance_mm for all FP×ELEC pairs.
W-H2-CLASH-2 H2 Clash detected and nudged Element moved to nearest clear position. C_OrderLine.dx/dy/dz updated. W_Validation_Result(tier=2, result='WARN').
W-H3-SPACING-1 H3 FP NN spacing within [min, max] All head pairs ≥ min_spacing_m AND ≤ max_spacing_m from ad_fp_coverage.
W-H3-SPACING-2 H3 Wall distance ≥ wall_distance_m Every head ≥ wall_distance_m from nearest wall face (ad_fp_coverage).
W-H4-HOST-1 H4 Ceiling element has valid host Parent FLOOR node has slab (AABB height > 0). ad_element_mep.host_type = 'CEILING' matches.
W-H4-HOST-2 H4 Missing host flagged WARN Element with no valid host surface → W_Validation_Result(tier=1, result='WARN').
W-H5-CONT-1 H5 Riser X,Y identical across storeys Same riser's dx,dy values differ ≤ max_xy_drift_mm across all FLOOR nodes.
W-H5-CONT-2 H5 XY drift flagged WARN Riser with dx drift > max_xy_drift_mm → W_Validation_Result(tier=3, result='WARN').
W-H6-COMPLETE-1 H6 Room has all required MEP per schedule BATHROOM has ≥ 1 EXHAUST_FAN, 1 SPRINKLER, 1 LIGHT per ad_space_type_mep_bom.
W-H6-COMPLETE-2 H6 Missing element flagged WARN BATHROOM missing EXHAUST_FAN → W_Validation_Result(tier=1, result='WARN', description contains 'IMC 2021 403.3').

Auto-fix acceptance criteria:

Handler Auto-fix Action Limit If Exceeded
H1 Insert connecting pipe/conduit segment ≤ 3 segments WARN (manual routing needed)
H2 Nudge element to clear position ≤ 100mm WARN (clash too severe for auto-fix)
H3 Adjust grid pitch ≤ ±10% of typical_spacing WARN (room too small/large for standard grid)
H4 Snap to nearest valid host surface ≤ 200mm WARN (no host nearby)
H5 Snap riser dx/dy to match storey below ≤ max_xy_drift_mm BLOCK (tree structure error)
H6 Flag missing items (no auto-insert) WARN always (user decides)

TODO Registry (open items for future sessions)

TODO-FIXTURE-DEDUP — Cross-Discipline Fixture Deduplication (HO_ origin, S136)

Context: Hospital IFC has bathroom fixtures (toilets, wall-mounted sinks) placed independently in both ARC and PLB discipline models. Both are correctly stored with GUID prefixes. At 69mm Z offset (toilets) and 27mm Z offset (sinks), they visually stack in the viewport. Root cause: Revit multi-discipline authoring practice (ARC counts for HTM compliance, PLB places for pipe routing).

Rule: When ARC and PLB both claim the same physical fixture (same element_name, |ΔX| < 50mm, |ΔY| < 50mm, |ΔZ| < 100mm), the BOM quantity takeoff counts it once from the PLB subtree. ARC retains the element for spatial/compliance use but its C_OrderLine.qty_for_takeoff = 0.

Detection query:

SELECT e1.guid as arc_guid, e2.guid as plb_guid, e1.element_name,
       ABS(t1.center_z - t2.center_z) as z_offset_m
FROM elements_meta e1
JOIN element_transforms t1 ON t1.guid = e1.guid
JOIN elements_meta e2 ON e1.element_name = e2.element_name
JOIN element_transforms t2 ON t2.guid = e2.guid
WHERE SUBSTR(e1.guid,1,3) = 'ARC' AND SUBSTR(e2.guid,1,3) = 'PLB'
  AND ABS(t1.center_x - t2.center_x) < 0.05
  AND ABS(t1.center_y - t2.center_y) < 0.05
  AND ABS(t1.center_z - t2.center_z) < 0.10;

Affects: Hospital (confirmed: 120 toilet pairs + 92 sink pairs). Likely to appear in any federated building where ARC and MEP discipline files are authored in Revit. Scope: BOM compile step (BOMWalker or DisciplineBomBuilder), not extraction. Priority: Before HO_005 Route/Walker witnesses (quantity proofs require clean counts).

TODO-HO-PC-CONSISTENCY — HO_ Product Categories Aligned with TE_ (S136)

Context: Hospital MEP uses the same IFC classes as Terminal but different product vocabulary (medical gas, sterile HVAC, clinical plumbing — see HospitalAnalysis.md §HO_ vs TE_ MEP). When seeding ad_ifc_class_map for Hospital, new HO_ product categories must be consistent with the existing TE_ naming convention.

Rule: New product category codes follow pattern {BUILDING_PREFIX}_{DISCIPLINE}_{SUBTYPE}. Terminal examples: not yet explicitly prefixed (TE_ prefix should be added retroactively for consistency). Hospital to define: HO_MECH_ICU, HO_MECH_WARD, HO_SPR_STERILE, HO_PLB_CLINICAL, HO_MED_GAS. Verify TE_ equivalent names before naming HO_ to ensure the pattern is uniform across the fleet.

Session: HO_004 (after DECLARE ROOMS, before Route/Walker witnesses).

TODO-DECLARE-ROOMS-FLEET — Buildings Needing DeclareRoomsService (S136)

DeclareRoomsService (designed in FINISH_WALLS_SRS.md §11) is needed for any building with walls but no IfcSpace. Fleet audit as of S136:

Building Elements Walls IfcSpace DECLARE ROOMS needed?
Hospital 62,291 1,468 0 YES — HO_002
Terminal 48,428 333 0 YES (discipline-only model, no arch zones)
Schependomlaan 3,214 631 0 YES (residential — missing spatial zones)
HITOS 2,068 838 0 YES
SampleCastle 3,284 879 100 No (partial, may still benefit)
Clinic 2,989 1,080 269 No
Molio 2,791 98 117 No

Hospital is the primary implementation target (HO_002). Once implemented, the service applies fleet-wide to TE, Schependomlaan, and HITOS with no code changes.

TODO-SHOWCASE-POC — Large Building PoC Demo Candidates (S136)

For a Compiler-Designer model demonstration ("move a 62K-element building smoothly"):

Building Elements Type Status Demo value
Hospital 62,291 Healthcare Extracting (HO_001–HO_005) Primary — largest, most MEP-diverse
Terminal 48,428 Airport 8/8 PASS, fully gated Live demo-ready NOW
Clinic ~16K (federated) Healthcare companion 5 separate DBs, needs federation merge TE companion — same campus concept
Schependomlaan 3,214 Residential Partial gate ARC reference model quality

The "Healthcare Campus" demo: Hospital + Clinic in one ERP instance, same iDempiere tenant, two buildings under one project order. Hospital is the main block, Clinic is the outpatient annex. Combined ~78K elements under one BOM tree. This is the demo that proves the multi-building compiler-designer model at PoC scale. No other open-source BIM tool can do this without scene-graph memory collapse.

Clinic federation merge (using --guid-prefix DISC --append per S136 pattern) can be done in one session once Hospital HO_001–HO_002 are complete and the pattern is proven.


References: BBC.md §1 (P0.1-DEDUP), BOMBasedCompilation.md §4 (tack convention), TheRosettaStoneStrategy.md (discipline vocabulary), CONCEPTUAL BLUEPRINT.txt (MEP AttributeSet taxonomy), DocAction_SRS.md §1 (processIt lifecycle), DocValidate.md §13 (three-tier cascade), BIM_COBOL.md §4.6 (joining verbs)

Copyright (c) 2025-2026 Redhuan D. Oon. MIT Licensed.