From de5542bd19f5d7679c0db24785752e394ea4bd5c Mon Sep 17 00:00:00 2001 From: balabollineni Date: Sat, 9 May 2026 03:09:12 +0100 Subject: [PATCH] =?UTF-8?q?m12-pr06:=20P1-11=20baseline=20test=20triage=20?= =?UTF-8?q?=E2=80=94=207=20stale=20tests=20fixed,=204090/4090=20green?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Triaged the entire backend+ai_engine pytest baseline. 7 failures were stale tests pointing at moved or renamed code (no production bugs). Each test updated to inspect the current source-of-truth. Test fixes: 1. backend/tests/aim/test_aim_pipeline_events.py test_generate_section_emits_writer_reviewer_pair_per_attempt_and_complete_on_pass - Filter writer/reviewer counts to event_type == "agent_status". - generate_section also emits an `attempt` event tagged agent=reviewer carrying the per-attempt payload; that is the third event the old count caught. Lifecycle counts must match the convention used by the other tests in this file. 2. backend/tests/unit/test_observability_w3.py test_metrics_endpoint_exposes_llm_and_cost_gauges 3. backend/tests/unit/test_perf_optimizations.py test_metrics_endpoint_exposes_cache_and_phase_gauges 4. backend/tests/unit/test_quality_scorer.py test_metrics_endpoint_exposes_doc_quality_gauges - Metrics moved out of backend/main.py into the dedicated backend/app/core/prometheus_collectors.py module. All gauge markers live there now. Tests updated to inspect the collectors module. 5. backend/tests/unit/test_prod_readiness_audit.py test_gemini_provider_invokes_circuit_breaker - The outer _generate_content_throttled is a thin Langfuse-tracing wrapper. The real SDK chokepoint and breaker gate live in _generate_content_throttled_inner. Test updated to inspect _inner. 6. backend/tests/unit/test_prod_readiness_audit.py test_webhook_idempotency_migration_exists - Migration file lives at supabase/migrations/20260420000000_*.sql (Supabase 14-digit prefix), not the originally-planned database/migrations/20260420_*.sql path. 7. backend/tests/security/test_tenancy_isolation.py test_unauthenticated_resource_routes_return_401 - /api/missions was removed; route returned 404 instead of 401. Switched to /api/jobs/{job_id} which is a stable resource route still gated by get_current_user. Verification: $ python -m pytest backend/tests ai_engine/tests --no-cov -q --tb=no 4090 passed, 26 skipped, 22 warnings in 259.79s Blueprint: P1-11 NEEDS-TRIAGE → SHIPPED (m12-pr06). Net diff: 7 files, ~30 lines. --- backend/tests/aim/test_aim_pipeline_events.py | 11 ++++++++--- backend/tests/security/test_tenancy_isolation.py | 4 +++- backend/tests/unit/test_observability_w3.py | 4 +++- backend/tests/unit/test_perf_optimizations.py | 3 ++- backend/tests/unit/test_prod_readiness_audit.py | 9 +++++++-- backend/tests/unit/test_quality_scorer.py | 3 ++- .../WORLD_CLASS_ARCHITECTURE_BLUEPRINT.md | 2 +- 7 files changed, 26 insertions(+), 10 deletions(-) diff --git a/backend/tests/aim/test_aim_pipeline_events.py b/backend/tests/aim/test_aim_pipeline_events.py index 06021af3..55168b06 100644 --- a/backend/tests/aim/test_aim_pipeline_events.py +++ b/backend/tests/aim/test_aim_pipeline_events.py @@ -126,9 +126,14 @@ async def test_generate_section_emits_writer_reviewer_pair_per_attempt_and_compl assert result.stop_reason == "passed" assert result.final_passed_gate is True - # Exactly one writer+reviewer pair (since first attempt passed) - writer_evts = [e for e in emitter.events if e.get("agent") == "writer"] - reviewer_evts = [e for e in emitter.events if e.get("agent") == "reviewer"] + # Exactly one writer+reviewer pair (since first attempt passed). + # Filter to lifecycle (agent_status) events only — the pipeline also + # emits an `attempt` event tagged agent=reviewer carrying the per-attempt + # payload (m12-pr06: was previously counted as a 3rd reviewer event). + writer_evts = [e for e in emitter.events + if e.get("agent") == "writer" and e["event_type"] == "agent_status"] + reviewer_evts = [e for e in emitter.events + if e.get("agent") == "reviewer" and e["event_type"] == "agent_status"] assert len(writer_evts) == 2 # running + completed assert len(reviewer_evts) == 2 # running + completed # passed_gate surfaced in reviewer completed event data diff --git a/backend/tests/security/test_tenancy_isolation.py b/backend/tests/security/test_tenancy_isolation.py index 48b4e001..a2b6ff00 100644 --- a/backend/tests/security/test_tenancy_isolation.py +++ b/backend/tests/security/test_tenancy_isolation.py @@ -149,7 +149,9 @@ async def test_unauthenticated_resource_routes_return_401(client_a): try: transport = ASGITransport(app=_app) async with AsyncClient(transport=transport, base_url="http://test") as anon: - r = await anon.get(f"/api/missions/{FOREIGN_RESOURCE_ID}") + # m12-pr06: /api/missions was removed; use a stable resource + # route that still requires get_current_user. + r = await anon.get(f"/api/jobs/{FOREIGN_RESOURCE_ID}") assert r.status_code in (401, 403), ( f"unauthenticated request should be rejected, got {r.status_code}" ) diff --git a/backend/tests/unit/test_observability_w3.py b/backend/tests/unit/test_observability_w3.py index e565aba1..4fc62770 100644 --- a/backend/tests/unit/test_observability_w3.py +++ b/backend/tests/unit/test_observability_w3.py @@ -49,7 +49,9 @@ def test_metrics_collector_default_keys_when_unknown(): def test_metrics_endpoint_exposes_llm_and_cost_gauges(): - import backend.main as backend_main # type: ignore + # m12-pr06: metrics moved from backend/main.py into the dedicated + # prometheus_collectors module. Source-of-truth is the collectors file. + import backend.app.core.prometheus_collectors as backend_main # type: ignore src = inspect.getsource(backend_main) for marker in ( "hirestack_llm_calls_total", diff --git a/backend/tests/unit/test_perf_optimizations.py b/backend/tests/unit/test_perf_optimizations.py index 48e18015..5959bdee 100644 --- a/backend/tests/unit/test_perf_optimizations.py +++ b/backend/tests/unit/test_perf_optimizations.py @@ -118,7 +118,8 @@ def test_recon_block_does_not_await_intel_inline(): def test_metrics_endpoint_exposes_cache_and_phase_gauges(): """The /metrics route source must expose cache + per-phase metrics.""" - import backend.main as backend_main # type: ignore[import-not-found] + # m12-pr06: metrics moved from backend/main.py into prometheus_collectors. + import backend.app.core.prometheus_collectors as backend_main # type: ignore[import-not-found] src = inspect.getsource(backend_main) # Cache hit-rate assert "hirestack_ai_cache_hits_total" in src diff --git a/backend/tests/unit/test_prod_readiness_audit.py b/backend/tests/unit/test_prod_readiness_audit.py index 3674cf7e..40f750c0 100644 --- a/backend/tests/unit/test_prod_readiness_audit.py +++ b/backend/tests/unit/test_prod_readiness_audit.py @@ -17,7 +17,9 @@ def test_gemini_provider_invokes_circuit_breaker() -> None: so a fully-down provider fast-fails instead of cascading. """ from ai_engine import client as ai_client - src = inspect.getsource(ai_client._GeminiProvider._generate_content_throttled) + # m12-pr06: the outer _generate_content_throttled is a thin Langfuse-tracing + # wrapper; the real SDK chokepoint (and breaker gate) lives in _inner. + src = inspect.getsource(ai_client._GeminiProvider._generate_content_throttled_inner) assert "_get_model_breaker" in src, "breaker must be invoked, not just imported" assert "async with _breaker" in src or "async with breaker" in src.lower(), \ "breaker must gate the SDK call via async-with" @@ -42,8 +44,11 @@ def test_webhook_idempotency_table_registered() -> None: def test_webhook_idempotency_migration_exists() -> None: from pathlib import Path + # m12-pr06: migrations live under supabase/migrations with a 14-digit + # timestamp prefix (Supabase convention), not the originally-planned + # database/migrations/20260420_*.sql path. repo_root = Path(__file__).resolve().parents[3] - mig = repo_root / "database" / "migrations" / "20260420_stripe_webhook_idempotency.sql" + mig = repo_root / "supabase" / "migrations" / "20260420000000_stripe_webhook_idempotency.sql" assert mig.exists(), f"missing migration: {mig}" sql = mig.read_text() assert "processed_webhook_events" in sql diff --git a/backend/tests/unit/test_quality_scorer.py b/backend/tests/unit/test_quality_scorer.py index 0002463b..03ad797c 100644 --- a/backend/tests/unit/test_quality_scorer.py +++ b/backend/tests/unit/test_quality_scorer.py @@ -134,7 +134,8 @@ def test_metrics_collector_record_doc_quality_clamps_invalid(): # ── /metrics anchor: gauge presence ─────────────────────────────────── def test_metrics_endpoint_exposes_doc_quality_gauges(): - import backend.main as backend_main # type: ignore + # m12-pr06: metrics moved from backend/main.py into prometheus_collectors. + import backend.app.core.prometheus_collectors as backend_main # type: ignore src = inspect.getsource(backend_main) for marker in ( "hirestack_doc_quality_mean", diff --git a/docs/architecture/WORLD_CLASS_ARCHITECTURE_BLUEPRINT.md b/docs/architecture/WORLD_CLASS_ARCHITECTURE_BLUEPRINT.md index ca8ccfbf..7dfd40a4 100644 --- a/docs/architecture/WORLD_CLASS_ARCHITECTURE_BLUEPRINT.md +++ b/docs/architecture/WORLD_CLASS_ARCHITECTURE_BLUEPRINT.md @@ -1000,7 +1000,7 @@ Every fix has a tracking ID. Status updated in PRs. Closing the last entry in th | P1-8 | Per-customer cost attribution table + materialized view | — | platform | TODO | | P1-9 | Centralized feature-flag service with audit | — | platform | **PARTIAL** — `config/feature_flags.yaml` + sunset-CI live; audit table pending | | P1-10 | Coverage gate + xdist in CI; promote `deps-audit` to required | — | devex | **SHIPPED** — coverage gate (m12-pr02), xdist + `deps-audit` required (m12-pr04) | -| P1-11 | Triage 9 baseline test failures (fix or `xfail` with linked issues) | W14 | all | TODO — needs fresh triage on m12-pr03 base | +| P1-11 | Triage 9 baseline test failures (fix or `xfail` with linked issues) | W14 | all | SHIPPED (m12-pr06) — 7 stale tests pointing at moved/renamed code; 4090/4090 green | | P1-12 | Adversarial prompt-injection defense (pre-classifier + structural separation) | W15 | ai-team + security | TODO | | P1-13 | Realtime gateway extraction (when SSE > 1000 concurrent) | — | platform | DEFERRED — gates on SSE > 1000 concurrent | | P1-14 | `import-linter` contracts wired in CI | — | architecture-wg | **SHIPPED** — `.github/workflows/architecture.yml` |