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.
193 lines
6.9 KiB
Python
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
|