feat(compliance): GET /sdk/v1/compliance/obligation-status (file-backed graph)

Vertical slice over the Compliance Execution Graph: obligation_id -> accepted
controls -> required evidence -> status. NEVER auto-asserts fulfillment - with
no evidence collection wired (MVP), a mapped obligation is "not_assessed" and
every required evidence is "missing". Fail-closed: no id -> 400; unknown id ->
unknown_obligation; mapped-but-no-control -> unmapped; graph not loaded -> 503.

- ComplianceGraphHandlers (separate from the DB-backed ObligationsHandlers):
  loads Registry join keys + accepted control mappings + evidence once at start.
- LoadComplianceGraph: candidate-path resolution across dev/container/test.
- Data plumbing: Dockerfile now COPYs data/{control_mappings,evidence_requirements,
  obligations}; data/obligations/obligation_join_keys.json is a SYNCED COPY of the
  repo-root Registry contract (re-sync on Registry growth).
- Table-driven handler test (mapped/unmapped/unknown/400 + no-fulfillment-claim).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-06-25 19:29:37 +02:00
parent 8a9d5e7c4d
commit d4df1e01df
7 changed files with 1151 additions and 1 deletions
+2
View File
@@ -30,6 +30,7 @@ func registerRoutes(
maximizerHandlers *handlers.MaximizerHandlers,
regulatoryNewsHandlers *handlers.RegulatoryNewsHandlers,
useCaseHandler *handlers.UseCaseHandler,
complianceGraphHandlers *handlers.ComplianceGraphHandlers,
) {
v1 := router.Group("/sdk/v1")
{
@@ -54,6 +55,7 @@ func registerRoutes(
registerMaximizerRoutes(v1, maximizerHandlers)
registerUseCaseRoutes(v1, useCaseHandler)
v1.GET("/regulatory-news", regulatoryNewsHandlers.GetNews)
complianceGraphHandlers.RegisterRoutes(v1)
}
}