From ae51e6e83c23fa3d1b588ebcfbe71fe55b45a712 Mon Sep 17 00:00:00 2001 From: chihlasm Date: Fri, 20 Mar 2026 00:11:12 +0000 Subject: [PATCH] feat(analytics): wire flow usage tracking into session matching and resolution - In `start_session`: increment `flow.usage_count` and set `flow.last_matched_at` when a flow is matched to a new session; errors are caught without blocking - In `resolve_session`: recalculate `flow.success_rate` as (resolved / total) across all sessions ever matched to the flow after each resolution; errors are caught without blocking the session close Co-Authored-By: Claude Opus 4.6 (1M context) --- backend/app/services/flowpilot_engine.py | 35 +++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/backend/app/services/flowpilot_engine.py b/backend/app/services/flowpilot_engine.py index ddd047b5..ad02d1c8 100644 --- a/backend/app/services/flowpilot_engine.py +++ b/backend/app/services/flowpilot_engine.py @@ -11,7 +11,7 @@ from datetime import datetime, timezone from typing import Any, Optional from uuid import UUID -from sqlalchemy import select, or_ +from sqlalchemy import select, func, or_ from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.orm import selectinload @@ -20,6 +20,7 @@ from app.core.config import settings from app.services.notification_service import notify from app.models.ai_session import AISession from app.models.ai_session_step import AISessionStep +from app.models.tree import Tree from app.schemas.ai_session import ( AISessionCreateRequest, AISessionCreateResponse, @@ -308,6 +309,16 @@ async def start_session( ) db.add(session) + # 7a. Update matched flow usage tracking + if matched_flow_id: + try: + flow_result = await db.get(Tree, matched_flow_id) + if flow_result: + flow_result.usage_count = (flow_result.usage_count or 0) + 1 + flow_result.last_matched_at = datetime.now(timezone.utc) + except Exception as e: + logger.warning("Failed to update flow usage stats for flow %s: %s", matched_flow_id, e) + # 7. Create first step step = _create_step_from_parsed( session_id=session.id, @@ -457,6 +468,28 @@ async def resolve_session( # Queue for Knowledge Flywheel analysis session.analysis_status = "pending" + # Recalculate success_rate for the matched flow + if session.matched_flow_id: + try: + flow = await db.get(Tree, session.matched_flow_id) + if flow: + total_result = await db.execute( + select(func.count(AISession.id)) + .where(AISession.matched_flow_id == flow.id) + ) + resolved_result = await db.execute( + select(func.count(AISession.id)) + .where( + AISession.matched_flow_id == flow.id, + AISession.status == "resolved", + ) + ) + total = total_result.scalar() or 0 + resolved_count = resolved_result.scalar() or 0 + flow.success_rate = round(resolved_count / total, 3) if total else None + except Exception as e: + logger.warning("Failed to recalculate success_rate for flow %s: %s", session.matched_flow_id, e) + await db.flush() # Push documentation to PSA if ticket is linked