Files
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

193 lines
6.9 KiB
Python

"""Tests for deprecation tracking module — Task 51."""
from __future__ import annotations
from services.intelligence_pipeline_v3.deprecation.tracker import (
DEFAULT_DEPRECATIONS,
DeprecationEntry,
DeprecationStatus,
DeprecationTracker,
MigrationReport,
)
class TestDeprecationEntry:
"""Task 51: Deprecation lifecycle."""
def test_create_entry(self):
entry = DeprecationEntry.create(
component_name="VLLMClient",
component_path="services/extractor/vllm_client.py",
reason="Replaced by OpenAICompatibleClient",
known_consumers=["worker.py", "thesis_llm.py"],
replacement="services/shared/inference/clients/openai_compatible.py",
)
assert entry.status == DeprecationStatus.DEPRECATED
assert entry.migration_progress == 0.0
assert not entry.all_consumers_migrated
def test_mark_consumer_migrated(self):
entry = DeprecationEntry.create(
component_name="VLLMClient",
component_path="services/extractor/vllm_client.py",
reason="Replaced",
known_consumers=["worker.py", "thesis_llm.py"],
)
entry.mark_consumer_migrated("worker.py")
assert entry.migration_progress == 0.5
entry.mark_consumer_migrated("thesis_llm.py")
assert entry.migration_progress == 1.0
assert entry.all_consumers_migrated
assert entry.status == DeprecationStatus.MIGRATION_COMPLETE
def test_approve_removal_requires_all_migrated(self):
entry = DeprecationEntry.create(
component_name="v2_prompt",
component_path="services/extractor/prompts.py",
reason="Replaced by staged extraction",
known_consumers=["worker.py"],
)
# Cannot approve before migration
assert not entry.approve_removal("admin")
# After migration
entry.mark_consumer_migrated("worker.py")
assert entry.approve_removal("admin")
assert entry.removal_approved
def test_mark_removed(self):
entry = DeprecationEntry.create(
component_name="truncation",
component_path="services/extractor/prompts.py",
reason="Replaced by segmenter",
known_consumers=["prompts.py"],
)
entry.mark_consumer_migrated("prompts.py")
entry.approve_removal("admin")
entry.mark_removed()
assert entry.status == DeprecationStatus.REMOVED
assert entry.removed_at is not None
def test_no_known_consumers_means_ready(self):
entry = DeprecationEntry.create(
component_name="old_defaults",
component_path="services/shared/config.py",
reason="Conflicting defaults removed",
known_consumers=[],
)
assert entry.all_consumers_migrated
assert entry.migration_progress == 1.0
class TestDeprecationTracker:
"""Task 51: Full deprecation tracking workflow."""
def test_add_and_get(self):
tracker = DeprecationTracker()
entry = DeprecationEntry.create(
component_name="VLLMClient",
component_path="vllm_client.py",
reason="replaced",
)
tracker.add(entry)
assert tracker.get("VLLMClient") is entry
def test_mark_migrated(self):
tracker = DeprecationTracker()
entry = DeprecationEntry.create(
component_name="VLLMClient",
component_path="vllm_client.py",
reason="replaced",
known_consumers=["worker.py"],
)
tracker.add(entry)
assert tracker.mark_migrated("VLLMClient", "worker.py")
assert tracker.get("VLLMClient").all_consumers_migrated
def test_can_remove(self):
tracker = DeprecationTracker()
entry = DeprecationEntry.create(
component_name="VLLMClient",
component_path="vllm_client.py",
reason="replaced",
known_consumers=["worker.py"],
)
tracker.add(entry)
assert not tracker.can_remove("VLLMClient")
tracker.mark_migrated("VLLMClient", "worker.py")
assert not tracker.can_remove("VLLMClient") # Not approved yet
tracker.approve_removal("VLLMClient", "admin")
assert tracker.can_remove("VLLMClient")
def test_pending_removals(self):
tracker = DeprecationTracker()
e1 = DeprecationEntry.create(
"comp1", "path1", "reason", known_consumers=["c1"]
)
e2 = DeprecationEntry.create(
"comp2", "path2", "reason", known_consumers=["c2"]
)
tracker.add(e1)
tracker.add(e2)
tracker.mark_migrated("comp1", "c1")
tracker.approve_removal("comp1", "admin")
assert len(tracker.pending_removals) == 1
assert tracker.pending_removals[0].component_name == "comp1"
def test_generate_report(self):
tracker = DeprecationTracker()
e1 = DeprecationEntry.create(
"VLLMClient", "path1", "replaced", known_consumers=["w1", "w2"]
)
e2 = DeprecationEntry.create(
"v2_prompt", "path2", "replaced", known_consumers=["w1"]
)
tracker.add(e1)
tracker.add(e2)
tracker.mark_migrated("VLLMClient", "w1")
tracker.mark_migrated("v2_prompt", "w1")
report = tracker.generate_report()
assert report.total_components == 2
assert report.deprecated == 1 # VLLMClient still has w2
assert report.migration_complete == 1 # v2_prompt is done
assert len(report.blocked_removals) == 1
class TestDefaultDeprecations:
"""Task 51: Default deprecation entries cover required components."""
def test_default_entries_defined(self):
assert len(DEFAULT_DEPRECATIONS) >= 5
def test_vllm_client_in_defaults(self):
names = [d["component_name"] for d in DEFAULT_DEPRECATIONS]
assert "VLLMClient" in names
def test_v2_prompt_in_defaults(self):
names = [d["component_name"] for d in DEFAULT_DEPRECATIONS]
assert "v2_extraction_prompt" in names
def test_provider_branching_in_defaults(self):
names = [d["component_name"] for d in DEFAULT_DEPRECATIONS]
assert "provider_branching" in names
def test_truncation_in_defaults(self):
names = [d["component_name"] for d in DEFAULT_DEPRECATIONS]
assert "8000_char_truncation" in names
def test_compatibility_adapter_in_defaults(self):
names = [d["component_name"] for d in DEFAULT_DEPRECATIONS]
assert "compatibility_adapter" in names
class TestMigrationReport:
"""Task 51.5: Archive final migration reports."""
def test_report_to_dict(self):
entries = [
DeprecationEntry.create("c1", "p1", "r", known_consumers=["x"]),
]
report = MigrationReport.generate(entries)
d = report.to_dict()
assert "total_components" in d
assert "blocked_removals" in d