{
  "steward": "react-ux-otl-steward",
  "project": "Azure-AI-RAG-CSharp-Semantic-Kernel-Functions",
  "runDate": "2026-03-21",
  "runId": "2026-03-21T00-00-00",
  "findings": [
    {
      "id": "UOTL-ERROR-001",
      "title": "No React Error Boundaries — one render crash takes down the entire app",
      "severity": "critical",
      "category": "error-boundary",
      "file": "src/index.js",
      "description": "No React Error Boundary exists anywhere in the application. None of the six components implement componentDidCatch or are wrapped by an ErrorBoundary. A render-time exception in any component, including ChatLayout which renders unsanitized HTML via html-react-parser, will crash the entire app and show a blank screen with no user feedback and no team notification.",
      "recommendation": "Create a class-based ErrorBoundary component with componentDidCatch and getDerivedStateFromError. Wrap <App> at root level and wrap <SupportAgent> as a secondary boundary. componentDidCatch must call Application Insights trackException to report the error to monitoring.",
      "status": "open"
    },
    {
      "id": "UOTL-ERROR-002",
      "title": "No global unhandledrejection handler — API call failures are silently dropped",
      "severity": "critical",
      "category": "global-handler",
      "file": "src/SupportAgent/Agent.js",
      "description": "The handlePrompt and handleSession functions use fetch().then().then() promise chains with no .catch() handler. If the API call to /chat or /session fails due to a network error, CORS issue, or server error, the promise rejection is silently unhandled. No window.addEventListener('unhandledrejection') handler exists to capture these failures. Users receive no feedback and the team has no visibility into API failures.",
      "recommendation": "Add window.addEventListener('unhandledrejection', handler) in index.js to capture all unhandled rejections. Additionally add .catch() to each fetch chain in Agent.js to display user-facing error messages and report to Application Insights.",
      "status": "open"
    },
    {
      "id": "UOTL-ERROR-003",
      "title": "No window.onerror handler — runtime JS errors outside React cycle are invisible",
      "severity": "critical",
      "category": "global-handler",
      "file": "src/index.js",
      "description": "No window.onerror handler is registered. Runtime JavaScript errors that occur outside of React's render cycle — such as errors in event handlers, timer callbacks, or third-party scripts — are not captured by any monitoring mechanism. These errors are completely invisible to the team in production.",
      "recommendation": "Register window.onerror in index.js before the ReactDOM.render call. The handler should capture message, source, lineno, colno, and error, and report them to Application Insights via trackException once the SDK is integrated.",
      "status": "open"
    },
    {
      "id": "UOTL-APPINS-001",
      "title": "No Application Insights SDK — no frontend exceptions, page views, or traces in Azure Monitor",
      "severity": "notable",
      "category": "app-insights",
      "file": "package.json",
      "description": "The @microsoft/applicationinsights-web package is not installed. No Application Insights connection string, instrumentation key, or SDK initialization exists anywhere in the frontend codebase. For an Azure-hosted AI application, the absence of the Azure Monitor frontend SDK means there is no end-to-end correlation between frontend user actions and backend API calls, no exception tracking, and no availability telemetry from the client perspective.",
      "recommendation": "Install @microsoft/applicationinsights-web. Create an appInsights.js module that initializes the SDK using a connection string sourced from REACT_APP_APPINSIGHTS_CONNECTION_STRING. Integrate trackException() in error boundaries and global handlers. Call trackPageView() on route changes.",
      "status": "open"
    },
    {
      "id": "UOTL-PERF-001",
      "title": "reportWebVitals called with no callback — Core Web Vitals are collected and silently discarded",
      "severity": "notable",
      "category": "performance",
      "file": "src/index.js",
      "line": 20,
      "description": "reportWebVitals() is called in index.js with no argument. The reportWebVitals function only executes metric collection when onPerfEntry is truthy and a Function. As called, the condition fails and no web vitals data is gathered or reported. CLS, FID, FCP, LCP, and TTFB metrics are never sent anywhere. The web-vitals infrastructure exists but is completely inert.",
      "recommendation": "Pass a reporting callback to reportWebVitals(). For development: reportWebVitals(console.log). For production: create a callback that sends metrics to Application Insights via appInsights.trackMetric() or to a custom analytics endpoint.",
      "status": "open"
    },
    {
      "id": "UOTL-ERROR-004",
      "title": "fetch() calls have no .catch() — API errors produce no user feedback and no error capture",
      "severity": "notable",
      "category": "error-handling",
      "file": "src/SupportAgent/Agent.js",
      "description": "Both handlePrompt and handleSession use fetch chains with no .catch() handler. Network failures, server errors (5xx), or CORS rejections will silently drop the error. The chat UI will appear to freeze (the user's message appears but no response ever comes) with no error message and no logging. This is a poor user experience and a production observability gap.",
      "recommendation": "Add .catch(error => { ... }) to both fetch chains. Show an error message in the chat UI. Log the error and, once Application Insights is integrated, call appInsights.trackException({ exception: error }).",
      "status": "open"
    },
    {
      "id": "UOTL-LOG-001",
      "title": "console.log(res) in production code path — full API response exposed in browser console",
      "severity": "minor",
      "category": "logging",
      "file": "src/SupportAgent/Agent.js",
      "line": 38,
      "description": "A console.log(res) call logs the complete API response object in the handlePrompt fetch handler. This is in an unconditional production code path and will be visible to any user who opens browser developer tools. The API response may contain model outputs, internal metadata, or other information not intended for end-user inspection.",
      "recommendation": "Remove console.log(res). If response inspection is needed during development, gate it with if (process.env.NODE_ENV === 'development') { console.log(res); }.",
      "status": "open"
    },
    {
      "id": "UOTL-LOG-002",
      "title": "No structured logging abstraction — raw console calls used directly in components",
      "severity": "minor",
      "category": "logging",
      "file": "src/SupportAgent/Agent.js",
      "description": "The application has no logging abstraction layer. Console methods are used directly without log level management, production suppression, or routing to a monitoring backend. There is no way to control verbosity or redirect logs to Application Insights without touching every call site.",
      "recommendation": "Create a logger.js module that wraps console methods with conditional production suppression (based on NODE_ENV) and optionally forwards error-level calls to Application Insights. Import logger in components instead of using console directly.",
      "status": "open"
    },
    {
      "id": "UOTL-PERF-002",
      "title": "web-vitals infrastructure is in place — only the reporting callback is missing",
      "severity": "info",
      "category": "performance",
      "file": "src/reportWebVitals.js",
      "description": "The web-vitals package (v2.1.4) is installed and reportWebVitals.js correctly imports and invokes getCLS, getFID, getFCP, getLCP, and getTTFB. The scaffolding is complete; only a reporting callback needs to be wired up in index.js to activate performance monitoring.",
      "recommendation": "No structural change needed. Wire up the callback as described in UOTL-PERF-001.",
      "status": "open"
    },
    {
      "id": "UOTL-ARCH-001",
      "title": "Single-route SPA — error boundary placement strategy is straightforward",
      "severity": "info",
      "category": "architecture",
      "file": "src/App.js",
      "description": "The application has a single route and a flat component hierarchy: App > Main > SupportAgent > ChatLayout. This simplifies error boundary strategy. Two boundaries are sufficient: one at the App root (catches anything) and one wrapping SupportAgent (allows partial UI recovery if the chat widget crashes while header/footer remain visible).",
      "recommendation": "Use this hierarchy as the boundary placement guide when implementing UOTL-ERROR-001.",
      "status": "open"
    }
  ],
  "summary": {
    "critical": 3,
    "notable": 3,
    "minor": 2,
    "info": 2,
    "total": 10
  }
}
