package ucca import ( "bufio" "encoding/json" "fmt" "os" "path/filepath" "strings" ) // ControlMapping is one persisted, versioned, REVIEWABLE link from a legal // obligation/requirement to a concrete framework control — a node in the curated // compliance graph (Regulation -> Obligation -> Control -> Evidence). The retriever only // PROPOSES candidates (mapping_status=candidate); a human/rule decision turns the good ones // into mapping_status=accepted, which is the audited truth the Advisor uses at runtime. // // There is intentionally NO probabilistic "confidence" field: once curated, a mapping is a // professional statement, not an AI guess. The retriever's score lives only in the rationale // of a candidate, never as structured truth. type ControlMapping struct { SourceNorm string `json:"source_norm"` // e.g. "CRA Annex I Part I (2)(c)" SourceRole string `json:"source_role"` // source_role of the norm (operational_requirement, ...) TargetFramework string `json:"target_framework"` // e.g. "OWASP ASVS" TargetControl string `json:"target_control"` // e.g. "V6.3.1" MappingType string `json:"mapping_type"` // supports | partially_supports | implements | related | contradicts MappingStatus string `json:"mapping_status"` // candidate | accepted | rejected | superseded Provenance string `json:"provenance"` // retriever_candidate | human_curated | rule_based ObligationID string `json:"obligation_id,omitempty"` // stable cross-session join key (Obligation Registry); empty until adopted, citation_unit is the interim bridge Rationale string `json:"rationale"` ReviewedBy string `json:"reviewed_by,omitempty"` // who decided (human or rule id) ReviewDate string `json:"review_date,omitempty"` // YYYY-MM-DD ReviewReason string `json:"review_reason,omitempty"` Version string `json:"version"` } // Allowed enum values — the deterministic "rule" layer that keeps the curated store clean. var ( mappingTypeValues = map[string]bool{"supports": true, "partially_supports": true, "implements": true, "related": true, "contradicts": true} mappingStatusValues = map[string]bool{"candidate": true, "accepted": true, "rejected": true, "superseded": true} provenanceValues = map[string]bool{"retriever_candidate": true, "human_curated": true, "rule_based": true} ) // Validate checks required fields + enum membership, and enforces the audit trail: any // human/rule DECISION (accepted/rejected) must carry who/when/why. Fail-closed at load. func (m ControlMapping) Validate() error { switch { case m.SourceNorm == "": return fmt.Errorf("control mapping: source_norm required") case m.TargetFramework == "": return fmt.Errorf("control mapping: target_framework required") case m.TargetControl == "": return fmt.Errorf("control mapping: target_control required") case !mappingTypeValues[m.MappingType]: return fmt.Errorf("control mapping: invalid mapping_type %q", m.MappingType) case !mappingStatusValues[m.MappingStatus]: return fmt.Errorf("control mapping: invalid mapping_status %q", m.MappingStatus) case !provenanceValues[m.Provenance]: return fmt.Errorf("control mapping: invalid provenance %q", m.Provenance) } if m.MappingStatus == "accepted" || m.MappingStatus == "rejected" { if m.ReviewedBy == "" || m.ReviewDate == "" || m.ReviewReason == "" { return fmt.Errorf("control mapping %s->%s: status %q requires reviewed_by + review_date + review_reason (audit trail)", m.SourceNorm, m.TargetControl, m.MappingStatus) } } return nil } // IsAccepted reports whether this mapping is the active audited truth. func (m ControlMapping) IsAccepted() bool { return m.MappingStatus == "accepted" } // ControlMappingSet is the loaded, indexed mapping store (forward + reverse lookup). type ControlMappingSet struct { All []ControlMapping bySourceNorm map[string][]ControlMapping byControl map[string][]ControlMapping } func controlKey(framework, control string) string { return framework + ":" + control } // ControlsFor returns the controls mapped to a source norm. acceptedOnly restricts to the // audited truth (what the Advisor may treat as fact). func (s *ControlMappingSet) ControlsFor(sourceNorm string, acceptedOnly bool) []ControlMapping { return filterAccepted(s.bySourceNorm[sourceNorm], acceptedOnly) } // ObligationsFor returns the norms mapped to a framework control (reverse lookup). func (s *ControlMappingSet) ObligationsFor(framework, control string, acceptedOnly bool) []ControlMapping { return filterAccepted(s.byControl[controlKey(framework, control)], acceptedOnly) } func filterAccepted(in []ControlMapping, acceptedOnly bool) []ControlMapping { if !acceptedOnly { return in } out := make([]ControlMapping, 0, len(in)) for _, m := range in { if m.IsAccepted() { out = append(out, m) } } return out } // LoadControlMappings reads every *.jsonl file under dir (one mapping per line; blank and // //-prefixed lines ignored), validates each row, and builds the index. An invalid row // aborts the whole load — fail-closed, because this is the audit truth, not best-effort. func LoadControlMappings(dir string) (*ControlMappingSet, error) { files, err := filepath.Glob(filepath.Join(dir, "*.jsonl")) if err != nil { return nil, err } set := &ControlMappingSet{ bySourceNorm: map[string][]ControlMapping{}, byControl: map[string][]ControlMapping{}, } for _, f := range files { fh, err := os.Open(f) if err != nil { return nil, err } sc := bufio.NewScanner(fh) sc.Buffer(make([]byte, 0, 64*1024), 1024*1024) line := 0 for sc.Scan() { line++ raw := strings.TrimSpace(sc.Text()) if raw == "" || strings.HasPrefix(raw, "//") { continue } var m ControlMapping if err := json.Unmarshal([]byte(raw), &m); err != nil { fh.Close() return nil, fmt.Errorf("%s:%d: %w", f, line, err) } if err := m.Validate(); err != nil { fh.Close() return nil, fmt.Errorf("%s:%d: %w", f, line, err) } set.All = append(set.All, m) set.bySourceNorm[m.SourceNorm] = append(set.bySourceNorm[m.SourceNorm], m) k := controlKey(m.TargetFramework, m.TargetControl) set.byControl[k] = append(set.byControl[k], m) } fh.Close() if err := sc.Err(); err != nil { return nil, err } } return set, nil }