a5687bbc65
RCI/Delta as a read-/reasoning layer ON TOP of the product-first pipeline. Answers "what changes relative to my existing Regulatory Map?" — NOT "what does the new law say in general". No UI, no ingestion (newsletter/mailbox), no RAG, no new regulations/controls, no legal evaluation outside the stored map. - 4 core objects (compliance/rci/schemas.py): ComplianceBaseline (snapshot of profile + map + registry obligations + required/present evidence), RegulatoryChange (simulated/provided INPUT), ObligationDelta (delta_type NEW|CHANGED|REMOVED| ALREADY_COVERED|NEEDS_REVIEW|NOT_APPLICABLE), ChangeImpactSummary. delta_type is a THIRD vocabulary, disjoint from ClaimCoverage (Welt 1) and ComplianceStatus (Welt 2). - create_baseline() snapshots the existing pipeline once; assess_change() computes deltas deterministically against the snapshot (no re-evaluation). - 12 tests = the 5 acceptance questions (affects product? new/changed? already covered by evidence? needs human review? not relevant?) + repeal/uncertain-reg/ missing-evidence/boundary. Existing pipeline tests stay green; mypy clean; LOC ok. - App/reasoning types only — no compliance-meta-model classes (freeze v1.0 untouched). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
45 lines
1.7 KiB
Python
45 lines
1.7 KiB
Python
"""Snapshot the current product-first pipeline into a ComplianceBaseline.
|
|
|
|
This is the ONLY place RCI runs the pipeline — to freeze a point-in-time map +
|
|
registry-linked obligations + their required evidence. Everything downstream
|
|
(delta computation) works purely against this snapshot, never re-evaluating.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import Dict, List, Optional
|
|
|
|
from compliance.profile.canonical import CanonicalProductRegulatoryProfile
|
|
from compliance.profile.to_reasoning import to_reasoning_profile
|
|
from compliance.reasoning.obligation_engine import derive_obligations
|
|
from compliance.regulatory_map.renderer import render_regulatory_map
|
|
|
|
from .schemas import ComplianceBaseline
|
|
|
|
|
|
def create_baseline(
|
|
profile: CanonicalProductRegulatoryProfile,
|
|
evidence_refs: Optional[Dict[str, List[str]]] = None,
|
|
baseline_id: str = "baseline",
|
|
created_at: Optional[str] = None,
|
|
) -> ComplianceBaseline:
|
|
reg_map = render_regulatory_map(profile)
|
|
obligations = derive_obligations(to_reasoning_profile(profile)).applicable_obligations
|
|
|
|
applicable: List[str] = []
|
|
required: Dict[str, List[str]] = {}
|
|
for ob in obligations:
|
|
if ob.registry_anchor: # only registry-linked obligations enter the baseline
|
|
applicable.append(ob.obligation_id)
|
|
required[ob.obligation_id] = list(ob.required_evidence)
|
|
|
|
return ComplianceBaseline(
|
|
baseline_id=baseline_id,
|
|
product_profile_snapshot=profile,
|
|
regulatory_map_snapshot=reg_map,
|
|
applicable_obligations=applicable,
|
|
obligation_evidence_required=required,
|
|
evidence_refs=dict(evidence_refs or {}),
|
|
created_at=created_at,
|
|
)
|