from __future__ import annotations from ..models import PhysicalRelation, ValidationCheck from .base import ( BasePhysicalRelationValidator, PhysicalValidationContext, add_check, add_common_relation_checks, relation_code, ) class BoltedValidator(BasePhysicalRelationValidator): relation_type = "bolted" def validate( self, context: PhysicalValidationContext, relation: PhysicalRelation, checks: list[ValidationCheck], ) -> None: mount_id = relation.details.get("mount") extra = [mount_id] if isinstance(mount_id, str) else [] add_common_relation_checks(context, relation, checks, extra_components=extra) params = context.instance.industrial_parameters if params is None: add_check( checks, section="geometry", code=relation_code(relation, "geometry_clearance_or_fit"), passed=False, message="industrial parameters are required for bolted joint validation", ) return bolt_ids = [ component_id for component_id in context.snapshot.manifest.components if component_id.startswith("housing_bolt_") ] enough_bolts = len(bolt_ids) >= params.bolt_count bolt_circle_valid = ( params.bolt_circle_diameter_mm < params.housing_outer_diameter_mm and params.bolt_diameter_mm < params.housing_wall_thickness_mm ) add_check( checks, section="assembly", code=relation_code(relation, "fastener_count"), passed=enough_bolts, message="bolted industrial joint has the rule-computed housing fastener count", actual=len(bolt_ids), expected=params.bolt_count, ) add_check( checks, section="geometry", code=relation_code(relation, "geometry_clearance_or_fit"), passed=bolt_circle_valid, message="bolt circle and bolt diameter fit within housing wall", actual={ "bolt_circle_diameter_mm": params.bolt_circle_diameter_mm, "housing_outer_diameter_mm": params.housing_outer_diameter_mm, "bolt_diameter_mm": params.bolt_diameter_mm, "housing_wall_thickness_mm": params.housing_wall_thickness_mm, }, expected="bolt circle inside housing OD and bolt diameter < wall thickness", )