417bcda68c
AssessObligationStatus traverses obligation_id -> (citation_unit) -> accepted controls -> required evidence -> status (erfuellt|offen|unklar). Evidence presence is a callback; MVP passes nil (nothing collected yet) -> offen. citation_spans = "pending" until the Legal-Knowledge-Graph session attaches them. This is the vertical slice that makes the graph a product feature: "CRA obligation fulfilled because evidence X/Y/Z is present", not "a doc exists". Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
72 lines
3.1 KiB
Go
72 lines
3.1 KiB
Go
package ucca
|
|
|
|
// ObligationStatus is the Advisor's vertical slice over the compliance graph for ONE legal
|
|
// obligation: which accepted controls satisfy it, what evidence they require, what's missing,
|
|
// and the resulting status. The point is "the required evidence is (not) present", not "a
|
|
// document exists". citation_spans is pending until the Legal-Knowledge-Graph session attaches
|
|
// them to the obligation (the upper half of the bridge).
|
|
type ObligationStatus struct {
|
|
ObligationID string `json:"obligation_id"`
|
|
LegalBasis []string `json:"legal_basis"` // the obligation's citation_units
|
|
Status string `json:"status"` // erfuellt | offen | unklar
|
|
Controls []ObligationControlStatus `json:"controls"`
|
|
CitationSpans string `json:"citation_spans"` // "pending" until the registry fills them
|
|
}
|
|
|
|
// ObligationControlStatus is one control under an obligation with its evidence picture.
|
|
type ObligationControlStatus struct {
|
|
Framework string `json:"framework"`
|
|
Control string `json:"control"`
|
|
MappingType string `json:"mapping_type"`
|
|
RequiredEvidence []EvidenceRequirement `json:"required_evidence"`
|
|
MissingEvidence []EvidenceRequirement `json:"missing_evidence"`
|
|
}
|
|
|
|
// AssessObligationStatus traverses obligation_id -> (citation_unit) -> accepted Controls ->
|
|
// required Evidence -> Status. hasEvidence reports whether a given (framework, control,
|
|
// evidence_type) is already collected; pass nil in the MVP (no collection yet) -> everything
|
|
// required is missing and the status is "offen". Unknown or unmapped obligation -> "unklar".
|
|
func AssessObligationStatus(joins *ObligationJoinKeys, mappings *ControlMappingSet, evidence *EvidenceRequirementSet, obligationID string, hasEvidence func(framework, control, evidenceType string) bool) ObligationStatus {
|
|
ob := joins.FindObligation(obligationID)
|
|
if ob == nil {
|
|
return ObligationStatus{ObligationID: obligationID, Status: "unklar", CitationSpans: "pending"}
|
|
}
|
|
st := ObligationStatus{
|
|
ObligationID: obligationID,
|
|
LegalBasis: ob.CitationUnits,
|
|
CitationSpans: "pending",
|
|
Controls: []ObligationControlStatus{},
|
|
}
|
|
ctrls := AcceptedControlsForObligation(*ob, mappings)
|
|
if len(ctrls) == 0 {
|
|
st.Status = "unklar" // no accepted control reaches it — we cannot assess
|
|
return st
|
|
}
|
|
anyMissing := false
|
|
for _, m := range ctrls {
|
|
req := evidence.RequiredFor(m.TargetFramework, m.TargetControl)
|
|
missing := make([]EvidenceRequirement, 0, len(req))
|
|
for _, e := range req {
|
|
if hasEvidence == nil || !hasEvidence(e.Framework, e.Control, e.EvidenceType) {
|
|
missing = append(missing, e)
|
|
}
|
|
}
|
|
if len(missing) > 0 {
|
|
anyMissing = true
|
|
}
|
|
st.Controls = append(st.Controls, ObligationControlStatus{
|
|
Framework: m.TargetFramework,
|
|
Control: m.TargetControl,
|
|
MappingType: m.MappingType,
|
|
RequiredEvidence: req,
|
|
MissingEvidence: missing,
|
|
})
|
|
}
|
|
if anyMissing {
|
|
st.Status = "offen"
|
|
} else {
|
|
st.Status = "erfuellt"
|
|
}
|
|
return st
|
|
}
|