Files
breakpilot-compliance/ai-compliance-sdk/internal/iace/models_api.go
T
Benjamin Admin afb3f83f30 feat(iace): cross-domain precision overhaul + component review + schema reconcile
Engine precision (stop foreign-machine patterns leaking into a project):
- Wire project.MachineType into the engine machine-type gate (empty input no
  longer fires every machine class — press/cnc/excavator/crane/medical...).
- Capability-domain gating extended by 7 domains (outdoor, ventilation,
  machining, bulk, palletizer, playground, fitness) so domain-specific hazards
  only fire when the narrative names that domain; emitted via keyword_dictionary.
- Relevance backstop moved into iace (single gating contract, testable), and its
  dominant false-anchor class removed (a long pattern word no longer matches a
  short common token; prepositions/leitung added to the generic stoplist).
- New guard tests: TestCrossDomainPrecision (full pipeline, 0 foreign per GT) and
  TestPatternReachability now asserts 0 dead patterns. Both GTs keep coverage 1.0.

Reachability fix: the 51 dead patterns required electrical/pneumatic/hydraulic
tags nothing produced — renamed to the canonical electrical_energy/
pneumatic_pressure/hydraulic_pressure/hydraulic_part.

Component review (negation is best-effort + expert-correctable):
- Parser surfaces negated components (ComponentMatch.Negated) instead of dropping
  them; negated contribute no tags/energy → no phantom hazards.
- presence_status (vorhanden|nicht_vorhanden|geloescht) + ce_marked on components;
  only `vorhanden` feed matching. CE+safety-relevant flags the PL/SIL obligation.
- Force re-seed preserves the expert's component decisions instead of wiping them.
- Tag-based component→hazard assignment (was: all on the first component).
- Negation-aware narrative parsing ("keine Pneumatik" no longer extracts it).

Local-dev DB: ai-sdk sets search_path=compliance,core,public; reconcile migrations
152-156 bring the consolidated local iace tables to the current schema + add the
presence_status/ce_marked columns. Machine-type vocabulary endpoint for the form.

[migration-approved]

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-10 17:15:55 +02:00

256 lines
12 KiB
Go

package iace
import (
"encoding/json"
"github.com/google/uuid"
)
// ============================================================================
// API Request Types
// ============================================================================
// CreateProjectRequest is the API request for creating a new IACE project
type CreateProjectRequest struct {
ParentProjectID *uuid.UUID `json:"parent_project_id,omitempty"`
MachineName string `json:"machine_name" binding:"required"`
MachineType string `json:"machine_type" binding:"required"`
Manufacturer string `json:"manufacturer" binding:"required"`
CustomerName string `json:"customer_name,omitempty"`
Description string `json:"description,omitempty"`
NarrativeText string `json:"narrative_text,omitempty"`
CEMarkingTarget string `json:"ce_marking_target,omitempty"`
Metadata json.RawMessage `json:"metadata,omitempty"`
}
// UpdateProjectRequest is the API request for updating an existing project
type UpdateProjectRequest struct {
MachineName *string `json:"machine_name,omitempty"`
MachineType *string `json:"machine_type,omitempty"`
Manufacturer *string `json:"manufacturer,omitempty"`
CustomerName *string `json:"customer_name,omitempty"`
Description *string `json:"description,omitempty"`
NarrativeText *string `json:"narrative_text,omitempty"`
CEMarkingTarget *string `json:"ce_marking_target,omitempty"`
Metadata *json.RawMessage `json:"metadata,omitempty"`
}
// CreateComponentRequest is the API request for adding a component to a project
type CreateComponentRequest struct {
ProjectID uuid.UUID `json:"project_id" binding:"required"`
ParentID *uuid.UUID `json:"parent_id,omitempty"`
Name string `json:"name" binding:"required"`
ComponentType ComponentType `json:"component_type" binding:"required"`
Version string `json:"version,omitempty"`
Description string `json:"description,omitempty"`
IsSafetyRelevant bool `json:"is_safety_relevant"`
IsNetworked bool `json:"is_networked"`
CEMarked bool `json:"ce_marked"`
// PresenceStatus defaults to "vorhanden" when empty (see Store.CreateComponent).
PresenceStatus string `json:"presence_status,omitempty"`
}
// CreateHazardRequest is the API request for creating a new hazard
type CreateHazardRequest struct {
ProjectID uuid.UUID `json:"project_id" binding:"required"`
ComponentID uuid.UUID `json:"component_id" binding:"required"`
LibraryHazardID *uuid.UUID `json:"library_hazard_id,omitempty"`
Name string `json:"name" binding:"required"`
Description string `json:"description,omitempty"`
Scenario string `json:"scenario,omitempty"`
Category string `json:"category" binding:"required"`
SubCategory string `json:"sub_category,omitempty"`
MachineModule string `json:"machine_module,omitempty"`
Function string `json:"function,omitempty"`
LifecyclePhase string `json:"lifecycle_phase,omitempty"`
HazardousZone string `json:"hazardous_zone,omitempty"`
TriggerEvent string `json:"trigger_event,omitempty"`
AffectedPerson string `json:"affected_person,omitempty"`
PossibleHarm string `json:"possible_harm,omitempty"`
}
// AssessRiskRequest is the API request for performing a risk assessment
type AssessRiskRequest struct {
HazardID uuid.UUID `json:"hazard_id" binding:"required"`
Severity int `json:"severity" binding:"required"`
Exposure int `json:"exposure" binding:"required"`
Probability int `json:"probability" binding:"required"`
Avoidance int `json:"avoidance,omitempty"` // 0=disabled, 1-5 (3=neutral)
ControlMaturity int `json:"control_maturity" binding:"required"`
ControlCoverage float64 `json:"control_coverage" binding:"required"`
TestEvidenceStrength float64 `json:"test_evidence_strength" binding:"required"`
AcceptanceJustification string `json:"acceptance_justification,omitempty"`
}
// CreateMitigationRequest is the API request for creating a mitigation measure
type CreateMitigationRequest struct {
HazardID uuid.UUID `json:"hazard_id" binding:"required"`
ReductionType ReductionType `json:"reduction_type" binding:"required"`
Name string `json:"name" binding:"required"`
Description string `json:"description,omitempty"`
}
// CreateVerificationPlanRequest is the API request for creating a verification plan
type CreateVerificationPlanRequest struct {
ProjectID uuid.UUID `json:"project_id" binding:"required"`
HazardID *uuid.UUID `json:"hazard_id,omitempty"`
MitigationID *uuid.UUID `json:"mitigation_id,omitempty"`
Title string `json:"title" binding:"required"`
Description string `json:"description,omitempty"`
AcceptanceCriteria string `json:"acceptance_criteria,omitempty"`
Method VerificationMethod `json:"method" binding:"required"`
}
// CreateMonitoringEventRequest is the API request for logging a monitoring event
type CreateMonitoringEventRequest struct {
ProjectID uuid.UUID `json:"project_id" binding:"required"`
EventType MonitoringEventType `json:"event_type" binding:"required"`
Title string `json:"title" binding:"required"`
Description string `json:"description,omitempty"`
Severity string `json:"severity" binding:"required"`
}
// InitFromProfileRequest is the API request for initializing a project from a company profile
type InitFromProfileRequest struct {
CompanyProfile json.RawMessage `json:"company_profile" binding:"required"`
ComplianceScope json.RawMessage `json:"compliance_scope" binding:"required"`
}
// ============================================================================
// API Response Types
// ============================================================================
// ProjectListResponse is the API response for listing projects
type ProjectListResponse struct {
Projects []Project `json:"projects"`
Total int `json:"total"`
}
// ProjectDetailResponse is the API response for a single project with related entities
type ProjectDetailResponse struct {
Project
Components []Component `json:"components"`
Classifications []RegulatoryClassification `json:"classifications"`
CompletenessGates []CompletenessGate `json:"completeness_gates"`
}
// RiskSummaryResponse is the API response for an aggregated risk overview
type RiskSummaryResponse struct {
TotalHazards int `json:"total_hazards"`
NotAcceptable int `json:"not_acceptable,omitempty"`
VeryHigh int `json:"very_high,omitempty"`
Critical int `json:"critical"`
High int `json:"high"`
Medium int `json:"medium"`
Low int `json:"low"`
Negligible int `json:"negligible"`
OverallRiskLevel RiskLevel `json:"overall_risk_level"`
AllAcceptable bool `json:"all_acceptable"`
}
// LifecyclePhaseInfo represents a machine lifecycle phase with labels
type LifecyclePhaseInfo struct {
ID string `json:"id"`
LabelDE string `json:"label_de"`
LabelEN string `json:"label_en"`
Sort int `json:"sort_order"`
}
// RoleInfo represents an affected person role with labels
type RoleInfo struct {
ID string `json:"id"`
LabelDE string `json:"label_de"`
LabelEN string `json:"label_en"`
Sort int `json:"sort_order"`
}
// EvidenceTypeInfo represents an evidence/verification type with labels
type EvidenceTypeInfo struct {
ID string `json:"id"`
Category string `json:"category"`
LabelDE string `json:"label_de"`
LabelEN string `json:"label_en"`
Tags []string `json:"tags,omitempty"`
Sort int `json:"sort_order"`
}
// ProtectiveMeasureEntry represents a protective measure from the library
type ProtectiveMeasureEntry struct {
ID string `json:"id"`
ReductionType string `json:"reduction_type"`
SubType string `json:"sub_type,omitempty"`
Name string `json:"name"`
Description string `json:"description"`
HazardCategory string `json:"hazard_category,omitempty"`
Examples []string `json:"examples,omitempty"`
NormReferences []string `json:"norm_references,omitempty"`
Tags []string `json:"tags,omitempty"`
// Mandatory indicates this measure is REQUIRED by a harmonized standard.
// When true, the measure must be implemented if the referenced norm is applied.
// The norm creates a "presumption of conformity" — deviating requires the
// manufacturer to independently prove equivalent safety.
Mandatory bool `json:"mandatory,omitempty"`
MandatoryNorm string `json:"mandatory_norm,omitempty"`
// RiskReduction describes the typical risk reduction effect of this measure.
// Used by the Suppression Engine to automatically calculate residual risk
// when measures are assigned to hazards.
RiskReduction *RiskReduction `json:"risk_reduction,omitempty"`
}
// RiskReduction describes how a protective measure reduces risk parameters.
// Deltas are negative integers (e.g. -2 means "reduces by 2 levels").
// The Suppression Engine cumulates deltas across all assigned measures
// and clamps each parameter to a minimum of 1.
type RiskReduction struct {
// SeverityDelta reduces the severity rating (e.g. -1 for PPE, -2 for inherent safe design).
SeverityDelta int `json:"severity_delta,omitempty"`
// ExposureDelta reduces the exposure/frequency rating (e.g. -2 for fixed guard, -1 for interlock).
ExposureDelta int `json:"exposure_delta,omitempty"`
// ProbabilityDelta reduces the probability rating (e.g. -2 for interlock, -1 for training).
ProbabilityDelta int `json:"probability_delta,omitempty"`
}
// ValidateMitigationHierarchyRequest is the request for hierarchy validation
type ValidateMitigationHierarchyRequest struct {
HazardID uuid.UUID `json:"hazard_id" binding:"required"`
ReductionType ReductionType `json:"reduction_type" binding:"required"`
}
// ValidateMitigationHierarchyResponse is the response from hierarchy validation
type ValidateMitigationHierarchyResponse struct {
Valid bool `json:"valid"`
Warnings []string `json:"warnings,omitempty"`
}
// VariantGap compares a variant project against its base project
type VariantGap struct {
BaseProject ProjectSummary `json:"base_project"`
Variant ProjectSummary `json:"variant"`
Gap GapDetail `json:"gap"`
}
// ProjectSummary is a lightweight project view for gap comparisons
type ProjectSummary struct {
ID uuid.UUID `json:"id"`
Name string `json:"name"`
HazardCount int `json:"hazard_count"`
MeasureCount int `json:"measure_count"`
}
// GapDetail describes the delta between variant and base project
type GapDetail struct {
AdditionalHazards int `json:"additional_hazards"`
AdditionalMeasures int `json:"additional_measures"`
CategoriesAffected []string `json:"categories_affected"`
}
// CompletenessGate represents a single gate in the project completeness checklist
type CompletenessGate struct {
ID string `json:"id"`
Category string `json:"category"`
Label string `json:"label"`
Required bool `json:"required"`
Passed bool `json:"passed"`
Details string `json:"details,omitempty"`
}