Files
breakpilot-compliance/backend-compliance/compliance/product_scope/schemas.py
T
Benjamin Admin 4e8eb2dc0e feat(product-scope): gate Navigator facts, then reuse discover_scope (step 3)
Connects the Navigator's fact-gate to the existing reasoning discover_scope —
the Scope Engine decides only once the minimum (P0) facts are released.

- resolve_product_scope(canonical): if not ready_for_scope -> NEEDS_FACTS
  (missing_facts + suggested_questions, discover_scope NOT run); else project
  canonical->reasoning profile and run the EXISTING discover_scope exactly once
  -> RESOLVED with applicable/excluded/uncertain regulations.
- Environmental triggers surface ONLY as unsupported_domains (future_corpus_needed),
  never as a legal evaluation — transparency, no false completeness.
- POST /reasoning/product-scope (thin handler) returns case NEEDS_FACTS or RESOLVED.
- No new scope rules, no new regulations, no environmental-law evaluation, no UI,
  no Go, no RAG, no percent-compliance. Response types are application-level, not
  meta-model classes (freeze v1.0 untouched).
- 6 tests incl. discover_scope spy (0 calls when gated, exactly 1 when ready),
  category separation, environmental-as-unsupported-only. 47 tests green (existing
  reasoning MVP tests stay green), mypy clean, LOC ok.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-26 10:21:27 +02:00

64 lines
2.1 KiB
Python

"""Response schemas for the product-scope orchestrator (step 3).
These are application/API types — NOT compliance-meta-model classes (architecture
freeze v1.0 untouched). The scope verdict itself is produced by the existing
`discover_scope`; nothing here adds scope rules.
"""
from __future__ import annotations
from enum import Enum
from typing import List, Optional
from pydantic import BaseModel, Field
from compliance.navigator.engine import CompletenessSummary
from compliance.navigator.questions import NavigatorQuestion
from compliance.profile.canonical import CanonicalProductRegulatoryProfile
from compliance.reasoning.enums import Confidence
from compliance.reasoning.schemas import (
ApplicableRegulation,
ExcludedRegulation,
UncertainRegulation,
)
class ScopeStatus(str, Enum):
NEEDS_FACTS = "needs_facts" # P0 facts missing -> ask, do not decide
RESOLVED = "resolved" # minimum facts present -> scope decided
class UnsupportedDomain(BaseModel):
"""A domain the product triggers but the corpus does not yet cover.
Surfaced for transparency (no false completeness) — NEVER a legal evaluation.
"""
domain: str
trigger: str
status: str = "future_corpus_needed"
note: str = ""
class RegulatoryScopeResult(BaseModel):
applicable_regulations: List[ApplicableRegulation] = Field(default_factory=list)
excluded_regulations: List[ExcludedRegulation] = Field(default_factory=list)
uncertain_regulations: List[UncertainRegulation] = Field(default_factory=list)
unsupported_domains: List[UnsupportedDomain] = Field(default_factory=list)
reasoning_summary: str = ""
confidence: Confidence = Confidence.MEDIUM
class ProductScopeRequest(BaseModel):
product_profile: CanonicalProductRegulatoryProfile
class ProductScopeResponse(BaseModel):
status: ScopeStatus
completeness_summary: CompletenessSummary
# case NEEDS_FACTS
missing_facts: List[str] = Field(default_factory=list)
suggested_questions: List[NavigatorQuestion] = Field(default_factory=list)
# case RESOLVED
regulatory_scope: Optional[RegulatoryScopeResult] = None