Files
stonks-oracle/services/intelligence_pipeline_v3/verification/models.py
T
Celes Renata a72f336ad1 feat: Intelligence Pipeline v3 — full implementation
Multi-stage evidence-grounded inference architecture replacing the
monolithic 9B model extraction pipeline. CPU-first specialist services
handle routine extraction while the 9B vLLM model is preserved for
semantic adjudication of ambiguous cases.

Key components:
- Capability-aware inference gateway (OpenAI-compatible + Ollama)
- Endpoint registry with DB migrations and REST API
- Sentence-aware document segmenter (property tests)
- Deterministic financial parsing with offset integrity
- Symbol resolution with ambiguity detection
- Specialist service (GLiNER2, dynamic batching, K8s deployment)
- Company-specific sentiment (FinBERT, calibration)
- Retrieval-based novelty and duplicate detection
- Confidence calibration pipeline
- Deterministic routing engine (property tests)
- 9B adjudication layer with VRAM gating
- Stock-specific impact model (features, labels, baseline, trained)
- Pipeline orchestrator (state machine, queues, leases, feature flags)
- Bounded parallelism (async workers, semaphore, load shedding)
- Observability (tracing, metrics, alerts)
- Compatibility adapter (v3→v2 golden mapping tests)
- Shadow/canary promotion framework
- Active learning and fine-tuning pipeline

Test results: 1,161 tests pass, ruff lint clean.
All 282 spec tasks completed.
2026-07-13 02:14:59 +00:00

101 lines
3.7 KiB
Python

"""Data models for evidence verification results and rejected candidates.
Provides structured types for offset verification, entity-evidence association,
numeric consistency checks, rejected-candidate storage, and verification reports.
"""
from __future__ import annotations
from datetime import datetime, timezone
from enum import Enum
from pydantic import BaseModel, Field
class RejectionReason(str, Enum):
"""Structured reason codes for candidate rejection during verification."""
INVALID_OFFSET = "invalid_offset"
TEXT_MISMATCH = "text_mismatch"
ENTITY_NOT_IN_EVIDENCE = "entity_not_in_evidence"
NUMERIC_INCONSISTENCY = "numeric_inconsistency"
UNSUPPORTED_CLAIM = "unsupported_claim"
SCHEMA_VIOLATION = "schema_violation"
CONFIDENCE_BELOW_THRESHOLD = "confidence_below_threshold"
class OffsetVerification(BaseModel):
"""Result of verifying a single evidence span's offsets against source text."""
span_id: str = Field(description="ID of the evidence span being verified.")
valid: bool = Field(description="Whether the span text matches source at offsets.")
reason: str | None = Field(
default=None,
description="Explanation when invalid (e.g., 'text mismatch at offset 42').",
)
class AssociationVerification(BaseModel):
"""Result of verifying that an entity appears in at least one linked evidence span."""
entity_id: str = Field(description="ID of the entity being verified.")
valid: bool = Field(description="Whether entity text was found in any linked span.")
reason: str | None = Field(
default=None,
description="Explanation when invalid (e.g., 'entity text not in any linked span').",
)
class NumericVerification(BaseModel):
"""Result of verifying a numeric fact against its evidence spans."""
fact_id: str = Field(description="ID of the numeric fact being verified.")
valid: bool = Field(description="Whether the numeric value was found in evidence text.")
found_value: str | None = Field(
default=None,
description="The value found in the evidence text, if any.",
)
expected_value: str = Field(description="The expected normalized value from the fact.")
reason: str | None = Field(
default=None,
description="Explanation when invalid (e.g., 'value 3.14 not found in evidence').",
)
class RejectedCandidate(BaseModel):
"""A candidate that was rejected during verification, stored for audit and learning."""
candidate_type: str = Field(
description="Type of candidate: entity, fact, event, relation, sentiment."
)
candidate_data: dict = Field(
description="Serialized candidate data for audit trail."
)
rejection_reason: RejectionReason = Field(
description="Structured reason code for rejection."
)
stage: str = Field(
description="Pipeline stage where rejection occurred (e.g., 'offset_verification')."
)
timestamp: datetime = Field(
default_factory=lambda: datetime.now(tz=timezone.utc),
description="When the rejection was recorded.",
)
class VerificationReport(BaseModel):
"""Summary report from a full verification pass over extraction candidates."""
total_candidates: int = Field(ge=0, description="Total candidates evaluated.")
verified: int = Field(ge=0, description="Candidates that passed verification.")
rejected: int = Field(ge=0, description="Candidates that failed verification.")
coverage_rate: float = Field(
ge=0.0,
le=1.0,
description="Proportion of candidates with valid evidence support.",
)
rejection_breakdown: dict[str, int] = Field(
default_factory=dict,
description="Count of rejections per RejectionReason code.",
)