from pathlib import Path from qonto_assistant.audit import AuditLogger from qonto_assistant.contracts import ActorClaims from qonto_assistant.policy import PolicyEngine from qonto_assistant.qonto_client import FixtureQontoClient from qonto_assistant.rate_limits import ConcurrencyLimiter, RateLimiter from qonto_assistant.service import CapabilityService POLICY_FILE = Path(__file__).resolve().parents[1] / "src" / "qonto_assistant" / "policy" / "qonto-v1.yaml" FIXTURE_DIR = Path(__file__).resolve().parent / "fixtures" / "qonto" def _claims() -> ActorClaims: return ActorClaims(actor_id="codex", tenant_id="binky", lane="green") def _service() -> CapabilityService: return CapabilityService( client=FixtureQontoClient(fixture_dir=FIXTURE_DIR), policy=PolicyEngine.from_file( POLICY_FILE, required_scope="finance.qonto.read", enforce_scope=False, ), audit_logger=AuditLogger(sink=lambda _: None), rate_limiter=RateLimiter(limit=20, window_seconds=60), concurrency_limiter=ConcurrencyLimiter(limit=4), ) def test_snapshot_recent_window_excludes_recurring_hint() -> None: payload = _service().get_snapshot( claims=_claims(), request_id="req-snapshot-31", window_days=31, page_size=50, ) assert payload["cost_run_rate_hints"]["recurring_debits"] == [] def test_snapshot_90_day_window_detects_recurring_hint() -> None: payload = _service().get_snapshot( claims=_claims(), request_id="req-snapshot-90", window_days=90, page_size=50, ) recurring = payload["cost_run_rate_hints"]["recurring_debits"] assert recurring[0]["label"] == "HUB31" assert recurring[0]["occurrences"] == 2