"""Sotto-step di avanzamento della raccolta (fase 1), uno per layer attivo. La fase di raccolta non deve apparire come un unico "step 1" opaco: emette un sotto-step per ciascun LAYER distinto in esecuzione (non per ogni recognizer, altrimenti le decine di regole genererebbero decine di voci), nominando il layer. """ from __future__ import annotations from core.contracts import LayerPriority, ScoringConfig from core.pipeline.collection import SpanCollector class FakeRec: def __init__(self, name: str, layer: LayerPriority) -> None: self.name = name self.layer = layer def analyze(self, text): # noqa: ARG002 return [] def test_collect_reports_one_substep_per_active_layer(): cfg = ScoringConfig(min_confidence=0.0) recs = [ FakeRec("rule_a", LayerPriority.RULES), FakeRec("rule_b", LayerPriority.RULES), # stesso layer → niente nuovo step FakeRec("gliner", LayerPriority.ZEROSHOT), ] events: list[tuple[float, str]] = [] SpanCollector(cfg).collect( recs, "testo di prova", progress=lambda f, m: events.append((f, m)) ) # Un sotto-step per LAYER distinto (2), non per recognizer (3). assert len(events) == 2 assert any("1/2" in m for _, m in events) assert any("2/2" in m for _, m in events) # Ogni sotto-step nomina il layer in esecuzione. assert any("Regole" in m for _, m in events) assert any("GLiNER" in m for _, m in events) def test_collect_substeps_advance_within_collection_band(): cfg = ScoringConfig(min_confidence=0.0) recs = [ FakeRec("rules", LayerPriority.RULES), FakeRec("gliner", LayerPriority.ZEROSHOT), ] fracs: list[float] = [] SpanCollector(cfg).collect( recs, "testo", progress=lambda f, m: fracs.append(f) ) # Le frazioni crescono e restano dentro la banda della raccolta (< fase cluster). assert fracs == sorted(fracs) assert all(0.0 <= f < 0.35 for f in fracs)