var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
(function() {
  "use strict";
  const _GuardRAIl = class _GuardRAIl {
    constructor() {
      __publicField(this, "isInitialized", false);
      __publicField(this, "isProcessing", false);
      __publicField(this, "isSendingMessage", false);
      // Guard to prevent duplicate sends
      __publicField(this, "currentPromptId", null);
      __publicField(this, "currentConversationId", null);
      __publicField(this, "originalPrompt", "");
      __publicField(this, "conversationHistory", []);
      __publicField(this, "dialogElement", null);
      __publicField(this, "storedSignals", null);
      // Store signals from analyzePrompt
      __publicField(this, "observer", null);
      __publicField(this, "allowNextSend", false);
      __publicField(this, "platform", "unknown");
      // Post-handoff state tracking (persisted to sessionStorage)
      __publicField(this, "handoffCompleted", false);
      // Flag for current conversation
      __publicField(this, "bypassAttemptCount", 0);
      // Escalation counter (resets per conversation)
      __publicField(this, "postHandoffMessagesSinceHandoff", 0);
      // Allowlist: next few messages after handoff
      // CRITICAL: Prevent re-interception of the same prompt
      __publicField(this, "lastAllowedPrompt", null);
      __publicField(this, "lastAllowedPromptTime", 0);
      __publicField(this, "PROMPT_DEBOUNCE_MS", 2e3);
      // Don't re-intercept same prompt within 2 seconds
      /** When true, do not intercept — let sends go through (lock off in popup). */
      __publicField(this, "guardrailDisabled", false);
      /** Learning score for current intercept dialog (for feedback snapshot). */
      __publicField(this, "currentDialogRating", null);
      /** When true, use fixed 3-question flow and single polishLearningPrompt call (no per-turn REFINE_PROMPT). */
      __publicField(this, "useFixedThreeStepFlow", false);
      // OPTIMIZATION: Cache DOM elements to avoid repeated queries
      __publicField(this, "cachedSendButton", null);
      __publicField(this, "cachedInputElement", null);
      __publicField(this, "guardrailIndicator", null);
      __publicField(this, "lastButtonCheck", 0);
      __publicField(this, "lastSendButtonNotFoundLog", 0);
      // Throttle "send button not found" to once per 15s
      __publicField(this, "debounceTimer", null);
      __publicField(this, "reattachIntervalId", null);
      __publicField(this, "BUTTON_CHECK_INTERVAL", 200);
      // Check for button every 200ms (shorter = fewer missed sends)
      __publicField(this, "boundKeydownHandler", (e) => this.handleKeyDown(e));
      __publicField(this, "boundSubmitHandler", (e) => {
        const form = e.target;
        if (!form || !form.querySelector('[data-testid="send-button"], button[aria-label*="Send" i]')) return;
        if (this.allowNextSend) {
          console.log("GuardRAIl: Allowing form submit through (allowNextSend)");
          return;
        }
        if (this.guardrailDisabled) return;
        console.log("GuardRAIl: Intercepting form submission");
        e.preventDefault();
        e.stopPropagation();
        e.stopImmediatePropagation();
        const syntheticEvent = new Event("submit", { bubbles: false, cancelable: true });
        this.handleSubmit(syntheticEvent);
      });
      // NEW: Proactive conversation caching for better context awareness
      __publicField(this, "conversationCache", []);
      __publicField(this, "lastCacheUpdate", 0);
      __publicField(this, "CACHE_UPDATE_INTERVAL", 2e3);
      // Update cache every 2 seconds max
      __publicField(this, "conversationCacheObserver", null);
      __publicField(this, "conversationCacheDebounce", null);
      // NEW: ChatGPT response monitoring (dual policing)
      __publicField(this, "lastChatGPTMessage", null);
      __publicField(this, "lastChatGPTMessageTimestamp", 0);
      __publicField(this, "chatGPTResponseObserver", null);
      // ACCURACY FIX: Adaptive monitoring based on engagement
      __publicField(this, "consecutiveGoodLearningPrompts", 0);
      // Track consecutive good learning prompts
      __publicField(this, "monitoringFrequency", 1);
      // 1 = every response, 3 = every 3rd, 5 = every 5th
      __publicField(this, "responsesSinceLastMonitoring", 0);
      // Counter for adaptive frequency
      __publicField(this, "MAX_MONITORING_FREQUENCY", 10);
      // Stop monitoring after this many consecutive good prompts
      // NEW: Intervention queue for rapid-fire shortcuts
      __publicField(this, "interventionQueue", []);
      __publicField(this, "isProcessingIntervention", false);
      // TEST MODE: Safe testing helpers with auto-logging
      __publicField(this, "testModeEnabled", false);
      __publicField(this, "testLogs", []);
      __publicField(this, "testCallCount", 0);
      __publicField(this, "testTokenCount", 0);
      __publicField(this, "testStartTime", null);
      __publicField(this, "testAutoDisableTimer", null);
      /**
       * IMPROVED: Update conversation cache from DOM with optimized extraction
       * Only scrolls when necessary (old tabs with empty cache), not on every update
       */
      __publicField(this, "lastScrollTrigger", 0);
      __publicField(this, "SCROLL_TRIGGER_INTERVAL", 1e4);
      // Client-side max turns to prevent infinite loops
      __publicField(this, "MAX_DIALOG_TURNS", 5);
      this.platform = this.detectPlatform();
      if (document.readyState === "loading") {
        document.addEventListener("DOMContentLoaded", () => {
          this.restoreHandoffState();
          this.init();
        });
      } else {
        this.restoreHandoffState();
        this.init();
      }
    }
    getHandoffStorageKey(convId) {
      const id = convId ?? _GuardRAIl.HANDOFF_KEY_NEW;
      return _GuardRAIl.HANDOFF_STORAGE_PREFIX + id;
    }
    /** Keep only the most recently used conversation keys to avoid unbounded storage. */
    pruneHandoffStorage() {
      try {
        const keys = [];
        for (let i = 0; i < sessionStorage.length; i++) {
          const k = sessionStorage.key(i);
          if (k && k.startsWith(_GuardRAIl.HANDOFF_STORAGE_PREFIX)) keys.push(k);
        }
        if (keys.length <= _GuardRAIl.MAX_HANDOFF_KEYS) return;
        const withTime = [];
        for (const k of keys) {
          try {
            const raw = sessionStorage.getItem(k);
            if (!raw) continue;
            const state = JSON.parse(raw);
            withTime.push({ key: k, time: state.lastCacheUpdate ?? 0 });
          } catch {
            withTime.push({ key: k, time: 0 });
          }
        }
        withTime.sort((a, b) => b.time - a.time);
        for (let i = _GuardRAIl.MAX_HANDOFF_KEYS; i < withTime.length; i++) {
          sessionStorage.removeItem(withTime[i].key);
        }
      } catch (e) {
        console.warn("GuardRAIl: pruneHandoffStorage failed:", e);
      }
    }
    /** Persist handoff state for a specific conversation ID (used when switching or saving). */
    saveHandoffStateToKey(convId) {
      const state = {
        handoffCompleted: this.handoffCompleted,
        bypassAttemptCount: this.bypassAttemptCount,
        postHandoffMessagesSinceHandoff: this.postHandoffMessagesSinceHandoff,
        conversationId: this.currentConversationId ?? convId,
        conversationCache: this.conversationCache.slice(-20),
        lastCacheUpdate: this.lastCacheUpdate,
        lastChatGPTMessage: this.lastChatGPTMessage,
        consecutiveGoodLearningPrompts: this.consecutiveGoodLearningPrompts,
        monitoringFrequency: this.monitoringFrequency,
        responsesSinceLastMonitoring: this.responsesSinceLastMonitoring
      };
      const key = this.getHandoffStorageKey(convId);
      sessionStorage.setItem(key, JSON.stringify(state));
    }
    // Persist handoff state to sessionStorage (keyed by current conversation ID)
    saveHandoffState() {
      const convId = this.getConversationIdFromUrl();
      this.saveHandoffStateToKey(convId);
      this.pruneHandoffStorage();
    }
    // Restore handoff state from sessionStorage (keyed by current conversation ID)
    restoreHandoffState() {
      try {
        const currentConvId = this.getConversationIdFromUrl();
        const key = this.getHandoffStorageKey(currentConvId);
        let stored = sessionStorage.getItem(key);
        if (!stored && !currentConvId) {
          stored = sessionStorage.getItem(this.getHandoffStorageKey(null));
        }
        if (!stored && currentConvId) {
          stored = sessionStorage.getItem(this.getHandoffStorageKey(null));
        }
        if (stored) {
          const state = JSON.parse(stored);
          const stateAge = Date.now() - (state.lastCacheUpdate || 0);
          const isRecentState = stateAge < 6e4;
          let shouldRestore = false;
          if (currentConvId && state.conversationId === currentConvId) {
            shouldRestore = true;
          } else if (!state.conversationId && currentConvId && state.handoffCompleted && isRecentState) {
            console.log("GuardRAIl: Restoring recent handoff state for new conversation that got URL");
            shouldRestore = true;
            state.conversationId = currentConvId;
          } else if (currentConvId && (state.conversationId === _GuardRAIl.HANDOFF_KEY_NEW || !state.conversationId) && state.handoffCompleted && isRecentState) {
            console.log("GuardRAIl: Restoring handoff state from _new (saved before URL had id), migrating to", currentConvId);
            shouldRestore = true;
            state.conversationId = currentConvId;
          } else if (!currentConvId && (state.conversationId === _GuardRAIl.HANDOFF_KEY_NEW || !state.conversationId) && isRecentState) {
            shouldRestore = true;
          }
          console.log("GuardRAIl: State restore check:", {
            currentConvId,
            storedConvId: state.conversationId,
            shouldRestore,
            stateAge: Math.round(stateAge / 1e3) + "s",
            handoffCompleted: state.handoffCompleted,
            url: window.location.href
          });
          if (!shouldRestore) {
            this.clearHandoffStateInMemory();
            return;
          }
          this.handoffCompleted = state.handoffCompleted || false;
          this.bypassAttemptCount = state.bypassAttemptCount || 0;
          this.postHandoffMessagesSinceHandoff = state.postHandoffMessagesSinceHandoff || 0;
          this.currentConversationId = state.conversationId ?? currentConvId;
          if (state.conversationCache && Array.isArray(state.conversationCache)) {
            this.conversationCache = state.conversationCache.map((m) => ({
              role: m.role,
              content: m.content,
              timestamp: m.timestamp || Date.now()
            }));
            this.lastCacheUpdate = state.lastCacheUpdate || 0;
            this.lastChatGPTMessage = state.lastChatGPTMessage || null;
            this.consecutiveGoodLearningPrompts = state.consecutiveGoodLearningPrompts || 0;
            this.monitoringFrequency = state.monitoringFrequency || 1;
            this.responsesSinceLastMonitoring = state.responsesSinceLastMonitoring || 0;
            console.log("GuardRAIl: Restored conversation cache:", this.conversationCache.length, "messages");
          }
          if ((!state.conversationCache || state.conversationCache.length === 0) && this.handoffCompleted) {
            if (document.readyState === "loading") {
              document.addEventListener("DOMContentLoaded", () => {
                setTimeout(() => this.reconstructConversationFromDOM(), 1e3);
              });
            } else {
              setTimeout(() => this.reconstructConversationFromDOM(), 500);
            }
          }
          console.log("GuardRAIl: Restored handoff state:", {
            handoffCompleted: this.handoffCompleted,
            messagesSinceHandoff: this.postHandoffMessagesSinceHandoff,
            cacheSize: this.conversationCache.length
          });
          this.saveHandoffState();
        }
      } catch (err) {
        console.log("GuardRAIl: Could not restore handoff state:", err);
      }
    }
    clearHandoffStateInMemory() {
      this.handoffCompleted = false;
      this.bypassAttemptCount = 0;
      this.postHandoffMessagesSinceHandoff = 0;
      this.conversationCache = [];
      this.lastChatGPTMessage = null;
    }
    /**
     * Switch to another conversation: save current state to old ID, load state for new ID, then re-setup observers.
     * One tab, multiple subjects: We key handoff state and cache by conversation ID. When the user switches chat
     * in the same tab we save/load per-conversation state so each chat has correct context. The post-handoff
     * intervention also asks the student for subject and stuck point, so the redirect prompt uses their words
     * even if our cache was briefly wrong.
     */
    switchToConversation(newConvId) {
      const oldId = this.currentConversationId;
      if (newConvId === oldId) return;
      console.log("GuardRAIl: Switching conversation:", oldId, "->", newConvId);
      this.saveHandoffStateToKey(oldId);
      this.pruneHandoffStorage();
      const key = this.getHandoffStorageKey(newConvId);
      const stored = sessionStorage.getItem(key);
      if (stored) {
        try {
          const state = JSON.parse(stored);
          this.handoffCompleted = state.handoffCompleted || false;
          this.bypassAttemptCount = state.bypassAttemptCount || 0;
          this.postHandoffMessagesSinceHandoff = state.postHandoffMessagesSinceHandoff || 0;
          this.currentConversationId = newConvId;
          if (state.conversationCache && Array.isArray(state.conversationCache)) {
            this.conversationCache = state.conversationCache.map((m) => ({
              role: m.role,
              content: m.content,
              timestamp: m.timestamp || Date.now()
            }));
            this.lastCacheUpdate = state.lastCacheUpdate || 0;
            this.lastChatGPTMessage = state.lastChatGPTMessage || null;
            this.consecutiveGoodLearningPrompts = state.consecutiveGoodLearningPrompts || 0;
            this.monitoringFrequency = state.monitoringFrequency || 1;
            this.responsesSinceLastMonitoring = state.responsesSinceLastMonitoring || 0;
            console.log("GuardRAIl: Loaded state for conversation:", newConvId, "cache:", this.conversationCache.length);
          } else {
            this.conversationCache = [];
            this.lastChatGPTMessage = null;
          }
          if (this.handoffCompleted && this.conversationCache.length > 0) {
            const userMsgs = this.conversationCache.filter((m) => m.role === "user");
            const hasLongFacilitation = userMsgs.some((m) => {
              const c = m.content.trim();
              return c.length >= 150 && (/I am working on .+ specifically/i.test(c) || /I'm working on .+ specifically/i.test(c) || /Please act as my tutor and help me learn/i.test(c));
            });
            if (!hasLongFacilitation) {
              console.log("GuardRAIl: Cleared stale handoffCompleted on switch — no long facilitation prompt in cache");
              this.handoffCompleted = false;
              this.bypassAttemptCount = 0;
              this.postHandoffMessagesSinceHandoff = 0;
            }
          }
        } catch (e) {
          console.warn("GuardRAIl: Failed to parse stored state for", newConvId, e);
          this.clearHandoffStateInMemory();
          this.currentConversationId = newConvId;
        }
      } else {
        this.clearHandoffStateInMemory();
        this.currentConversationId = newConvId;
        console.log("GuardRAIl: No stored state for conversation:", newConvId);
      }
      this.cleanup();
      setTimeout(() => {
        this.setupConversationCache();
        this.setupChatGPTResponseMonitoring();
        this.setupInterception();
        this.updateConversationCache();
      }, 500);
    }
    /**
     * NEW: Reconstruct conversation from DOM after page refresh
     * Recovers conversation context when cache is lost
     */
    reconstructConversationFromDOM() {
      try {
        const history = this.getChatGPTConversationHistory(20);
        if (history.length > 0) {
          const now = Date.now();
          this.conversationCache = history.map((msg, index) => ({
            role: msg.role,
            content: msg.content,
            timestamp: now - (history.length - index) * 1e3
            // Approximate timestamps
          }));
          const lastAssistant = history.filter((m) => m.role === "assistant").slice(-1)[0];
          if (lastAssistant) {
            this.lastChatGPTMessage = lastAssistant.content;
            this.lastChatGPTMessageTimestamp = now;
          }
          this.lastCacheUpdate = now;
          this.saveHandoffState();
          console.log("GuardRAIl: Reconstructed conversation from DOM:", this.conversationCache.length, "messages");
        }
      } catch (err) {
        console.error("GuardRAIl: Error reconstructing conversation from DOM:", err);
      }
    }
    // Get conversation ID from URL (path or hash) without side effects
    getConversationIdFromUrl() {
      if (this.platform === "chatgpt") {
        const pathMatch = window.location.pathname.match(/\/c\/([a-z0-9-]+)/i);
        if (pathMatch) return pathMatch[1];
        const hash = window.location.hash || "";
        const hashMatch = hash.match(/[/#]c[/-]([a-z0-9-]+)/i);
        return hashMatch ? hashMatch[1] : null;
      } else if (this.platform === "gemini") {
        const pathMatch = window.location.pathname.match(/\/chat\/([a-z0-9-]+)/i);
        if (pathMatch) return pathMatch[1];
        const urlParams = new URLSearchParams(window.location.search);
        return urlParams.get("chat");
      }
      return null;
    }
    detectPlatform() {
      const hostname = window.location.hostname;
      if (hostname.includes("chatgpt.com") || hostname.includes("chat.openai.com")) {
        return "chatgpt";
      }
      if (hostname.includes("gemini.google.com")) {
        return "gemini";
      }
      return "unknown";
    }
    /**
     * Extract ChatGPT conversation history from the DOM
     * Returns recent conversation messages (both user and assistant)
     */
    /**
     * IMPROVED: Get ChatGPT conversation history from DOM with multiple extraction strategies
     * Enhanced to work better with old tabs, lazy-loaded messages, and different DOM structures
     */
    getChatGPTConversationHistory(limit = 10) {
      const history = [];
      try {
        if (this.platform === "chatgpt") {
          let conversationTurns = document.querySelectorAll('[data-testid*="conversation-turn-"]');
          if (conversationTurns.length === 0) {
            conversationTurns = document.querySelectorAll('div[class*="group/conversation-turn"], div[class*="conversation-turn"]');
          }
          if (conversationTurns.length === 0) {
            conversationTurns = document.querySelectorAll("article[data-testid], div[data-message-id]");
          }
          if (conversationTurns.length === 0) {
            console.log("GuardRAIl: Trying fallback selector for messages...");
            const fallbackTurns = document.querySelectorAll("[data-message-author-role]");
            if (fallbackTurns.length > 0) {
              const messagesByRole = {
                user: [],
                assistant: []
              };
              fallbackTurns.forEach((el, index) => {
                const role = el.getAttribute("data-message-author-role");
                if (!role || role !== "user" && role !== "assistant") return;
                const contentSelectors = [
                  "div[data-message-content]",
                  "div.markdown",
                  "div.prose",
                  'div[class*="markdown"]',
                  'div[class*="text-base"]'
                ];
                let content = "";
                for (const selector of contentSelectors) {
                  const contentEl = el.querySelector(selector);
                  if (contentEl) {
                    content = contentEl.textContent?.trim() || "";
                    if (content.length > (role === "assistant" ? 10 : 5)) break;
                  }
                }
                if (!content || content.length < (role === "assistant" ? 10 : 5)) {
                  content = el.textContent?.trim() || "";
                }
                if (content.length > (role === "assistant" ? 10 : 5)) {
                  messagesByRole[role].push({ content, order: index });
                }
              });
              const allMessages = [];
              Array.from(fallbackTurns).forEach((el, domIndex) => {
                const role = el.getAttribute("data-message-author-role");
                if (!role || role !== "user" && role !== "assistant") return;
                const match = messagesByRole[role].find((m) => {
                  const contentSelectors = [
                    "div[data-message-content]",
                    "div.markdown",
                    "div.prose",
                    'div[class*="markdown"]'
                  ];
                  let content = "";
                  for (const selector of contentSelectors) {
                    const contentEl = el.querySelector(selector);
                    if (contentEl) {
                      content = contentEl.textContent?.trim() || "";
                      if (content.length > 5) break;
                    }
                  }
                  if (!content) {
                    content = el.textContent?.trim() || "";
                  }
                  return content.length > 5 && content.substring(0, 50) === m.content.substring(0, 50);
                });
                if (match) {
                  allMessages.push({ role, content: match.content, position: domIndex });
                }
              });
              allMessages.sort((a, b) => a.position - b.position);
              const recentMessages = allMessages.slice(-limit * 2);
              recentMessages.forEach((msg) => {
                history.push({ role: msg.role, content: msg.content });
              });
              console.log("GuardRAIl: Fallback extraction found:", history.length, "messages");
              return history;
            }
          }
          const allTurns = Array.from(conversationTurns);
          const recentTurns = allTurns.slice(-limit * 2).reverse();
          for (const turn of recentTurns) {
            const assistantEl = turn.querySelector('[data-message-author-role="assistant"]');
            if (assistantEl) {
              const contentSelectors = [
                "div[data-message-content]",
                "div.markdown",
                "div.prose",
                'div[class*="markdown"]'
              ];
              let content = "";
              for (const selector of contentSelectors) {
                const contentEl = assistantEl.querySelector(selector);
                if (contentEl) {
                  content = contentEl.textContent?.trim() || "";
                  if (content.length > 10) break;
                }
              }
              if (!content || content.length < 10) {
                content = assistantEl.textContent?.trim() || "";
              }
              if (content.length > 10) {
                history.push({ role: "assistant", content });
              }
            }
            const userEl = turn.querySelector('[data-message-author-role="user"]');
            if (userEl) {
              const contentSelectors = [
                "div[data-message-content]",
                "div.prose",
                'div[class*="text-base"]'
              ];
              let content = "";
              for (const selector of contentSelectors) {
                const contentEl = userEl.querySelector(selector);
                if (contentEl) {
                  content = contentEl.textContent?.trim() || "";
                  if (content.length > 5) break;
                }
              }
              if (!content || content.length < 5) {
                content = userEl.textContent?.trim() || "";
              }
              if (content.length > 5) {
                history.push({ role: "user", content });
              }
            }
          }
        } else if (this.platform === "gemini") {
          const geminiMessageSelectors = [
            '[data-role="model"], [data-role="user"]',
            '[data-message-author="model"], [data-message-author="user"]',
            'div[class*="message"][class*="model"], div[class*="message"][class*="user"]',
            "message-content"
          ];
          const messages = [];
          for (const selector of geminiMessageSelectors) {
            try {
              const geminiMessages = document.querySelectorAll(selector);
              if (geminiMessages.length > 0) {
                geminiMessages.forEach((el, index) => {
                  const dataRole = el.getAttribute("data-role");
                  const dataAuthor = el.getAttribute("data-message-author");
                  const classList = el.className || "";
                  let role = "user";
                  if (dataRole === "model" || dataAuthor === "model" || classList.includes("model") || classList.includes("assistant")) {
                    role = "assistant";
                  }
                  const content = el.textContent?.trim() || "";
                  if (content.length > 5) {
                    messages.push({ role, content, order: index });
                  }
                });
                break;
              }
            } catch (e) {
              continue;
            }
          }
          const recentMessages = messages.slice(-limit * 2);
          recentMessages.forEach((msg) => {
            history.push({ role: msg.role, content: msg.content });
          });
        }
      } catch (error) {
        console.error("GuardRAIl: Error extracting conversation history:", error);
      }
      return history;
    }
    /**
     * Extract ChatGPT's last message/question from the DOM
     * Returns the most recent assistant message in the conversation
     */
    getChatGPTLastMessage() {
      try {
        if (this.platform === "chatgpt") {
          const messageSelectors = [
            '[data-message-author-role="assistant"]',
            '[data-testid="conversation-turn-"]:has([data-message-author-role="assistant"])',
            'div[class*="group/conversation-turn"]:has([data-message-author-role="assistant"])',
            'div[class*="text-base"]:has([data-message-author-role="assistant"])'
          ];
          for (const selector of messageSelectors) {
            const elements = document.querySelectorAll(selector);
            if (elements.length > 0) {
              const lastElement = elements[elements.length - 1];
              const contentSelectors = [
                "div[data-message-content]",
                "div.markdown",
                "div.prose",
                'div[class*="markdown"]'
              ];
              let messageText = "";
              for (const contentSelector of contentSelectors) {
                const contentEl = lastElement.querySelector(contentSelector);
                if (contentEl) {
                  messageText = contentEl.textContent?.trim() || "";
                  if (messageText && messageText.length > 10) {
                    break;
                  }
                }
              }
              if (!messageText || messageText.length < 10) {
                messageText = lastElement.textContent?.trim() || "";
              }
              if (messageText && messageText.length > 10) {
                console.log("GuardRAIl: Found ChatGPT message:", `[${messageText.length} chars]`);
                return messageText;
              }
            }
          }
          const allDivs = document.querySelectorAll('div[class*="group"], div[class*="message"]');
          const messages = [];
          allDivs.forEach((div, index) => {
            const text = div.textContent?.trim() || "";
            if (text.length > 20 && (text.includes("?") || text.split(/\s+/).length > 10)) {
              const hasInput = div.querySelector('textarea, input[type="text"]');
              if (!hasInput) {
                messages.push({ text, order: index });
              }
            }
          });
          if (messages.length > 0) {
            const lastMessage = messages[messages.length - 1];
            console.log("GuardRAIl: Found ChatGPT message (fallback):", `[${lastMessage.text.length} chars]`);
            return lastMessage.text;
          }
        } else if (this.platform === "gemini") {
          const geminiSelectors = [
            '[data-role="model"]',
            '[data-message-author="model"]',
            'div[class*="model-response"]',
            'div[class*="model-message"]',
            'div[class*="assistant"]',
            'div[class*="response-container"] div[class*="message"]',
            'message-content[class*="model"]',
            ".model-response-text",
            "model-response"
          ];
          for (const selector of geminiSelectors) {
            try {
              const elements = document.querySelectorAll(selector);
              if (elements.length > 0) {
                const lastElement = elements[elements.length - 1];
                const text = lastElement.textContent?.trim() || "";
                if (text && text.length > 10) {
                  console.log("GuardRAIl: Found Gemini message:", `[${text.length} chars]`);
                  return text;
                }
              }
            } catch (e) {
              continue;
            }
          }
        }
        return null;
      } catch (error) {
        console.error("GuardRAIl: Error extracting ChatGPT message:", error);
        return null;
      }
    }
    /**
     * NEW: Setup proactive conversation caching using MutationObserver
     * Caches conversation history as it happens for better context awareness
     */
    setupConversationCache() {
      this.conversationCacheObserver = new MutationObserver(() => {
        const now = Date.now();
        if (now - this.lastCacheUpdate < this.CACHE_UPDATE_INTERVAL) {
          if (!this.conversationCacheDebounce) {
            this.conversationCacheDebounce = setTimeout(() => {
              this.conversationCacheDebounce = null;
              this.updateConversationCache();
            }, this.CACHE_UPDATE_INTERVAL);
          }
          return;
        }
        this.lastCacheUpdate = now;
        this.updateConversationCache();
      });
      this.conversationCacheObserver.observe(document.body, {
        childList: true,
        subtree: true
      });
      this.updateConversationCache();
      console.log("GuardRAIl: Conversation cache setup complete");
    }
    // Only scroll every 10 seconds max
    updateConversationCache() {
      try {
        const shouldTriggerScroll = this.conversationCache.length === 0 || Date.now() - this.lastScrollTrigger > this.SCROLL_TRIGGER_INTERVAL;
        if (shouldTriggerScroll) {
          const conversationContainer = document.querySelector('main, [role="main"], div[class*="conversation"], div[class*="chat"]');
          if (conversationContainer) {
            requestAnimationFrame(() => {
              conversationContainer.scrollTop = 0;
              setTimeout(() => {
                conversationContainer.scrollTop = conversationContainer.scrollHeight;
              }, 100);
            });
            this.lastScrollTrigger = Date.now();
            console.log("GuardRAIl: Triggered scroll for cache update (old tab or empty cache)");
          }
        }
        const history = this.getChatGPTConversationHistory(20);
        console.log("GuardRAIl: updateConversationCache extracted:", history.length, "messages");
        if (history.length > 0) {
          const now = Date.now();
          this.conversationCache = history.map((msg) => ({
            ...msg,
            timestamp: now
          }));
          const lastAssistant = history.filter((m) => m.role === "assistant").slice(-1)[0];
          if (lastAssistant) {
            this.lastChatGPTMessage = lastAssistant.content;
            this.lastChatGPTMessageTimestamp = now;
            console.log("GuardRAIl: Updated last ChatGPT message:", `[${this.lastChatGPTMessage.length} chars]`);
          }
          this.saveHandoffState();
          console.log("GuardRAIl: ✅ Conversation cache updated:", this.conversationCache.length, "messages");
        } else {
          const hasConversationId = this.getConversationIdFromUrl() !== null;
          if (hasConversationId) {
            console.warn("GuardRAIl: ⚠️ updateConversationCache found 0 messages in existing conversation");
            const turns1 = document.querySelectorAll('[data-testid*="conversation-turn-"]');
            const turns2 = document.querySelectorAll("[data-message-author-role]");
            const turns3 = document.querySelectorAll("article[data-testid]");
            const turns4 = document.querySelectorAll("div[data-message-id]");
            console.warn("GuardRAIl: DOM debug:", {
              conversationTurns: turns1.length,
              messageRoles: turns2.length,
              articles: turns3.length,
              messageIds: turns4.length,
              platform: this.platform
            });
          }
        }
      } catch (err) {
        console.error("GuardRAIl: Error updating conversation cache:", err);
      }
    }
    /**
     * IMPROVED: Get context for analysis (always use cached data)
     * Enhanced with intelligent context selection for long conversations
     */
    getContextForAnalysis() {
      const lastAssistant = this.conversationCache.filter((m) => m.role === "assistant").slice(-1)[0]?.content || this.lastChatGPTMessage || null;
      let conversationHistory = this.conversationCache.slice(-20);
      if (this.conversationCache.length > 50) {
        const recentMessages = this.conversationCache.slice(-5);
        const questionMessages = this.conversationCache.filter(
          (m) => m.role === "assistant" && (m.content.includes("?") || /\b(think|understand|explain|what|how|why)\b/i.test(m.content))
        ).slice(-5);
        const combined = [];
        const seen = /* @__PURE__ */ new Set();
        for (const msg of [...recentMessages, ...questionMessages, ...this.conversationCache.slice(-10)]) {
          const key = `${msg.role}:${msg.content.substring(0, 100)}`;
          if (!seen.has(key)) {
            seen.add(key);
            combined.push(msg);
          }
        }
        conversationHistory = combined.sort((a, b) => a.timestamp - b.timestamp).slice(-15);
        console.log("GuardRAIl: Long conversation detected, using intelligent context selection:", {
          totalMessages: this.conversationCache.length,
          selectedMessages: conversationHistory.length
        });
      }
      return {
        lastMessage: lastAssistant,
        conversationHistory: conversationHistory.map((m) => ({
          role: m.role,
          content: m.content
        })),
        isStreaming: this.isChatGPTStreaming()
      };
    }
    /**
     * PERFORMANCE FIX: Non-blocking context extraction with exponential backoff
     * Only retries when cache is empty (old tab scenario)
     */
    async ensureContextAvailable(maxAttempts = 3) {
      for (let attempt = 0; attempt < maxAttempts && this.conversationCache.length === 0; attempt++) {
        console.log(`GuardRAIl: Cache empty (attempt ${attempt + 1}/${maxAttempts}), extracting from DOM...`);
        this.updateConversationCache();
        if (this.conversationCache.length > 0) {
          console.log("GuardRAIl: ✅ Context extracted successfully");
          break;
        }
        const delay = 300 * Math.pow(2, attempt);
        await new Promise((resolve) => setTimeout(resolve, delay));
      }
      if (this.conversationCache.length === 0) {
        console.warn("GuardRAIl: ⚠️ Could not extract conversation context after", maxAttempts, "attempts");
      }
    }
    /**
     * NEW: Heuristic prompt rating for API failure fallback
     * Uses pattern matching when API is unavailable
     */
    heuristicPromptRating(prompt, chatGPTMessage) {
      let rating = 5;
      if (/\b(write my|do my|complete my|finish my|give me|just give|solve this for me)\b/i.test(prompt)) {
        rating -= 3;
      }
      if (/\b(make this output for me|can you make this output for me|make .+ for me immediately)\b/i.test(prompt)) {
        rating -= 3;
      }
      if (/\b(write|create|generate|make|build|do|solve|complete|finish)\s+(my|the|this|a|an)\s+\w+/i.test(prompt) && prompt.length < 30) {
        rating -= 2;
      }
      if (!/\b(why|how|what|think|understand|learn|explain|help|check|review)\b/i.test(prompt) && prompt.length < 20) {
        rating -= 1;
      }
      if (/\b(why|how|what|think|understand|learn|explain|help|check|review|reasoning)\b/i.test(prompt)) {
        rating += 2;
      }
      if (/\b(I tried|I attempted|I think|I believe|my reasoning|my approach)\b/i.test(prompt)) {
        rating += 2;
      }
      if (/\b(because|since|so|therefore|I think|probably|maybe)\b/i.test(prompt) && prompt.length > 30) {
        rating += 1;
      }
      if (prompt.length > 50 && /\b(why|how|what|think|understand)\b/i.test(prompt)) {
        rating += 1;
      }
      if (chatGPTMessage && this.isLikelyAnswerToQuestion(prompt, chatGPTMessage)) {
        rating += 2;
      }
      return Math.max(1, Math.min(10, rating));
    }
    /**
     * NEW: Detect if ChatGPT is currently streaming a response
     */
    isChatGPTStreaming() {
      if (this.platform === "chatgpt") {
        return document.querySelector('[data-testid*="typing"], [aria-live="polite"], [class*="streaming"], [class*="typing"]') !== null || document.querySelector('[data-testid*="stop-button"]') !== null;
      } else if (this.platform === "gemini") {
        return document.querySelector(
          '[aria-live="polite"], [class*="streaming"], [class*="typing"], [class*="loading"], mat-spinner, .loading-indicator, [aria-busy="true"], button[aria-label*="Stop" i]'
          // Stop button appears during generation
        ) !== null;
      }
      return false;
    }
    /**
     * NEW: Setup ChatGPT response monitoring for dual policing
     * Monitors ChatGPT responses for compliance with learning facilitation prompt
     */
    setupChatGPTResponseMonitoring() {
      this.chatGPTResponseObserver = new MutationObserver((mutations) => {
        if (!this.handoffCompleted) return;
        if (this.consecutiveGoodLearningPrompts >= this.MAX_MONITORING_FREQUENCY) {
          return;
        }
        const now = Date.now();
        if (now - this.lastChatGPTMessageTimestamp < 2e3) return;
        const newMessage = this.detectNewChatGPTMessage(mutations);
        if (newMessage && newMessage !== this.lastChatGPTMessage) {
          this.responsesSinceLastMonitoring++;
          if (this.responsesSinceLastMonitoring < this.monitoringFrequency) {
            return;
          }
          this.responsesSinceLastMonitoring = 0;
          if (!this.isChatGPTStreaming()) {
            this.analyzeChatGPTCompliance(newMessage).catch((err) => {
              console.error("GuardRAIl: Error analyzing ChatGPT compliance:", err);
            });
          }
        }
      });
      this.chatGPTResponseObserver.observe(document.body, {
        childList: true,
        subtree: true
      });
      console.log("GuardRAIl: ChatGPT response monitoring setup complete (adaptive frequency:", this.monitoringFrequency, ")");
    }
    /**
     * NEW: Detect new ChatGPT message from DOM mutations
     */
    detectNewChatGPTMessage(mutations) {
      for (const mutation of mutations) {
        if (mutation.addedNodes.length > 0) {
          for (const node of Array.from(mutation.addedNodes)) {
            if (node.nodeType === Node.ELEMENT_NODE) {
              const element = node;
              if (element.matches('[data-message-author-role="assistant"]') || element.querySelector('[data-message-author-role="assistant"]')) {
                const message = this.getChatGPTLastMessage();
                if (message && message !== this.lastChatGPTMessage) {
                  return message;
                }
              }
            }
          }
        }
      }
      return null;
    }
    /**
     * NEW: Analyze ChatGPT response for compliance with learning facilitation
     * Dual policing: Check if ChatGPT is following the learning prompt
     */
    async analyzeChatGPTCompliance(message) {
      if (!this.handoffCompleted || this.postHandoffMessagesSinceHandoff < 2) {
        return;
      }
      try {
        const result = await this.sendMessage({
          type: "ANALYZE_CHATGPT_RESPONSE",
          response: message,
          conversationContext: this.getContextForAnalysis().conversationHistory,
          handoffState: {
            completed: this.handoffCompleted,
            messagesSinceHandoff: this.postHandoffMessagesSinceHandoff
          }
        });
        this.lastChatGPTMessage = message;
        this.lastChatGPTMessageTimestamp = Date.now();
        this.saveHandoffState();
        if (result.shouldIntervene && result.isDirectAnswer && !result.isAppropriate) {
          console.warn("GuardRAIl: ChatGPT non-compliance detected:", {
            isDirectAnswer: result.isDirectAnswer,
            isAppropriate: result.isAppropriate,
            confidence: result.confidence
          });
          this.interveneOnChatGPTNonCompliance(message, result);
        }
      } catch (err) {
        console.error("GuardRAIl: Error analyzing ChatGPT compliance:", err);
      }
    }
    /**
     * NEW: Intervene when ChatGPT doesn't comply with learning prompt
     */
    interveneOnChatGPTNonCompliance(chatGPTMessage, complianceResult) {
      if (complianceResult.confidence >= 0.8) {
        const interventionQuestion = `I see ChatGPT provided a direct answer. To help you learn better, can you explain what you understand from that response? What steps would you take to apply it?`;
        this.showChatGPTComplianceIntervention(interventionQuestion, chatGPTMessage);
      } else {
        console.log("GuardRAIl: Borderline ChatGPT compliance, logging for analysis");
        this.logPostHandoffPrompt(
          chatGPTMessage,
          false,
          "none",
          5,
          // Medium rating
          "shortcut",
          // ChatGPT gave direct answer
          null,
          null
        );
      }
    }
    /**
     * NEW: Show intervention dialog for ChatGPT non-compliance
     */
    showChatGPTComplianceIntervention(question, chatGPTMessage) {
      this.showToast("ChatGPT provided a direct answer. Consider explaining what you understand.", "warning");
      this.logPostHandoffPrompt(
        `[ChatGPT Non-Compliance] ${chatGPTMessage.substring(0, 200)}`,
        true,
        "gentle",
        3,
        // Low rating (ChatGPT bypassed learning prompt)
        "shortcut",
        null,
        null
      );
    }
    /**
     * NEW: Setup monitoring for conversation reset (new chat, URL changes)
     */
    setupConversationResetMonitoring() {
      const handlePopState = () => {
        const currentConvId = this.getConversationIdFromUrl();
        if (currentConvId !== this.currentConversationId) {
          if (!this.currentConversationId && currentConvId) {
            console.log("GuardRAIl: New conversation got its URL ID, updating state (not resetting):", currentConvId);
            this.currentConversationId = currentConvId;
            this.saveHandoffState();
            return;
          }
          if (currentConvId) {
            this.switchToConversation(currentConvId);
          } else {
            this.resetPostHandoffState();
            this.cleanup();
            setTimeout(() => {
              this.setupConversationCache();
              this.setupChatGPTResponseMonitoring();
              this.setupInterception();
            }, 500);
          }
        }
      };
      window.addEventListener("popstate", handlePopState);
      const handleClick = (e) => {
        const target = e.target;
        if (target.matches('a[href*="/new"], button[aria-label*="New"], button[aria-label*="new chat"]')) {
          console.log("GuardRAIl: New chat detected, resetting state");
          setTimeout(() => {
            this.resetPostHandoffState();
            this.cleanup();
            setTimeout(() => {
              this.setupConversationCache();
              this.setupChatGPTResponseMonitoring();
              this.setupInterception();
            }, 500);
          }, 1e3);
        }
      };
      document.addEventListener("click", handleClick, true);
      setInterval(() => {
        const currentConvId = this.getConversationIdFromUrl();
        if (currentConvId && currentConvId !== this.currentConversationId) {
          if (!this.currentConversationId) {
            console.log("GuardRAIl: New conversation got URL ID (periodic check), updating state:", currentConvId);
            this.currentConversationId = currentConvId;
            this.saveHandoffState();
            return;
          }
          if (currentConvId) {
            this.switchToConversation(currentConvId);
          }
        }
      }, 5e3);
      window.addEventListener("beforeunload", () => {
        this.cleanup();
      });
      let lastUrl = window.location.href;
      setInterval(() => {
        if (window.location.href !== lastUrl) {
          lastUrl = window.location.href;
          const newConvId = this.getConversationIdFromUrl();
          if (newConvId && newConvId !== this.currentConversationId) {
            console.log("GuardRAIl: URL changed (different conversation), switching state");
            this.switchToConversation(newConvId);
          } else {
            console.log("GuardRAIl: URL changed (SPA navigation), cleaning up observers");
            this.cleanup();
            setTimeout(() => {
              this.setupConversationCache();
              this.setupChatGPTResponseMonitoring();
              this.setupInterception();
            }, 1e3);
          }
        }
      }, 1e3);
      console.log("GuardRAIl: Conversation reset monitoring setup complete");
    }
    /**
     * CRITICAL FIX: Cleanup all MutationObservers and timers to prevent memory leaks
     */
    cleanup() {
      console.log("GuardRAIl: Cleaning up observers and timers...");
      if (this.conversationCacheObserver) {
        this.conversationCacheObserver.disconnect();
        this.conversationCacheObserver = null;
        console.log("GuardRAIl: conversationCacheObserver disconnected");
      }
      if (this.chatGPTResponseObserver) {
        this.chatGPTResponseObserver.disconnect();
        this.chatGPTResponseObserver = null;
        console.log("GuardRAIl: chatGPTResponseObserver disconnected");
      }
      if (this.observer) {
        this.observer.disconnect();
        this.observer = null;
        console.log("GuardRAIl: observer disconnected");
      }
      if (this.conversationCacheDebounce) {
        clearTimeout(this.conversationCacheDebounce);
        this.conversationCacheDebounce = null;
        console.log("GuardRAIl: conversationCacheDebounce cleared");
      }
      if (this.debounceTimer) {
        clearTimeout(this.debounceTimer);
        this.debounceTimer = null;
        console.log("GuardRAIl: debounceTimer cleared");
      }
      if (this.reattachIntervalId) {
        clearInterval(this.reattachIntervalId);
        this.reattachIntervalId = null;
        console.log("GuardRAIl: reattachInterval cleared");
      }
      document.removeEventListener("keydown", this.boundKeydownHandler, true);
      document.removeEventListener("submit", this.boundSubmitHandler, true);
      if (this.guardrailIndicator && this.guardrailIndicator.parentNode) {
        this.guardrailIndicator.remove();
        this.guardrailIndicator = null;
      }
      console.log("GuardRAIl: Cleanup complete");
    }
    /** Get the last assistant (ChatGPT) message for context checks. Prefers cache, then DOM. */
    getLastAssistantMessage() {
      if (this.lastChatGPTMessage) return this.lastChatGPTMessage;
      const fromCache = this.conversationCache.filter((m) => m.role === "assistant").slice(-1)[0];
      if (fromCache?.content) return fromCache.content;
      const history = this.getChatGPTConversationHistory(5);
      const last = history.filter((m) => m.role === "assistant").slice(-1)[0];
      return last?.content ?? null;
    }
    /**
     * LEARNING-REPLY GATE: Allow short replies (e.g. "110", "yes") without intervention.
     * When ChatGPT is helping learn, these are always answers to tutor questions, not shortcut attempts.
     * Two paths: (1) short reply that can't be a shortcut → always allow; (2) have last message → allow if answer to question.
     * CRITICAL: Only skip API for genuinely short replies (<=25 chars). Longer substantive messages must go to analyzePrompt.
     */
    isLearningReplyAllowThrough(prompt) {
      if (prompt.length > 25) return false;
      const obviousShortcutPatterns = [
        /\b(write my|do my|complete my|finish my|give me the|just give me)\b/i,
        /\b(write a|write an|write the)\s+(paper|essay|report|assignment|homework|code|solution)\b/i,
        /\b(do it for me|solve this for me|write this for me|write it for me|just write it)\b/i
      ];
      if (obviousShortcutPatterns.some((p) => p.test(prompt))) return false;
      if (prompt.length > 120) return false;
      const trimmed = prompt.trim();
      const isShortReply = trimmed.length <= 15;
      const isPureNumeric = /^\s*[\d.,]+\s*$/.test(trimmed);
      const isShortAffirmative = /^(yes|no|yeah|nope|yep|ok|okay|sure|maybe|idk|i don't know|correct|wrong|true|false)$/i.test(trimmed);
      if (isShortReply && (isPureNumeric || isShortAffirmative)) {
        return true;
      }
      const lastMsg = this.getLastAssistantMessage();
      if (!lastMsg || lastMsg.length < 20) return false;
      return this.isLikelyAnswerToQuestion(prompt, lastMsg);
    }
    /**
     * IMPROVED: Check if student message is likely an answer to ChatGPT's question
     * Enhanced with semantic analysis using conversation context
     */
    isLikelyAnswerToQuestion(studentMessage, chatGPTMessage) {
      if (!chatGPTMessage) return false;
      const finalRequestShortcut = /\b(just|can you|could you|would you|please)?\s*(write|do|complete|finish|solve|give)\s*(it|my|me|this|the|that|to)(\s+for me)?[\s.?!]*$/i;
      if (finalRequestShortcut.test(studentMessage)) {
        console.log("GuardRAIl: Final request shortcut detected - NOT an answer:", `[${studentMessage.length} chars]`);
        return false;
      }
      if (/\b(just\s+)?write\s+to\s+for\s+me[\s.?!]*$/i.test(studentMessage)) {
        console.log("GuardRAIl: Final request shortcut detected - NOT an answer (write to for me):", `[${studentMessage.length} chars]`);
        return false;
      }
      const explicitShortcutPatterns = [
        /\b(write my|write the|write it|write this|write that|write to for me)\b/i,
        /\b(do my|do it|do this|do that|do the)\b/i,
        /\b(complete my|complete it|complete this|complete the)\b/i,
        /\b(give me|just give|just tell|just do|just write)\b/i,
        /\b(solve this|solve it|solve the|solve my)\b/i,
        /\b(no write|no just write|no do|no give)\b/i,
        // "No write it for me" pattern
        /\b(for me|for you to do|you do|you write|you complete)\b/i,
        /\b(don't ask|skip|ignore|no questions|just the answer)\b/i,
        // Additional patterns for disguised shortcuts
        /\b(nothing|i tried nothing|i haven't tried anything).*\b(just|write|do|complete|solve)\b/i,
        /\bi don't (know|understand|care).*\b(just|write|do|complete)\b/i
      ];
      if (explicitShortcutPatterns.some((pattern) => pattern.test(studentMessage))) {
        console.log('GuardRAIl: Shortcut language detected in "answer" - NOT an answer:', `[${studentMessage.length} chars]`);
        return false;
      }
      const hasQuestion = chatGPTMessage.trim().endsWith("?") || /\b(what|how|why|when|where|which|who|can|could|would|should|do|does|did|is|are|was|were|will|would)\s+\w+[^.]*[?]?$/i.test(chatGPTMessage);
      if (!hasQuestion) return false;
      const chatGPTKeywords = chatGPTMessage.toLowerCase().replace(/[?.,!;:]/g, "").split(/\s+/).filter((word) => word.length > 3 && !["the", "are", "you", "your", "what", "how", "why", "when", "where", "which", "who", "can", "could", "would", "should"].includes(word)).slice(0, 5);
      const studentLower = studentMessage.toLowerCase();
      const sharedKeywords = chatGPTKeywords.filter((keyword) => studentLower.includes(keyword));
      if (sharedKeywords.length === 0 && studentMessage.length < 30) {
        if (/^(no|yes|maybe|nope|yep|sure|ok|okay)$/i.test(studentMessage.trim())) {
          return true;
        }
        const chatLower = chatGPTMessage.toLowerCase();
        const askingForNumberOrGuess = /\b(guess|just guess|how much|what do you think|what would you have|what\'?d you have|just (a )?number|give me a number|your answer|don\'?t overthink|calculate|compute|work out)\b/i.test(chatLower) || hasQuestion && /\b(amount|number|percent|%\s*\)|after \d+\s*year|you\'?d have|you would have)\b/i.test(chatLower);
        const isShortNumericReply = /^\s*[\d.,]+\s*$/.test(studentMessage.trim()) || /^\s*\d+\s*$/.test(studentMessage.trim());
        if (askingForNumberOrGuess && isShortNumericReply) {
          return true;
        }
        const tutorAskingChoice = /\b(more than|less than|exactly|or exactly|slightly more|slightly less|the same\b|would be (more|less|same)|option (a|b|c)|first choice|second choice)\b/i.test(chatLower);
        const looksLikeChoiceReply = /\b(more than|less than|exactly|more|less|same)\b/i.test(studentMessage) && studentMessage.length <= 35 || /^\s*(more than|less than|exactly)\s*[\d$.,]*\s*$/i.test(studentMessage.trim());
        if (tutorAskingChoice && looksLikeChoiceReply) {
          console.log("GuardRAIl: Detected answer to question (choice/comparative reply).", {
            chatGPTLength: chatGPTMessage.length,
            studentLength: studentMessage.length
          });
          return true;
        }
        const tutorAskingThink = /\b(do you think|what do you think|think about|why\s*\?)\b/i.test(chatLower);
        const looksLikeThinkReply = /\b(probably|I think|I believe|I guess|maybe)\b/i.test(studentMessage) && studentMessage.length <= 40 && /\b(more|less|same|because|would)\b/i.test(studentMessage);
        if (tutorAskingThink && looksLikeThinkReply) {
          console.log("GuardRAIl: Detected answer to question (think/opinion reply).", {
            chatGPTLength: chatGPTMessage.length,
            studentLength: studentMessage.length
          });
          return true;
        }
        return false;
      }
      if (hasQuestion && studentMessage.length >= 8) {
        const tutorAskingForCalculation = /\b(calculate|how much|how many|what\'?s the (answer|result|number)|compute|work out|can you (calculate|work out)|rate|percent|%)\b/i.test(chatGPTMessage);
        const hasNumberOrPercent = /\d|%/.test(studentMessage);
        const hasCalculationLanguage = /\b(times|plus|minus|multiply|divide|\*|\+|\-|\/|%|would be)\b/i.test(studentMessage) || /^\s*[\d.,]+\s*$/.test(studentMessage.trim());
        if (tutorAskingForCalculation && hasNumberOrPercent && (hasCalculationLanguage || studentMessage.split(/\s+/).length >= 3)) {
          console.log("GuardRAIl: Detected answer to question (calculation reply).", {
            chatGPTLength: chatGPTMessage.length,
            studentLength: studentMessage.length
          });
          return true;
        }
      }
      if (studentMessage.length >= 30 && hasQuestion) {
        const hasExplanationWords = /\b(because|since|so|I think|probably|I believe|I guess|would|could|might|actually|basically)\b/i.test(studentMessage);
        const looksLikeStatement = !studentMessage.trim().endsWith("?") && studentMessage.split(/\s+/).length >= 5;
        if (hasExplanationWords || looksLikeStatement && sharedKeywords.length >= 0) {
          console.log("GuardRAIl: Detected answer to question (substantive reply).", {
            chatGPTLength: chatGPTMessage.length,
            studentLength: studentMessage.length,
            hasExplanationWords,
            looksLikeStatement
          });
          return true;
        }
      }
      const answerIndicators = [
        // Short to medium length (answers are often concise, but can be longer with explanation)
        studentMessage.length < 500,
        // Contains answer words or reasoning
        /\b(yes|no|maybe|I think|probably|definitely|because|so|then|first|second|next|because|since|I believe|I guess|I suppose|in my opinion)\b/i.test(studentMessage),
        // Looks like a response (sentence structure)
        /^[A-Z]/.test(studentMessage.trim()) && studentMessage.includes(" "),
        // Direct answer pattern
        /^\w+\s+\w+/.test(studentMessage) && !studentMessage.includes("?"),
        // IMPROVED: Shares keywords with ChatGPT's question (semantic similarity)
        sharedKeywords.length >= 2,
        // IMPROVED: Student references the question topic
        chatGPTKeywords.length > 0 && sharedKeywords.length > 0,
        // IMPROVED: Student provides explanation/reasoning (often answers contain "because", "since", "so")
        /\b(because|since|so|therefore|thus|hence|as|if|when|where)\b/i.test(studentMessage),
        // IMPROVED: Student shows understanding (mentions specific concepts from question)
        sharedKeywords.length >= 1 && studentMessage.length > 20
      ];
      const matchCount = answerIndicators.filter(Boolean).length;
      const strongIndicators = [
        sharedKeywords.length >= 2,
        // High semantic similarity
        /\b(because|since|so|I think|probably)\b/i.test(studentMessage)
        // Explanation words
      ].filter(Boolean).length;
      const hasSemanticConnection = sharedKeywords.length >= 1 || /\b(because|since|so|I think|probably|I believe|I guess)\b/i.test(studentMessage);
      const isAnswer = hasSemanticConnection && (matchCount >= 2 || strongIndicators >= 2 && matchCount >= 1);
      if (isAnswer) {
        console.log("GuardRAIl: Detected answer to question.", {
          chatGPTLength: chatGPTMessage.length,
          studentLength: studentMessage.length,
          sharedKeywords: sharedKeywords.length
        });
      } else {
        console.log("GuardRAIl: NOT an answer.", {
          chatGPTLength: chatGPTMessage.length,
          studentLength: studentMessage.length,
          sharedKeywords: sharedKeywords.length,
          hasSemanticConnection
        });
      }
      return isAnswer;
    }
    /** Read guardrail_disabled from storage and update local flag (used to skip interception when lock is off). */
    syncGuardrailDisabled() {
      chrome.storage.sync.get(["guardrail_disabled"], (result) => {
        this.guardrailDisabled = result.guardrail_disabled === true;
        console.log("GuardRAIl: Disabled state from storage:", this.guardrailDisabled);
      });
    }
    async init() {
      console.log("GuardRAIl: Initializing...");
      console.log("GuardRAIl: Platform detected:", this.platform);
      console.log("GuardRAIl: URL:", window.location.href);
      chrome.runtime.onMessage.addListener((message) => {
        if (message.type === "THEME_CHANGED" && this.dialogElement) {
          if (message.theme === "dark") {
            this.dialogElement.setAttribute("data-theme", "dark");
          } else {
            this.dialogElement.removeAttribute("data-theme");
          }
        }
        if (message.type === "GUARDRail_DISABLED_CHANGED" && typeof message.disabled === "boolean") {
          this.guardrailDisabled = message.disabled;
          console.log("GuardRAIl: Disabled state updated:", this.guardrailDisabled);
        }
      });
      this.syncGuardrailDisabled();
      this.setupInterception();
      try {
        await this.ensureAuthenticated();
        console.log("GuardRAIl: Authentication complete");
      } catch (err) {
        console.log("GuardRAIl: Auth setup failed (non-critical):", err);
      }
      this.setupConversationCache();
      this.detectExistingHandoff();
      this.setupChatGPTResponseMonitoring();
      this.setupConversationResetMonitoring();
      this.setupConsoleHelpers();
      this.isInitialized = true;
      this.showToast("GuardRAIl active", "success");
      console.log("GuardRAIl v2 initialized");
    }
    /**
     * CRITICAL: Detect if handoff was already completed for this conversation (old tabs)
     * Checks if a facilitation prompt exists in the conversation
     */
    detectExistingHandoff() {
      try {
        if (document.readyState === "loading") {
          document.addEventListener("DOMContentLoaded", () => {
            setTimeout(() => this.checkForFacilitationMessage(), 1500);
          });
        } else {
          setTimeout(() => this.checkForFacilitationMessage(), 1e3);
        }
      } catch (err) {
        console.error("GuardRAIl: Error detecting existing handoff:", err);
      }
    }
    /**
     * Check if a facilitation message exists in the conversation
     * If found, mark handoff as completed and extract context
     */
    checkForFacilitationMessage() {
      try {
        if (this.handoffCompleted) {
          console.log("GuardRAIl: Handoff already marked as completed");
          return;
        }
        console.log("GuardRAIl: Checking for existing facilitation message...");
        this.updateConversationCache();
        setTimeout(() => {
          let messagesToCheck = this.conversationCache;
          if (messagesToCheck.length === 0) {
            messagesToCheck = this.getChatGPTConversationHistory(20);
          }
          console.log("GuardRAIl: Checking", messagesToCheck.length, "messages for facilitation prompt...");
          const isActualFacilitationPrompt = (c) => {
            const t = c.trim();
            if (t.length < 150) return false;
            return /^I am working on .+ specifically .+ My understanding is that I need to .+ I am stuck on .+/i.test(t) || /Please act as my tutor and help me learn this step by step/i.test(t) && t.length > 200 || /^I'm working on .+ specifically .+ I have tried/i.test(t) || /^I am working on .+ specifically .+ I have tried/i.test(t) || /I'm in grade .+ I'm working on .+ specifically .+ I have tried/i.test(t) && t.length > 200 || /YOUR TEACHING CONTRACT/i.test(t) && /I want to UNDERSTAND this/i.test(t) && t.length > 200;
          };
          const userMessages = messagesToCheck.filter((m) => m.role === "user");
          for (const msg of userMessages) {
            const hasFacilitationPrompt = isActualFacilitationPrompt(msg.content);
            if (hasFacilitationPrompt) {
              console.log("GuardRAIl: ✅ Detected existing facilitation message! Marking handoff as completed.");
              console.log("GuardRAIl: Facilitation prompt preview:", `[${msg.content.length} chars]`);
              this.handoffCompleted = true;
              this.bypassAttemptCount = 0;
              this.postHandoffMessagesSinceHandoff = 10;
              this.currentConversationId = this.getConversationId();
              if (this.conversationCache.length === 0 && messagesToCheck.length > 0) {
                const now = Date.now();
                this.conversationCache = messagesToCheck.map((msg2, index) => ({
                  ...msg2,
                  timestamp: now - (messagesToCheck.length - index) * 1e3
                }));
                const lastAssistant = messagesToCheck.filter((m) => m.role === "assistant").slice(-1)[0];
                if (lastAssistant) {
                  this.lastChatGPTMessage = lastAssistant.content;
                  this.lastChatGPTMessageTimestamp = now;
                }
              }
              this.saveHandoffState();
              console.log("GuardRAIl: ✅ Handoff detection complete. Post-handoff mode activated.");
              console.log("GuardRAIl: Conversation cache:", this.conversationCache.length, "messages");
              return;
            }
          }
          console.log("GuardRAIl: No facilitation message detected. This is a new conversation.");
        }, 500);
      } catch (err) {
        console.error("GuardRAIl: Error checking for facilitation message:", err);
      }
    }
    async ensureAuthenticated() {
      try {
        const auth = await this.sendMessage({ type: "GET_AUTH_STATUS" });
        console.log("GuardRAIl: Auth status:", auth);
        if (!auth?.isAuthenticated) {
          console.log("GuardRAIl: Not authenticated - user must sign in via popup");
          this.showToast("Please sign in to use GuardRAIl. Click the extension icon to get started.", "warning");
          throw new Error("Not authenticated - please sign in via the extension popup");
        } else {
          console.log("GuardRAIl: Already authenticated");
        }
      } catch (err) {
        console.error("GuardRAIl: Auth error:", err);
      }
    }
    setupInterception() {
      this.observer = new MutationObserver(() => {
        if (this.cachedSendButton && !document.body.contains(this.cachedSendButton)) {
          this.cachedSendButton = null;
          this.lastButtonCheck = Date.now();
          this.attachToSendButton();
          return;
        }
        const now = Date.now();
        if (now - this.lastButtonCheck < this.BUTTON_CHECK_INTERVAL) {
          if (!this.debounceTimer) {
            this.debounceTimer = setTimeout(() => {
              this.debounceTimer = null;
              this.attachToSendButton();
            }, this.BUTTON_CHECK_INTERVAL);
          }
          return;
        }
        this.lastButtonCheck = now;
        this.attachToSendButton();
      });
      this.observer.observe(document.body, {
        childList: true,
        subtree: true
      });
      this.attachToSendButton();
      const REATTACH_INTERVAL_MS = 1500;
      this.reattachIntervalId = setInterval(() => {
        const needReattach = !this.cachedSendButton || !document.body.contains(this.cachedSendButton);
        if (needReattach) {
          if (this.cachedSendButton) this.cachedSendButton = null;
          this.attachToSendButton();
        }
      }, REATTACH_INTERVAL_MS);
      document.addEventListener("keydown", this.boundKeydownHandler, true);
      document.addEventListener("submit", this.boundSubmitHandler, true);
      console.log(`GuardRAIl: Platform detected: ${this.platform}`);
    }
    attachToSendButton() {
      const sendButton = this.findSendButton();
      if (!sendButton) {
        if (this.observer) {
          const now = Date.now();
          if (now - this.lastSendButtonNotFoundLog > 15e3) {
            this.lastSendButtonNotFoundLog = now;
            console.warn(`GuardRAIl: Send button not found - ${this.platform} UI may have changed`);
          }
        }
        return;
      }
      if (sendButton.dataset.guardrailAttached) {
        return;
      }
      console.log(`GuardRAIl: Attaching to send button (${this.platform})`, sendButton);
      sendButton.dataset.guardrailAttached = "true";
      const oldIndicator = document.getElementById("guardrail-indicator-button") ?? document.querySelector(".guardrail-indicator");
      if (oldIndicator && oldIndicator.parentNode) oldIndicator.remove();
      sendButton.addEventListener("click", (e) => {
        if (this.allowNextSend) {
          console.log("GuardRAIl: Allowing native send");
          setTimeout(() => {
            this.allowNextSend = false;
          }, 500);
          return true;
        }
        if (this.guardrailDisabled) {
          return;
        }
        console.log("GuardRAIl: Intercepting send button click");
        e.preventDefault();
        e.stopPropagation();
        e.stopImmediatePropagation();
        if (sendButton instanceof HTMLElement) {
          sendButton.setAttribute("disabled", "true");
        }
        this.handleSubmit(e).catch((error) => {
          console.error("GuardRAIl: Error in handleSubmit:", error);
          if (sendButton instanceof HTMLElement) {
            sendButton.removeAttribute("disabled");
          }
          this.unblockUI();
          this.isProcessing = false;
        });
        return false;
      }, true);
    }
    /** Exclude Voice / mic button so we attach to and click the real send button. */
    isVoiceButton(el) {
      const aria = el.getAttribute("aria-label")?.toLowerCase() || "";
      return aria.includes("voice") || aria.includes("mic") || aria.includes("speech");
    }
    findSendButton() {
      if (this.cachedSendButton && document.body.contains(this.cachedSendButton) && this.cachedSendButton.dataset.guardrailAttached) {
        return this.cachedSendButton;
      }
      const chatgptSelectors = [
        "button#composer-submit-button",
        'button[data-testid="send-button"]',
        '[data-testid="send-button"]',
        '[data-testid="composer-send-button"]',
        'button[data-testid="composer-send-button"]',
        "button.composer-submit-btn",
        "button.composer-submit-button-color",
        'form[data-testid="composer"] button[type="submit"]',
        'form button[type="submit"]:not([aria-label*="voice" i]):not([aria-label*="mic" i])'
      ];
      const geminiSelectors = [
        // Gemini 2024-2026 send button selectors (UI changes frequently)
        'button[aria-label*="Send" i]',
        // Case-insensitive
        'button[aria-label*="Submit" i]',
        "button.send-button",
        'button[data-icon="send"]',
        'button[data-testid*="send" i]',
        'button[class*="send-button"]',
        '[role="button"][aria-label*="Send" i]',
        "button:has(mat-icon)",
        // Gemini uses Material Design icons
        'mat-icon-button[aria-label*="Send" i]'
      ];
      const commonSelectors = [
        'form button[type="submit"]',
        'button[aria-label*="Send message"]',
        'button[aria-label*="Send prompt"]'
      ];
      let selectors = [];
      if (this.platform === "chatgpt") {
        selectors = [...chatgptSelectors, ...commonSelectors];
      } else if (this.platform === "gemini") {
        selectors = [...geminiSelectors, ...commonSelectors];
      } else {
        selectors = [...chatgptSelectors, ...geminiSelectors, ...commonSelectors];
      }
      for (const selector of selectors) {
        const el = document.querySelector(selector);
        if (el && !this.isVoiceButton(el)) {
          this.cachedSendButton = el;
          return el;
        }
      }
      const buttons = document.querySelectorAll("button");
      for (const btn of buttons) {
        if (this.isVoiceButton(btn)) continue;
        const ariaLabel = btn.getAttribute("aria-label")?.toLowerCase() || "";
        const className = btn.className?.toLowerCase() || "";
        if (className.includes("send") || className.includes("submit") || ariaLabel.includes("send") || ariaLabel.includes("submit")) {
          this.cachedSendButton = btn;
          return btn;
        }
      }
      this.cachedSendButton = null;
      return null;
    }
    getPromptText() {
      if (this.cachedInputElement && document.body.contains(this.cachedInputElement)) {
        if (this.cachedInputElement instanceof HTMLTextAreaElement) {
          return this.cachedInputElement.value.trim();
        }
        const text = this.cachedInputElement.innerText || this.cachedInputElement.textContent || "";
        return text.trim();
      }
      const chatgptSelectors = [
        "#prompt-textarea",
        'textarea[data-id="root"]',
        'textarea[placeholder*="Message"]'
      ];
      const geminiSelectors = [
        // Gemini 2024-2026 selectors (UI changes frequently)
        'div[contenteditable="true"].ql-editor',
        // Quill editor used by Gemini
        'div[contenteditable="true"][data-placeholder]',
        "rich-textarea textarea",
        // Gemini's custom textarea component
        'textarea[aria-label*="Enter a prompt"]',
        'textarea[aria-label*="Type a message"]',
        'textarea[aria-label*="prompt" i]',
        // Case-insensitive
        'div[contenteditable="true"][aria-label*="prompt" i]',
        'div[contenteditable="true"][aria-label*="message" i]',
        'div.text-input-field [contenteditable="true"]',
        'div[contenteditable="true"]:not([role="button"]):not([aria-hidden="true"])'
      ];
      const commonSelectors = [
        'div[contenteditable="true"][data-placeholder]',
        'div[contenteditable="true"]',
        "textarea"
      ];
      let selectors = [];
      if (this.platform === "chatgpt") {
        selectors = [...chatgptSelectors, ...commonSelectors];
      } else if (this.platform === "gemini") {
        selectors = [...geminiSelectors, ...commonSelectors];
      } else {
        selectors = [...chatgptSelectors, ...geminiSelectors, ...commonSelectors];
      }
      for (const selector of selectors) {
        const el = document.querySelector(selector);
        if (el) {
          this.cachedInputElement = el;
          if (el instanceof HTMLTextAreaElement) {
            return el.value.trim();
          }
          const text = el.innerText || el.textContent || "";
          return text.trim();
        }
      }
      this.cachedInputElement = null;
      return "";
    }
    /** Returns the composer input element (textarea or contenteditable) for Enter-key submit fallback. */
    getPromptInputElement() {
      if (this.cachedInputElement && document.body.contains(this.cachedInputElement)) {
        return this.cachedInputElement;
      }
      const chatgptSelectors = [
        "#prompt-textarea",
        'textarea[data-id="root"]',
        'textarea[placeholder*="Message"]',
        'textarea[aria-label*="Message"]',
        'textarea[aria-label*="prompt" i]'
      ];
      const geminiSelectors = [
        'div[contenteditable="true"].ql-editor',
        'div[contenteditable="true"][data-placeholder]',
        "rich-textarea textarea",
        'textarea[aria-label*="Enter a prompt"]',
        'textarea[aria-label*="Type a message"]',
        'div[contenteditable="true"][aria-label*="prompt" i]',
        'div[contenteditable="true"][aria-label*="message" i]'
      ];
      const common = ['div[contenteditable="true"][data-placeholder]', 'div[contenteditable="true"]', "textarea"];
      const selectors = this.platform === "chatgpt" ? [...chatgptSelectors, ...common] : this.platform === "gemini" ? [...geminiSelectors, ...common] : [...chatgptSelectors, ...geminiSelectors, ...common];
      for (const sel of selectors) {
        try {
          const el = document.querySelector(sel);
          if (el && el.offsetParent !== null) {
            this.cachedInputElement = el;
            return el;
          }
        } catch {
          continue;
        }
      }
      return null;
    }
    setPromptText(text) {
      const chatgptSelectors = [
        "#prompt-textarea",
        'textarea[data-id="root"]',
        'textarea[placeholder*="Message"]',
        'textarea[aria-label*="Message"]',
        'textarea[aria-label*="prompt" i]'
      ];
      const geminiSelectors = [
        // Gemini 2024-2026 selectors (UI changes frequently)
        'div[contenteditable="true"].ql-editor',
        // Quill editor used by Gemini
        'div[contenteditable="true"][data-placeholder]',
        "rich-textarea textarea",
        // Gemini's custom textarea component
        'textarea[aria-label*="Enter a prompt"]',
        'textarea[aria-label*="Type a message"]',
        'textarea[aria-label*="prompt" i]',
        // Case-insensitive
        'div[contenteditable="true"][aria-label*="prompt" i]',
        'div[contenteditable="true"][aria-label*="message" i]',
        'div.text-input-field [contenteditable="true"]',
        'div[contenteditable="true"]:not([role="button"]):not([aria-hidden="true"])'
      ];
      const commonSelectors = [
        'div[contenteditable="true"][data-placeholder]',
        'div[contenteditable="true"]',
        "textarea"
      ];
      let selectors = [];
      if (this.platform === "chatgpt") {
        selectors = [...chatgptSelectors, ...commonSelectors];
      } else if (this.platform === "gemini") {
        selectors = [...geminiSelectors, ...commonSelectors];
      } else {
        selectors = [...chatgptSelectors, ...geminiSelectors, ...commonSelectors];
      }
      let elementFound = false;
      for (const selector of selectors) {
        try {
          const el = document.querySelector(selector);
          if (el && el.offsetParent !== null) {
            elementFound = true;
            if (el instanceof HTMLTextAreaElement) {
              el.focus();
              el.value = text;
              const nativeInputValueSetter = Object.getOwnPropertyDescriptor(
                window.HTMLTextAreaElement.prototype,
                "value"
              )?.set;
              if (nativeInputValueSetter) {
                nativeInputValueSetter.call(el, text);
              }
              el.dispatchEvent(new Event("input", { bubbles: true, cancelable: true }));
              el.dispatchEvent(new Event("change", { bubbles: true, cancelable: true }));
              el.dispatchEvent(new InputEvent("input", {
                bubbles: true,
                cancelable: true,
                data: text,
                inputType: "insertText"
              }));
              el.dispatchEvent(new InputEvent("beforeinput", {
                bubbles: true,
                cancelable: true,
                data: text,
                inputType: "insertText"
              }));
              el.blur();
              el.focus();
              console.log("GuardRAIl: Set text in textarea:", text.substring(0, 50), "Current value:", el.value.substring(0, 50));
            } else {
              el.innerHTML = "";
              el.innerText = text;
              el.textContent = text;
              el.dispatchEvent(new Event("input", { bubbles: true }));
              el.dispatchEvent(new Event("change", { bubbles: true }));
              el.dispatchEvent(new InputEvent("input", { bubbles: true, cancelable: true, data: text }));
              el.focus();
              el.dispatchEvent(new FocusEvent("focus", { bubbles: true }));
              setTimeout(() => {
                el.dispatchEvent(new Event("input", { bubbles: true }));
              }, 50);
            }
            break;
          }
        } catch (e) {
          continue;
        }
      }
      if (!elementFound) {
        console.warn("GuardRAIl: Could not find prompt input element to set text");
      }
    }
    getConversationId() {
      if (this.platform === "chatgpt") {
        const match = window.location.pathname.match(/\/c\/([a-z0-9-]+)/i);
        if (match) return match[1];
      } else if (this.platform === "gemini") {
        const pathMatch = window.location.pathname.match(/\/chat\/([a-z0-9-]+)/i);
        if (pathMatch) return pathMatch[1];
        const urlParams = new URLSearchParams(window.location.search);
        const chatParam = urlParams.get("chat");
        if (chatParam) return chatParam;
      }
      const storageKey = `guardrail_conversation_id_${this.platform}`;
      const stored = sessionStorage.getItem(storageKey);
      if (stored) return stored;
      const newId = `gr_${this.platform}_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
      sessionStorage.setItem(storageKey, newId);
      return newId;
    }
    handleKeyDown(e) {
      if (this.guardrailDisabled) return;
      if (this.allowNextSend || this.dialogElement) {
        return;
      }
      if (this.isProcessing) return;
      if (e.key === "Enter" && !e.shiftKey) {
        const target = e.target;
        if (this.isPromptInput(target)) {
          const prompt = this.getPromptText().trim();
          if (prompt) {
            console.log("GuardRAIl: Enter key intercepted");
            e.preventDefault();
            e.stopPropagation();
            e.stopImmediatePropagation();
            this.handleSubmit(e);
          }
        }
      }
    }
    isPromptInput(el) {
      if (this.platform === "chatgpt") {
        return el.matches('#prompt-textarea, textarea[data-id="root"], textarea');
      } else if (this.platform === "gemini") {
        try {
          return el.matches(
            'textarea, div[contenteditable="true"].ql-editor, div[contenteditable="true"][data-placeholder], div[contenteditable="true"][aria-label*="prompt" i], div[contenteditable="true"][aria-label*="message" i], div.text-input-field [contenteditable="true"], rich-textarea textarea, div[contenteditable="true"]:not([role="button"]):not([aria-hidden="true"])'
          );
        } catch (e) {
          return el.matches('textarea, [contenteditable="true"]');
        }
      }
      return el.matches('#prompt-textarea, textarea, [contenteditable="true"]');
    }
    async handleSubmit(e) {
      if (this.dialogElement) {
        console.log("GuardRAIl: Dialog open, ignoring main submit");
        return;
      }
      if (this.allowNextSend) {
        console.log("GuardRAIl: allowNextSend is true, allowing through (no preventDefault)");
        this.allowNextSend = false;
        return;
      }
      e.preventDefault();
      e.stopPropagation();
      if (typeof e.stopImmediatePropagation === "function") {
        e.stopImmediatePropagation();
      }
      if (this.isProcessing) {
        console.log("GuardRAIl: Already processing, ignoring");
        return;
      }
      const prompt = this.getPromptText().trim();
      if (!prompt) {
        console.log("GuardRAIl: Empty prompt, ignoring");
        return;
      }
      const now = Date.now();
      const withinDebounce = now - this.lastAllowedPromptTime < this.PROMPT_DEBOUNCE_MS;
      const exactMatch = this.lastAllowedPrompt === prompt;
      const startsWithAllowed = this.lastAllowedPrompt != null && this.lastAllowedPrompt.length > 0 && (prompt.startsWith(this.lastAllowedPrompt.trim()) || this.lastAllowedPrompt.trim().startsWith(prompt.substring(0, 30)));
      if (withinDebounce && (exactMatch || startsWithAllowed)) {
        console.log("GuardRAIl: Same prompt detected within debounce window - allowing through (already being sent)");
        this.unblockUI();
        this.isProcessing = false;
        this.isSendingMessage = false;
        this.allowNextSend = true;
        return;
      }
      this.originalPrompt = prompt;
      if (this.isLearningReplyAllowThrough(prompt)) {
        console.log("GuardRAIl: Learning reply detected (answer to tutor question) - allowing through without intervention");
        this.allowNextSend = true;
        this.clickNativeSendButton(prompt);
        return;
      }
      this.isProcessing = true;
      this.blockUI();
      this.setPromptText("");
      console.log("GuardRAIl: Intercepted prompt (length:", prompt.length, ")");
      const isFacilitationPrompt = prompt.length > 500 && (/Please act as my tutor and help me learn/i.test(prompt) || /Before explaining.*ask me what I PREDICT/i.test(prompt) || /I want to understand this deeply, not just get an answer/i.test(prompt) || /Do not write any submission-ready work for me/i.test(prompt) || /Guide me to discover answers through questions/i.test(prompt));
      if (isFacilitationPrompt) {
        console.log("GuardRAIl: ✅ Detected facilitation prompt - allowing through without analysis");
        this.handoffCompleted = true;
        this.bypassAttemptCount = 0;
        this.postHandoffMessagesSinceHandoff = 0;
        this.saveHandoffState();
        this.unblockUI();
        this.clickNativeSendButton();
        return;
      }
      const FULL_ASSIGNMENT_LENGTH = 5e3;
      const LONG_PASTE_LENGTH = 8e3;
      const assignmentLikePatterns = [
        /\bTopic\s*:\s*/i,
        /\bPrompt\s*:\s*/i,
        /\bAssignment\s*:\s*/i,
        /\bChapter\s+\d+/i,
        /\bInstructions\s*:\s*/i,
        /\bTake a stance\b/i,
        /\bSupport your argument\b/i,
        /\bWrite an? essay\b/i,
        /\bAnswer the following\b/i,
        /\bDescribe the\b.*\b(in detail|fully)\b/i,
        /\bReflect on\b/i,
        /\bRespond to the following\b/i
      ];
      const isAssignmentStyle = prompt.length >= FULL_ASSIGNMENT_LENGTH && assignmentLikePatterns.some((p) => p.test(prompt));
      const isLongPaste = prompt.length >= LONG_PASTE_LENGTH;
      const isFullAssignmentPaste = isAssignmentStyle || isLongPaste;
      if (isFullAssignmentPaste) {
        console.log("GuardRAIl: Full assignment / long paste detected (length: " + prompt.length + "), blocking send");
        this.showToast("Full assignment detected — please send one problem or question at a time for the best learning experience.", "success");
        this.isProcessing = false;
        this.unblockUI();
        this.setPromptText(prompt);
        return;
      }
      if (this.handoffCompleted) {
        const resetCheckHistory = this.getChatGPTConversationHistory(5);
        if (resetCheckHistory.length === 0 && this.conversationCache.length === 0) {
          console.log("GuardRAIl: ⚠️ Post-handoff mode but no conversation history - resetting to pre-handoff");
          this.handoffCompleted = false;
          this.bypassAttemptCount = 0;
          this.postHandoffMessagesSinceHandoff = 0;
          this.saveHandoffState();
        }
      }
      if (this.handoffCompleted) {
        console.log("GuardRAIl: Post-handoff mode active. Bypass count:", this.bypassAttemptCount, "Messages since handoff:", this.postHandoffMessagesSinceHandoff);
        const now2 = Date.now();
        const withinDebouncePost = now2 - this.lastAllowedPromptTime < this.PROMPT_DEBOUNCE_MS;
        const exactMatchPost = this.lastAllowedPrompt === prompt;
        const startsWithAllowedPost = this.lastAllowedPrompt != null && this.lastAllowedPrompt.length > 0 && (prompt.startsWith(this.lastAllowedPrompt.trim()) || this.lastAllowedPrompt.trim().startsWith(prompt.substring(0, 30)));
        if (withinDebouncePost && (exactMatchPost || startsWithAllowedPost)) {
          console.log("GuardRAIl: Post-handoff - Same prompt detected within debounce window - allowing through (already being sent)");
          this.unblockUI();
          this.isProcessing = false;
          this.isSendingMessage = false;
          this.allowNextSend = true;
          return;
        }
        const obviousShortcutPatterns = [
          /\b(write my|do my|complete my|finish my|give me the|just give me)\b/i,
          /\b(write a|write an|write the)\s+(paper|essay|report|assignment|homework|code|solution)\b/i,
          /\b(full (code|essay|solution|answer|implementation|paper))\b/i,
          /\b(do it for me|solve this for me|write this for me|write it for me|just write it)\b/i,
          /\b(write to for me|just write to for me|write it to for me)\b/i,
          /\bjust write\s+\w+\s+for me\b/i,
          /\b(paper on|essay on|report on)\b.*\bfor me\b/i
        ];
        const isObviousShortcut = obviousShortcutPatterns.some((p) => p.test(prompt));
        if (isObviousShortcut) {
          console.log("GuardRAIl: Post-handoff - OBVIOUS SHORTCUT detected, intervening");
        }
        try {
          await this.ensureAuthenticated();
        } catch (err) {
          if (err instanceof Error && (err.name === "ExtensionContextInvalidated" || err.message.includes("Extension context invalidated"))) {
            console.warn("GuardRAIl: Extension context invalidated in post-handoff - allowing through");
            this.showToast("Extension was reloaded. Please refresh the page.", "warning");
            this.unblockUI();
            this.isProcessing = false;
            if (this.originalPrompt) {
              this.clickNativeSendButton();
            }
            return;
          }
          console.log("GuardRAIl: Auth failed in post-handoff check");
        }
        if (this.conversationCache.length === 0) {
          this.updateConversationCache();
          if (this.conversationCache.length === 0) {
            const fromDom = this.getChatGPTConversationHistory(10);
            if (fromDom.length > 0) {
              this.conversationCache = fromDom.map((m) => ({ ...m, timestamp: Date.now() }));
              const lastAsst = fromDom.filter((m) => m.role === "assistant").slice(-1)[0];
              if (lastAsst) this.lastChatGPTMessage = lastAsst.content;
              console.log("GuardRAIl: Post-handoff: refreshed context from DOM for analysis:", fromDom.length, "messages");
            }
          }
        }
        const context = this.getContextForAnalysis();
        const chatGPTLastMessage = context.lastMessage || this.getChatGPTLastMessage();
        const isAnswerToQuestion = this.isLikelyAnswerToQuestion(prompt, chatGPTLastMessage);
        if (isAnswerToQuestion && chatGPTLastMessage) {
          console.log("GuardRAIl: Post-handoff - detected answer to question, allowing through");
          console.log("ChatGPT asked:", `[${chatGPTLastMessage.length} chars]`);
          console.log("Student answered:", `[${prompt.length} chars]`);
          this.postHandoffMessagesSinceHandoff++;
          this.consecutiveGoodLearningPrompts++;
          if (this.consecutiveGoodLearningPrompts >= 3 && this.monitoringFrequency === 1) {
            this.monitoringFrequency = 3;
            console.log("GuardRAIl: Reduced monitoring frequency to", this.monitoringFrequency);
          } else if (this.consecutiveGoodLearningPrompts >= 5 && this.monitoringFrequency === 3) {
            this.monitoringFrequency = 5;
            console.log("GuardRAIl: Reduced monitoring frequency to", this.monitoringFrequency);
          }
          this.saveHandoffState();
          const answerRating = prompt.length > 50 && /\b(because|since|so|I think|probably|definitely)\b/i.test(prompt) ? 9 : 8;
          this.logPostHandoffPrompt(prompt, false, "none", answerRating, "learning", null, chatGPTLastMessage);
          this.lastAllowedPrompt = prompt;
          this.lastAllowedPromptTime = Date.now();
          this.unblockUI();
          this.isProcessing = false;
          this.updateGuardrailIndicator("ready");
          this.clickNativeSendButton();
          return;
        }
        let result;
        try {
          result = await this.sendMessage({
            type: "ANALYZE_PROMPT",
            prompt,
            previousMessage: chatGPTLastMessage || void 0,
            conversationContext: chatGPTLastMessage ? {
              lastAssistantMessage: chatGPTLastMessage.substring(0, 500),
              conversationHistory: context.conversationHistory.slice(-4),
              isAnswer: isAnswerToQuestion,
              isStreaming: context.isStreaming
            } : void 0,
            platform: this.platform,
            conversationId: this.getConversationId(),
            url: window.location.href,
            isPostHandoff: true
          });
        } catch (apiError) {
          console.warn("GuardRAIl: API analysis failed, using heuristic fallback:", apiError);
          const heuristicRating = this.heuristicPromptRating(prompt, chatGPTLastMessage);
          const heuristicClassification = heuristicRating >= 6 ? "learning" : "shortcut";
          result = {
            classification: heuristicClassification,
            rating: heuristicRating,
            refinedPrompt: prompt,
            promptId: `fallback_${Date.now()}`,
            conversationId: this.getConversationId()
          };
          console.log("GuardRAIl: Using heuristic fallback - rating:", heuristicRating, "classification:", heuristicClassification);
        }
        if (result?.ratingProvider) {
          console.log("GuardRAIl: Prompt rated via", result.ratingProvider);
        }
        let shouldInterveneNow = this.shouldIntervene(
          result.classification,
          result.rating,
          true,
          chatGPTLastMessage || void 0,
          prompt
        );
        if (!shouldInterveneNow) {
          this.lastAllowedPrompt = prompt;
          this.lastAllowedPromptTime = Date.now();
          console.log("GuardRAIl: Post-handoff - learning prompt (rating:", result.rating, ", classification:", result.classification, "), allowing through");
          this.postHandoffMessagesSinceHandoff++;
          this.saveHandoffState();
          const chatGPTMsgForLog = chatGPTLastMessage || void 0;
          this.logPostHandoffPrompt(prompt, false, "none", result.rating, result.classification, null, chatGPTMsgForLog);
          this.isProcessing = false;
          this.unblockUI();
          this.setPromptText(prompt);
          this.allowNextSend = true;
          setTimeout(() => {
            const sendButton = this.findSendButton();
            if (sendButton) {
              delete sendButton.dataset.guardrailAttached;
              sendButton.click();
              setTimeout(() => this.attachToSendButton(), 100);
            }
          }, 100);
          return;
        }
        if (this.isProcessingIntervention) {
          console.log("GuardRAIl: Intervention already in progress, queueing shortcut");
          this.interventionQueue.push({
            prompt,
            rating: result.rating,
            classification: result.classification,
            promptId: result.promptId,
            conversationId: result.conversationId,
            chatGPTQuestion: chatGPTLastMessage || void 0
          });
          this.postHandoffMessagesSinceHandoff++;
          this.saveHandoffState();
          return;
        }
        const currentConvId = this.getConversationId();
        if (currentConvId !== this.currentConversationId && this.currentConversationId) {
          console.log("GuardRAIl: New conversation detected in post-handoff! Resetting state.");
          this.resetPostHandoffState();
          this.currentConversationId = currentConvId;
          this.handoffCompleted = false;
          this.bypassAttemptCount = 0;
        } else {
          const isBypass = this.detectBypassAttempt(prompt, result.rating, result.classification);
          console.log("GuardRAIl: Post-handoff - shortcut detected (rating:", result.rating, ", classification:", result.classification, ", bypass:", isBypass, "), intervention level:", this.getInterventionLevel());
          this.bypassAttemptCount++;
          this.consecutiveGoodLearningPrompts = 0;
          this.monitoringFrequency = 1;
          this.responsesSinceLastMonitoring = 0;
          console.log("GuardRAIl: Reset monitoring to high frequency (shortcut detected)");
          this.saveHandoffState();
          this.isProcessingIntervention = true;
          this.handlePostHandoffIntervention(prompt, result.rating, result.classification, result.promptId, result.conversationId, chatGPTLastMessage || void 0).catch((err) => {
            console.error("GuardRAIl: handlePostHandoffIntervention error (direct call):", err);
            this.setPromptText(prompt);
            this.unblockUI();
            this.isProcessing = false;
            const errStr = String(err);
            if (errStr.includes("401") || errStr.includes("API error")) {
              this.showToast("Connection error. Your message was restored. Please try again.", "error");
            } else {
              this.showToast("Something went wrong. Your message was restored.", "error");
            }
          }).finally(() => {
            this.isProcessingIntervention = false;
            this.processInterventionQueue();
          });
          this.postHandoffMessagesSinceHandoff++;
          return;
        }
      }
      if (this.testModeEnabled) {
        console.log("🧪 TEST MODE: Prompt intercepted:", prompt);
        const guardrailTest = window.guardrailTest;
        if (guardrailTest && typeof guardrailTest.testClassification === "function") {
          try {
            const testResult = await guardrailTest.testClassification(prompt);
            if (!testResult.error) {
              const emoji = testResult.classification === "learning" ? "✅" : "⚠️";
              this.showToast(
                `🧪 TEST: ${emoji} ${testResult.classification.toUpperCase()} (${testResult.rating}/10)`,
                testResult.classification === "learning" ? "success" : "warning"
              );
              console.log("🧪 TEST MODE Result:", {
                classification: testResult.classification,
                rating: testResult.rating,
                method: testResult.method,
                wouldIntervene: testResult.rating <= 4 || testResult.classification === "shortcut"
              });
            }
          } catch (testError) {
            console.error("🧪 TEST MODE: Error running test:", testError);
            this.showToast("🧪 TEST: Error running classification", "error");
          }
        } else {
          console.warn("🧪 TEST MODE: Test helpers not loaded yet. Allowing through.");
          this.showToast("🧪 TEST: Helpers not ready - allowing through", "warning");
        }
        this.unblockUI();
        this.clickNativeSendButton();
        return;
      }
      this.originalPrompt = prompt;
      try {
        await this.ensureAuthenticated();
      } catch (err) {
        if (err instanceof Error && (err.name === "ExtensionContextInvalidated" || err.message.includes("Extension context invalidated"))) {
          console.warn("GuardRAIl: Extension context invalidated - allowing message through");
          this.showToast("Extension was reloaded. Please refresh the page for full functionality.", "warning");
          this.unblockUI();
          this.isProcessing = false;
          if (this.originalPrompt) {
            this.clickNativeSendButton();
          }
          return;
        }
        console.log("GuardRAIl: Auth failed, proceeding anyway");
      }
      try {
        const context = this.getContextForAnalysis();
        console.log("GuardRAIl: Calling analyzePrompt API with context...");
        const result = await this.sendMessage({
          type: "ANALYZE_PROMPT",
          prompt,
          previousMessage: context.lastMessage || void 0,
          conversationContext: context.lastMessage ? {
            lastAssistantMessage: context.lastMessage.substring(0, 500),
            conversationHistory: context.conversationHistory.slice(-5),
            isAnswer: false,
            // Pre-handoff, so not answering a question
            isStreaming: context.isStreaming
          } : void 0,
          platform: this.platform,
          conversationId: this.getConversationId(),
          url: window.location.href,
          isPostHandoff: false
        });
        if (result?.ratingProvider) {
          console.log("GuardRAIl: Prompt rated via", result.ratingProvider);
        }
        console.log("GuardRAIl: Analysis result:", result);
        this.currentPromptId = result.promptId;
        const urlConvId = this.getConversationIdFromUrl();
        this.currentConversationId = urlConvId ?? result.conversationId ?? this.currentConversationId ?? null;
        const conversationId = this.getConversationId();
        if (conversationId && this.currentConversationId && conversationId !== this.currentConversationId) {
          this.resetPostHandoffState();
          this.currentConversationId = this.getConversationIdFromUrl();
        }
        let shouldInterveneNow = this.shouldIntervene(result.classification, result.rating, false, void 0, prompt);
        if (!shouldInterveneNow && this.isObviousDeliverableRequest(prompt)) {
          shouldInterveneNow = true;
          console.log("GuardRAIl: Pre-handoff obvious deliverable request - intervening despite API result:", { classification: result.classification, rating: result.rating });
        }
        if (!shouldInterveneNow) {
          this.showToast(`Learning prompt detected (${result.rating}/10) ✓`, "success");
          this.handoffCompleted = false;
          this.bypassAttemptCount = 0;
          this.postHandoffMessagesSinceHandoff = 0;
          this.saveHandoffState();
          this.lastAllowedPrompt = prompt;
          this.lastAllowedPromptTime = Date.now();
          this.isProcessing = false;
          this.unblockUI();
          this.setPromptText(prompt);
          this.allowNextSend = true;
          this.clickNativeSendButton(prompt);
          return;
        } else {
          this.storedSignals = result.signals || {
            academicIntent: false,
            explicitShortcut: false,
            attemptPresent: false,
            metacognitive: false,
            benignChatter: false
          };
          this.useFixedThreeStepFlow = true;
          const firstQuestion = _GuardRAIl.FIXED_REPROMPT_QUESTIONS[0];
          this.conversationHistory = [
            { role: "user", content: prompt },
            { role: "assistant", content: firstQuestion }
          ];
          this.updateGuardrailIndicator("active");
          this.showGuidedDialog(firstQuestion, result.rating);
        }
      } catch (error) {
        console.error("GuardRAIl error:", error);
        const errMsg = error.message || "Unknown error";
        const isExtensionContextError = error.name === "ExtensionContextInvalidated" || errMsg.includes("Extension context invalidated") || errMsg.includes("message port closed") || errMsg.includes("Receiving end does not exist");
        if (isExtensionContextError) {
          console.warn("GuardRAIl: Extension context invalidated - allowing message through");
          this.showToast("Extension was reloaded. Please refresh the page for full functionality.", "warning");
          this.unblockUI();
          this.isProcessing = false;
          if (this.originalPrompt) {
            this.clickNativeSendButton();
          } else {
            const currentText = this.getPromptText();
            if (currentText && currentText.trim().length > 0) {
              this.originalPrompt = currentText;
              this.clickNativeSendButton();
            } else {
              console.error("GuardRAIl: Could not restore prompt text after extension context invalidation");
              this.showToast("Please refresh the page and try again", "error");
            }
          }
          return;
        }
        if (errMsg.includes("Not authenticated") || errMsg.includes("Student not found")) {
          try {
            await this.ensureAuthenticated();
            this.showToast("Retrying...", "warning");
            setTimeout(() => this.handleSubmit(e), 1e3);
            return;
          } catch (retryErr) {
            this.showToast("Auth failed - please login in popup", "error");
          }
        } else if (errMsg.includes("rate_limit") || errMsg.includes("Rate limit")) {
          this.showToast("Rate limited - wait 20s and try again", "warning");
        } else if (errMsg.includes("quota") || errMsg.includes("billing")) {
          this.showToast("OpenAI API needs credits - check billing", "error");
        } else {
          this.showToast(`Error: ${errMsg.slice(0, 50)}...`, "error");
        }
        this.unblockUI();
      } finally {
        this.isProcessing = false;
      }
    }
    blockUI() {
      const sendButton = this.findSendButton();
      if (sendButton) {
        sendButton.setAttribute("disabled", "true");
        sendButton.style.opacity = "0.5";
        sendButton.style.pointerEvents = "none";
      }
      this.updateGuardrailIndicator("processing");
    }
    unblockUI() {
      const sendButton = this.findSendButton();
      if (sendButton) {
        sendButton.removeAttribute("disabled");
        sendButton.style.opacity = "1";
        sendButton.style.pointerEvents = "auto";
      }
      this.updateGuardrailIndicator("ready");
    }
    async getThemePreference() {
      try {
        const storage = await chrome.storage.sync.get(["guardrail_theme"]);
        if (storage.guardrail_theme) {
          return storage.guardrail_theme === "dark" ? "dark" : "light";
        }
        if (this.platform === "gemini") {
          const isDark = document.documentElement.getAttribute("data-theme") === "dark" || document.body.classList.contains("dark-mode") || document.body.classList.contains("dark-theme") || document.documentElement.classList.contains("dark") || window.matchMedia("(prefers-color-scheme: dark)").matches;
          return isDark ? "dark" : "light";
        } else if (this.platform === "chatgpt") {
          const isDark = document.documentElement.classList.contains("dark") || document.documentElement.getAttribute("data-theme") === "dark" || window.matchMedia("(prefers-color-scheme: dark)").matches;
          return isDark ? "dark" : "light";
        }
        return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
      } catch {
        return "light";
      }
    }
    /**
     * Safety: Detect if text looks like the full final prompt instead of a guided question.
     * Prevents showing cached/full prompt in guided dialog. Full prompts can contain '?'
     * in instructions (e.g. "What do you already know?"), so we check length + phrases.
     */
    ensureGuidedQuestion(text) {
      if (!text || text.trim().length === 0) return text;
      const t = text.trim();
      const hasFullPromptPhrases = /Please act as my tutor and help me learn/i.test(t) || /Here is how I would like you to teach me/i.test(t) || /I am working on .+ specifically .+ I have tried/i.test(t) || /1\.\s*Before explaining/i.test(t) || // Numbered list start
      /Do not write any submission-ready work for me/i.test(t);
      const looksLikeFullPrompt = t.length > 350 && hasFullPromptPhrases;
      if (looksLikeFullPrompt) {
        console.warn("GuardRAIl: ensureGuidedQuestion - detected full prompt (length=", t.length, "), using fallback");
        return "What specific part of what you're learning are you stuck on? Let's get you back on track.";
      }
      return t;
    }
    // REMOVED: showWorkingOnDialog() — "What assignment or topic" was a separate popup that broke the flow.
    // First question (subject/class) is now always the first question IN the reprompting dialog from refinePrompt.
    showGuidedDialog(initialQuestion, rating) {
      initialQuestion = this.ensureGuidedQuestion(initialQuestion);
      this.currentDialogRating = rating;
      if (!initialQuestion || initialQuestion.trim().length === 0) {
        console.error("GuardRAIl: showGuidedDialog called with empty question, allowing prompt through");
        this.clickNativeSendButton();
        return;
      }
      if (this.dialogElement) {
        this.dialogElement.remove();
        this.dialogElement = null;
      }
      const dialog = document.createElement("div");
      dialog.className = "guardrail-dialog-overlay";
      this.getThemePreference().then((theme) => {
        if (theme === "dark") {
          dialog.setAttribute("data-theme", "dark");
        }
      });
      dialog.innerHTML = `
      <div class="guardrail-dialog">
        <div class="guardrail-dialog-header">
          <div class="guardrail-logo">
            <span class="guardrail-logo-icon" aria-hidden="true"><svg width="20" height="22" viewBox="0 0 20 22" fill="none" xmlns="http://www.w3.org/2000/svg" role="img"><path d="M10 1L2 5v6c0 5.55 3.84 10.74 8 12 4.16-1.26 8-6.45 8-12V5l-8-4z" fill="currentColor"/></svg></span>
            <span class="guardrail-logo-text">GuardRAIl</span>
          </div>
          <div class="guardrail-header-right">
            <div class="guardrail-rating">
              <span class="guardrail-rating-label">Learning Score</span>
              <span class="guardrail-rating-value ${rating <= 3 ? "low" : rating <= 6 ? "medium" : "high"}">${rating}/10</span>
            </div>
            <button type="button" id="guardrail-dialog-feedback-btn" class="guardrail-dialog-feedback-btn" aria-label="Report feedback" title="Report feedback about this prompt">
              <svg class="guardrail-dialog-feedback-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/><line x1="12" y1="7" x2="12" y2="12"/><circle cx="12" cy="15" r="1" fill="currentColor" stroke="none"/></svg>
            </button>
          </div>
        </div>
        
        <div class="guardrail-dialog-body" id="guardrail-dialog-main">
          <div class="guardrail-info">
            <p>Answer a couple of quick questions so I can help you learn this effectively. This only takes a moment.</p>
          </div>
          <div class="guardrail-messages" id="guardrail-messages">
            <div class="guardrail-message assistant">
              <div class="guardrail-message-content">${this.escapeHtml(initialQuestion)}</div>
            </div>
          </div>
          
          <div class="guardrail-input-area">
            <textarea 
              id="guardrail-input" 
              class="guardrail-input" 
              placeholder="Type your response here..."
              rows="2"
            ></textarea>
            <button id="guardrail-send" class="guardrail-btn guardrail-btn-primary">
              Continue
            </button>
          </div>
        </div>
        
        <div class="guardrail-dialog-feedback-panel hidden" id="guardrail-dialog-feedback-panel">
          <div class="guardrail-dialog-feedback-title">Send feedback</div>
          <p class="guardrail-dialog-feedback-hint">Your feedback will be linked to this conversation so we can improve the process.</p>
          <div class="guardrail-dialog-feedback-form">
            <label for="guardrail-feedback-subject">Subject</label>
            <input type="text" id="guardrail-feedback-subject" placeholder="Brief summary (optional)" maxlength="120">
            <label for="guardrail-feedback-message">Message</label>
            <textarea id="guardrail-feedback-message" placeholder="Your feedback…" rows="3" required></textarea>
            <div id="guardrail-feedback-error" class="guardrail-feedback-error hidden"></div>
            <div class="guardrail-dialog-feedback-actions">
              <button type="button" id="guardrail-feedback-submit" class="guardrail-btn guardrail-btn-primary">Send feedback</button>
              <button type="button" id="guardrail-feedback-back" class="guardrail-btn guardrail-btn-ghost">Back</button>
            </div>
          </div>
        </div>
        
        <div class="guardrail-dialog-footer" id="guardrail-dialog-footer">
          <button id="guardrail-cancel" class="guardrail-btn guardrail-btn-ghost">
            Cancel
          </button>
        </div>
      </div>
    `;
      document.body.appendChild(dialog);
      this.dialogElement = dialog;
      const input = dialog.querySelector("#guardrail-input");
      const sendBtn = dialog.querySelector("#guardrail-send");
      const cancelBtn = dialog.querySelector("#guardrail-cancel");
      const feedbackBtn = dialog.querySelector("#guardrail-dialog-feedback-btn");
      const feedbackPanel = dialog.querySelector("#guardrail-dialog-feedback-panel");
      const mainBody = dialog.querySelector("#guardrail-dialog-main");
      const footer = dialog.querySelector("#guardrail-dialog-footer");
      input.focus();
      input.addEventListener("keydown", (e) => {
        if (e.key === "Enter" && !e.shiftKey) {
          e.preventDefault();
          e.stopPropagation();
          e.stopImmediatePropagation();
          console.log("GuardRAIl: Dialog Enter key pressed");
          this.sendGuidedResponse();
          return false;
        }
      }, true);
      sendBtn.addEventListener("click", () => this.sendGuidedResponse());
      cancelBtn.addEventListener("click", () => this.closeGuidedDialog());
      feedbackBtn.addEventListener("click", () => {
        mainBody.classList.add("hidden");
        footer.classList.add("hidden");
        feedbackPanel.classList.remove("hidden");
        feedbackPanel.querySelector("#guardrail-feedback-message")?.focus();
      });
      dialog.querySelector("#guardrail-feedback-back")?.addEventListener("click", () => {
        feedbackPanel.classList.add("hidden");
        mainBody.classList.remove("hidden");
        footer.classList.remove("hidden");
      });
      dialog.querySelector("#guardrail-feedback-submit")?.addEventListener("click", () => this.submitInterceptDialogFeedback(dialog));
    }
    async submitInterceptDialogFeedback(dialogRoot) {
      const panel = dialogRoot.querySelector("#guardrail-dialog-feedback-panel");
      const subjectEl = dialogRoot.querySelector("#guardrail-feedback-subject");
      const messageEl = dialogRoot.querySelector("#guardrail-feedback-message");
      const errorEl = dialogRoot.querySelector("#guardrail-feedback-error");
      const submitBtn = dialogRoot.querySelector("#guardrail-feedback-submit");
      const mainBody = dialogRoot.querySelector("#guardrail-dialog-main");
      const footer = dialogRoot.querySelector("#guardrail-dialog-footer");
      const subject = subjectEl?.value?.trim() ?? "";
      const message = messageEl?.value?.trim() ?? "";
      if (!message) {
        if (errorEl) {
          errorEl.textContent = "Please enter your feedback.";
          errorEl.classList.remove("hidden");
        }
        return;
      }
      if (errorEl) errorEl.classList.add("hidden");
      if (submitBtn) {
        submitBtn.disabled = true;
        submitBtn.textContent = "Sending…";
      }
      const conversationSnapshot = {
        originalPrompt: this.originalPrompt || null,
        conversationHistory: this.conversationHistory,
        rating: this.currentDialogRating ?? null
      };
      try {
        const auth = await this.sendMessage({ type: "GET_AUTH_STATUS" });
        await this.sendMessage({
          type: "SUBMIT_FEEDBACK",
          source: "intercept_dialog",
          subject,
          message,
          studentId: auth?.studentId ?? void 0,
          conversationId: this.currentConversationId ?? void 0,
          promptId: this.currentPromptId ?? void 0,
          conversationSnapshot
        });
        if (subjectEl) subjectEl.value = "";
        if (messageEl) messageEl.value = "";
        panel?.classList.add("hidden");
        mainBody?.classList.remove("hidden");
        footer?.classList.remove("hidden");
        this.showToast("Thanks for your feedback", "success");
      } catch (err) {
        if (errorEl) {
          errorEl.textContent = err.message || "Failed to send feedback.";
          errorEl.classList.remove("hidden");
        }
      } finally {
        if (submitBtn) {
          submitBtn.disabled = false;
          submitBtn.textContent = "Send feedback";
        }
      }
    }
    // Hard cap: 5 user responses max, then auto-generate learning prompt (matches server forceFinishThreshold)
    async sendGuidedResponse() {
      const input = this.dialogElement?.querySelector("#guardrail-input");
      const sendBtn = this.dialogElement?.querySelector("#guardrail-send");
      const messagesContainer = this.dialogElement?.querySelector("#guardrail-messages");
      if (!input || !messagesContainer) {
        console.log("GuardRAIl: Dialog elements not found");
        return;
      }
      const userResponse = input.value.trim();
      if (!userResponse) {
        console.log("GuardRAIl: Empty response, ignoring");
        return;
      }
      if (userResponse.length > 500) {
        this.showToast("Please keep responses to 500 characters or less", "warning");
        input.focus();
        return;
      }
      const userTurns = this.conversationHistory.filter((m) => m.role === "user").length;
      if (userTurns >= this.MAX_DIALOG_TURNS) {
        console.warn("GuardRAIl: Max dialog turns reached (" + userTurns + "). Auto-generating learning prompt.");
        this.addMessageToDialog(userResponse, "user");
        const allUserMessages = this.conversationHistory.filter((m) => m.role === "user");
        const meaningfulResponses = allUserMessages.slice(1).filter((m) => m.content.length > 15 && !/^(yes|no|ok|maybe|i don't know|idk)$/i.test(m.content.trim())).map((m) => m.content).slice(0, 3);
        let learningPrompt = `I need help understanding my assignment. `;
        if (this.originalPrompt && this.originalPrompt.length > 10) {
          learningPrompt += `I'm working on: ${this.originalPrompt}. `;
        }
        if (meaningfulResponses.length > 0) {
          learningPrompt += `Here's what I've shared: ${meaningfulResponses.join(". ")}. `;
        }
        learningPrompt += `I'd like to learn the concepts step by step rather than just getting the answer.`;
        this.addMessageToDialog(
          "Thanks for your responses! I've created a learning prompt based on what you've shared.",
          "assistant"
        );
        setTimeout(() => {
          this.showFinalPrompt(learningPrompt);
        }, 500);
        return;
      }
      console.log("GuardRAIl: Sending guided response (length:", userResponse.length, ", turn:", userTurns + 1, "/" + this.MAX_DIALOG_TURNS + ")");
      console.log("GuardRAIl: Current state:", {
        originalPromptLength: this.originalPrompt?.length || 0,
        historyLength: this.conversationHistory.length,
        hasPromptId: !!this.currentPromptId
      });
      input.disabled = true;
      if (sendBtn) {
        sendBtn.disabled = true;
        sendBtn.textContent = "Thinking...";
      }
      this.updateGuardrailIndicator("processing");
      this.addMessageToDialog(userResponse, "user");
      input.value = "";
      const updatedHistory = [...this.conversationHistory, { role: "user", content: userResponse }];
      this.conversationHistory = updatedHistory;
      try {
        if (this.useFixedThreeStepFlow) {
          const userMessages = updatedHistory.filter((m) => m.role === "user");
          const dialogAnswerCount2 = userMessages.length - 1;
          if (dialogAnswerCount2 < 3) {
            const nextQuestion = _GuardRAIl.FIXED_REPROMPT_QUESTIONS[dialogAnswerCount2];
            this.conversationHistory.push({ role: "assistant", content: nextQuestion });
            this.addMessageToDialog(nextQuestion, "assistant");
            this.updateGuardrailIndicator("active");
            input.disabled = false;
            if (sendBtn) {
              sendBtn.disabled = false;
              sendBtn.textContent = "Continue";
            }
            input.focus();
            return;
          }
          const subjectAnswer = userMessages[1]?.content ?? "";
          const taskAnswer = userMessages[2]?.content ?? "";
          const stuckAnswer = userMessages[3]?.content ?? "";
          const polishResult = await this.sendMessage({
            type: "POLISH_LEARNING_PROMPT",
            originalPrompt: String(this.originalPrompt || ""),
            subjectAnswer,
            taskAnswer,
            stuckAnswer,
            promptId: this.currentPromptId || "",
            conversationId: this.currentConversationId || ""
          });
          this.updateGuardrailIndicator("active");
          this.showFinalPrompt(polishResult.refinedPrompt);
          this.showToast("Your prompt is ready", "success");
          return;
        }
        const currentTurns = updatedHistory.filter((m) => m.role === "user").length;
        const atMaxTurns = currentTurns >= this.MAX_DIALOG_TURNS;
        console.log("GuardRAIl: Calling refinePrompt API with:", {
          originalPrompt: this.originalPrompt?.substring(0, 50),
          historyLength: updatedHistory.length,
          currentTurns,
          clientForceFinal: atMaxTurns
        });
        const result = await this.sendMessage({
          type: "REFINE_PROMPT",
          originalPrompt: String(this.originalPrompt || ""),
          conversationHistory: JSON.parse(JSON.stringify(updatedHistory)),
          // Deep copy for message passing
          promptId: this.currentPromptId || "",
          conversationId: this.currentConversationId || "",
          signals: this.storedSignals || void 0,
          // Pass stored signals
          ...atMaxTurns && { clientForceFinal: true }
        });
        console.log("GuardRAIl: Refine result:", result);
        console.log("GuardRAIl: isFinal:", result.isFinal);
        const userMessageCount = updatedHistory.filter((m) => m.role === "user").length;
        const dialogAnswerCount = userMessageCount - 1;
        if (result.isFinal) {
          if (dialogAnswerCount < 3) {
            const nextQuestion = dialogAnswerCount === 1 ? "What are you working on or what's the assignment?" : "What part are you stuck on or want to work on?";
            this.conversationHistory.push({ role: "assistant", content: nextQuestion });
            this.addMessageToDialog(nextQuestion, "assistant");
            this.updateGuardrailIndicator("active");
            input.disabled = false;
            if (sendBtn) {
              sendBtn.disabled = false;
              sendBtn.textContent = "Continue";
            }
            input.focus();
            return;
          }
          console.log("GuardRAIl: ✅ Final learning-focused prompt generated!");
          this.updateGuardrailIndicator("active");
          this.showFinalPrompt(result.refinedPrompt);
          this.showToast("Your prompt is ready", "success");
        } else {
          if (currentTurns >= this.MAX_DIALOG_TURNS) {
            console.warn("GuardRAIl: Max turns reached (" + currentTurns + "), using fallback learning prompt");
            const um = updatedHistory.filter((m) => m.role === "user");
            let learningPrompt = `I need help understanding my assignment. `;
            if (this.originalPrompt && this.originalPrompt.length > 10) {
              learningPrompt += `I'm working on: ${this.originalPrompt}. `;
            }
            const meaningfulResponses = um.slice(1).filter((m) => m.content.length > 15 && !/^(yes|no|ok|maybe|i don't know|idk)$/i.test(m.content.trim())).map((m) => m.content).slice(0, 2);
            if (meaningfulResponses.length > 0) {
              learningPrompt += `Here's what I've shared: ${meaningfulResponses.join(". ")}. `;
            }
            learningPrompt += `I'd like to learn the concepts step by step rather than just getting the answer.`;
            this.updateGuardrailIndicator("active");
            this.addMessageToDialog("Thanks for your responses! Here's your learning prompt:", "assistant");
            this.showFinalPrompt(learningPrompt);
            return;
          }
          this.conversationHistory.push({ role: "assistant", content: result.refinedPrompt });
          this.addMessageToDialog(result.refinedPrompt, "assistant");
          this.updateGuardrailIndicator("active");
          input.disabled = false;
          if (sendBtn) {
            sendBtn.disabled = false;
            sendBtn.textContent = "Continue";
          }
          input.focus();
        }
      } catch (error) {
        console.error("GuardRAIl: Refine/Polish error:", error);
        console.error("GuardRAIl: Refine error details:", {
          error,
          errorType: error?.constructor?.name,
          errorMessage: error instanceof Error ? error.message : String(error),
          errorStack: error instanceof Error ? error.stack : void 0
        });
        const errMsg = error.message || "Unknown error";
        this.showToast(`Error: ${errMsg.slice(0, 50)}`, "error");
        this.updateGuardrailIndicator(this.dialogElement ? "active" : "ready");
        input.disabled = false;
        if (sendBtn) {
          sendBtn.disabled = false;
          sendBtn.textContent = "Continue";
        }
        input.focus();
      }
    }
    addMessageToDialog(content, role) {
      const messagesContainer = this.dialogElement?.querySelector("#guardrail-messages");
      if (!messagesContainer) return;
      const messageEl = document.createElement("div");
      messageEl.className = `guardrail-message ${role}`;
      messageEl.innerHTML = `<div class="guardrail-message-content">${this.escapeHtml(content)}</div>`;
      messagesContainer.appendChild(messageEl);
      messagesContainer.scrollTop = messagesContainer.scrollHeight;
    }
    showFinalPrompt(finalPrompt) {
      const inputArea = this.dialogElement?.querySelector(".guardrail-input-area");
      if (!inputArea) return;
      inputArea.innerHTML = `
      <div class="guardrail-final-prompt">
        <div class="guardrail-final-label">Your prompt is ready</div>
        <div class="guardrail-final-text">${this.escapeHtml(finalPrompt)}</div>
        <div class="guardrail-final-actions">
          <button id="guardrail-copy" class="guardrail-btn guardrail-btn-secondary">
            Copy
          </button>
          <button id="guardrail-use" class="guardrail-btn guardrail-btn-success">
            Use Prompt
          </button>
        </div>
      </div>
    `;
      const copyBtn = inputArea.querySelector("#guardrail-copy");
      const useBtn = inputArea.querySelector("#guardrail-use");
      copyBtn.addEventListener("click", () => {
        navigator.clipboard.writeText(finalPrompt);
        this.showToast("Copied to clipboard!", "success");
      });
      useBtn.addEventListener("click", () => {
        this.closeGuidedDialog();
        this.handoffCompleted = true;
        this.bypassAttemptCount = 0;
        this.postHandoffMessagesSinceHandoff = 0;
        this.saveHandoffState();
        this.unblockUI();
        this.isProcessing = false;
        this.lastAllowedPrompt = finalPrompt;
        this.lastAllowedPromptTime = Date.now();
        this.showToast("Sending to ChatGPT...", "success");
        this.clickNativeSendButton(finalPrompt);
      });
    }
    closeGuidedDialog() {
      if (this.currentPromptId && this.conversationHistory.length > 2) {
        const turns = Math.floor(this.conversationHistory.length / 2);
        console.log("GuardRAIl: Dialog canceled after", turns, "questions");
      }
      if (this.dialogElement) {
        this.dialogElement.remove();
        this.dialogElement = null;
      }
      this.conversationHistory = [];
      this.useFixedThreeStepFlow = false;
      this.currentPromptId = null;
      this.storedSignals = null;
      this.originalPrompt = "";
      this.updateGuardrailIndicator("ready");
    }
    resetPostHandoffState() {
      console.log("GuardRAIl: Resetting post-handoff state for current conversation");
      const convId = this.getConversationIdFromUrl();
      sessionStorage.removeItem(this.getHandoffStorageKey(convId));
      this.clearHandoffStateInMemory();
      this.lastCacheUpdate = 0;
      this.currentConversationId = convId;
      console.log("GuardRAIl: Post-handoff state reset complete. Conversation ID:", this.currentConversationId);
    }
    getInterventionLevel() {
      if (this.bypassAttemptCount === 1) return "gentle";
      if (this.bypassAttemptCount === 2) return "artifact";
      return "full";
    }
    /**
     * NEW: Process queued interventions (rapid-fire shortcuts)
     * Handles multiple shortcut attempts in quick succession
     */
    async processInterventionQueue() {
      if (this.interventionQueue.length === 0 || this.isProcessingIntervention) {
        return;
      }
      const nextIntervention = this.interventionQueue.shift();
      if (!nextIntervention) return;
      console.log("GuardRAIl: Processing queued intervention");
      this.isProcessingIntervention = true;
      try {
        if (this.handoffCompleted) {
          await this.handlePostHandoffIntervention(
            nextIntervention.prompt,
            nextIntervention.rating,
            nextIntervention.classification,
            nextIntervention.promptId,
            nextIntervention.conversationId,
            nextIntervention.chatGPTQuestion
          );
        } else {
          this.isProcessing = true;
          this.blockUI();
          this.originalPrompt = nextIntervention.prompt;
          this.currentPromptId = nextIntervention.promptId;
          this.currentConversationId = nextIntervention.conversationId;
          this.conversationHistory = [{ role: "user", content: nextIntervention.prompt }];
          try {
            const refineResult = await this.sendMessage({
              type: "REFINE_PROMPT",
              originalPrompt: nextIntervention.prompt,
              conversationHistory: this.conversationHistory,
              promptId: nextIntervention.promptId,
              conversationId: nextIntervention.conversationId
            });
            if (refineResult.isFinal) {
              this.showFinalPrompt(refineResult.refinedPrompt);
            } else {
              this.showGuidedDialog(refineResult.refinedPrompt, nextIntervention.rating);
            }
          } catch (error) {
            console.error("GuardRAIl: Error processing queued intervention:", error);
            this.setPromptText(nextIntervention.prompt);
            this.unblockUI();
            this.isProcessing = false;
            const errStr = String(error);
            this.showToast(errStr.includes("401") || errStr.includes("API error") ? "Connection error. Your message was restored. Please try again." : "Something went wrong. Your message was restored.", "error");
          }
        }
      } catch (error) {
        console.error("GuardRAIl: Error in processInterventionQueue:", error);
        this.setPromptText(nextIntervention?.prompt ?? this.originalPrompt);
        this.unblockUI();
        this.isProcessing = false;
        const errStr = String(error);
        this.showToast(errStr.includes("401") || errStr.includes("API error") ? "Connection error. Your message was restored. Please try again." : "Something went wrong. Your message was restored.", "error");
      } finally {
        this.isProcessingIntervention = false;
        this.processInterventionQueue();
      }
    }
    /**
     * Unified decision logic: Should we intervene or allow through?
     * Uses both classification and rating consistently
     */
    shouldIntervene(classification, rating, isPostHandoff, chatGPTQuestion, studentPrompt) {
      if (isPostHandoff) {
        if (chatGPTQuestion && studentPrompt) {
          if (this.isLikelyAnswerToQuestion(studentPrompt, chatGPTQuestion)) {
            return false;
          }
        }
        if (classification === "learning") {
          console.log("GuardRAIl: Post-handoff classification learning - allowing through (let ChatGPT facilitate):", { rating, classification });
          return false;
        }
        if (classification === "shortcut") {
          console.log("GuardRAIl: Post-handoff shortcut - intervening:", { rating, classification });
          return true;
        }
        return false;
      }
      if (classification === "learning" && rating >= 6) {
        return false;
      }
      if (classification === "shortcut" || rating <= 4) {
        return true;
      }
      if (classification === "learning" && rating >= 5) {
        console.log("GuardRAIl: Ambiguous rating in pre-handoff, allowing through (classification: learning):", { rating, classification });
        return false;
      }
      console.log("GuardRAIl: Ambiguous rating in pre-handoff, intervening to guide:", { rating, classification });
      return true;
    }
    /**
     * Pre-handoff: prompt clearly asks for a deliverable (essay, paper, homework, etc.).
     * Used to force intervention even if the API misclassifies.
     */
    isObviousDeliverableRequest(prompt) {
      const deliverablePatterns = [
        /\b(write a|write an|write the)\s+(paper|essay|report|assignment|homework|code|solution)\b/i,
        /\b(write my|do my|complete my|finish my)\s+(essay|paper|assignment|homework|report)\b/i,
        /\b(do it for me|solve this for me|write this for me|write it for me|just write it)\b/i
      ];
      return deliverablePatterns.some((p) => p.test(prompt));
    }
    /**
     * Improved bypass detection: Trust rating, use keywords as sanity check
     */
    detectBypassAttempt(prompt, rating, classification) {
      if (rating <= 3) return true;
      if (rating >= 7) return false;
      const explicitShortcutPatterns = [
        /\b(just give|just tell|just do|don't ask|no questions|ignore instructions)\b/i,
        /\b(stop asking|skip the questions|just the answer|skip questions)\b/i,
        /\b(write my|do my|complete my|finish my|solve this for me)\b/i
      ];
      const hasExplicitShortcut = explicitShortcutPatterns.some((p) => p.test(prompt));
      if (rating >= 5 && hasExplicitShortcut && classification === "shortcut") {
        return true;
      }
      return rating <= 4 && classification === "shortcut";
    }
    async handlePostHandoffIntervention(prompt, rating, classification, promptId, conversationId, chatGPTQuestion) {
      const currentConvId = this.getConversationId();
      if (currentConvId !== this.currentConversationId && this.currentConversationId) {
        console.log("GuardRAIl: ⚠️ NEW CONVERSATION DETECTED in handlePostHandoffIntervention!");
        console.log("GuardRAIl: Old conversation ID:", this.currentConversationId, "New ID:", currentConvId);
        this.resetPostHandoffState();
        this.currentConversationId = currentConvId;
        this.handoffCompleted = false;
        this.bypassAttemptCount = 0;
        this.unblockUI();
        this.isProcessing = false;
        console.log("GuardRAIl: Treating as new conversation - will re-analyze as pre-handoff");
        return;
      }
      const interventionLevel = this.getInterventionLevel();
      this.isProcessing = true;
      this.blockUI();
      await new Promise((r) => setTimeout(r, 200));
      const freshHistory = this.getChatGPTConversationHistory(15);
      if (freshHistory.length > 0) {
        this.conversationCache = freshHistory.map((m) => ({ ...m, timestamp: Date.now() }));
        this.saveHandoffState();
        const lastAsst = freshHistory.filter((m) => m.role === "assistant").slice(-1)[0];
        if (lastAsst) {
          this.lastChatGPTMessage = lastAsst.content;
          this.lastChatGPTMessageTimestamp = Date.now();
        }
        console.log("GuardRAIl: Re-interception: refreshed context from DOM:", freshHistory.length, "messages");
      }
      this.updateConversationCache();
      if (this.conversationCache.length === 0) {
        await this.ensureContextAvailable(3);
      }
      const context = this.getContextForAnalysis();
      let chatGPTHistory = [];
      console.log("GuardRAIl: Context extraction - cache length:", this.conversationCache.length);
      if (this.conversationCache.length > 0) {
        chatGPTHistory = this.conversationCache.slice(-10);
        console.log("GuardRAIl: Using conversation context for re-intervention:", chatGPTHistory.length, "messages");
        console.log("GuardRAIl: Cached messages preview:", chatGPTHistory.map((m) => `${m.role}: [${m.content.length} chars]`));
      } else {
        console.log("GuardRAIl: Cache empty, extracting from DOM...");
        chatGPTHistory = this.getChatGPTConversationHistory(10);
        console.log("GuardRAIl: DOM extraction result:", chatGPTHistory.length, "messages");
        if (chatGPTHistory.length === 0) {
          const lastMsg = this.lastChatGPTMessage || context.lastMessage || chatGPTQuestion;
          console.log("GuardRAIl: Fallback - lastMsg available:", !!lastMsg, "context.lastMessage:", !!context.lastMessage);
          if (lastMsg) {
            chatGPTHistory = [{ role: "assistant", content: lastMsg }];
            console.log("GuardRAIl: Using last ChatGPT message as fallback context:", `[${lastMsg.length} chars]`);
          } else {
            console.warn("GuardRAIl: ⚠️ CRITICAL: No conversation context available at all");
            console.warn("GuardRAIl: Context debug:", {
              cacheLength: this.conversationCache.length,
              lastChatGPTMessage: this.lastChatGPTMessage?.substring(0, 50),
              contextLastMessage: context.lastMessage?.substring(0, 50),
              chatGPTQuestion: chatGPTQuestion?.substring(0, 50)
            });
          }
        } else {
          this.conversationCache = chatGPTHistory.map((msg) => ({ ...msg, timestamp: Date.now() }));
          this.saveHandoffState();
          console.log("GuardRAIl: ✅ Extracted and cached conversation context from DOM:", chatGPTHistory.length, "messages");
          console.log("GuardRAIl: Extracted messages preview:", chatGPTHistory.map((m) => `${m.role}: [${m.content.length} chars]`));
        }
      }
      console.log("GuardRAIl: Final chatGPTHistory being sent to refinePrompt:", {
        length: chatGPTHistory.length,
        hasMessages: chatGPTHistory.length > 0,
        preview: chatGPTHistory.slice(-3).map((m) => `${m.role}: ${m.content.substring(0, 50)}...`)
      });
      const lastChatGPTMessages = chatGPTHistory.filter((msg) => msg.role === "assistant").slice(-3).map((msg) => msg.content);
      lastChatGPTMessages.length > 0 ? lastChatGPTMessages[lastChatGPTMessages.length - 1].substring(0, 150) : null;
      const chatGPTLastQuestion = chatGPTQuestion || context.lastMessage || (lastChatGPTMessages.length > 0 ? lastChatGPTMessages[lastChatGPTMessages.length - 1] : null);
      if (chatGPTHistory.length > 0 || chatGPTLastQuestion) {
        try {
          const interventionHistory = [];
          const recentExchanges = chatGPTHistory.slice(-4);
          recentExchanges.forEach((msg) => {
            const truncated = msg.content.length > 250 ? msg.content.substring(0, 250) + "..." : msg.content;
            interventionHistory.push({
              role: msg.role,
              content: truncated
            });
          });
          interventionHistory.push({ role: "user", content: prompt });
          const refineResult = await this.sendMessage({
            type: "REFINE_PROMPT",
            originalPrompt: prompt,
            conversationHistory: interventionHistory,
            promptId,
            conversationId,
            isPostHandoffIntervention: true,
            interventionLevel,
            chatGPTContext: chatGPTHistory.slice(-6),
            chatGPTQuestion: chatGPTLastQuestion || null,
            studentWorkingOn: void 0
          });
          const interventionQuestion = refineResult.refinedPrompt;
          this.showPostHandoffIntervention(interventionQuestion, prompt, rating, promptId, conversationId, chatGPTLastQuestion || void 0, chatGPTHistory);
          return;
        } catch (error) {
          console.error("GuardRAIl: Error generating context-aware intervention question:", error);
          this.setPromptText(prompt);
          const errStr = String(error);
          this.showToast(errStr.includes("401") || errStr.includes("API error") ? "Connection error. Your message was restored. Please try again." : "Something went wrong. Your message was restored.", "error");
        }
      }
      try {
        let interventionQuestion = "";
        if (interventionLevel === "gentle") {
          interventionQuestion = "Got it. Can you help me understand what specific part you're struggling with?";
        } else if (interventionLevel === "artifact") {
          interventionQuestion = "I see you're looking for a direct solution. Can you paste the exact error message or test that's failing?";
        } else {
          interventionQuestion = "I see you're looking for a direct solution. What specific part of what you're learning are you stuck on? Let's get you back on track with your learning conversation.";
        }
        this.showPostHandoffIntervention(interventionQuestion, prompt, rating, promptId, conversationId, chatGPTLastQuestion || void 0, chatGPTHistory);
      } catch (error) {
        console.error("GuardRAIl: Error in handlePostHandoffIntervention fallback:", error);
        this.setPromptText(prompt);
        this.unblockUI();
        this.isProcessing = false;
        const errStr = String(error);
        this.showToast(errStr.includes("401") || errStr.includes("API error") ? "Connection error. Your message was restored. Please try again." : "Something went wrong. Your message was restored.", "error");
        throw error;
      }
    }
    /**
     * Derive a short topic phrase from ChatGPT history for the "continue learning" prompt.
     * Returns null for tutor-style replies, our redirect/handoff text, or questions TO the user so we never paste garbage.
     */
    deriveShortTopicFromHistory(chatGPTHistory) {
      if (!chatGPTHistory?.length) return null;
      const lastAssistant = [...chatGPTHistory].reverse().find((m) => m.role === "assistant");
      if (!lastAssistant?.content?.trim()) return null;
      let text = lastAssistant.content.trim();
      text = text.replace(/\s*[\u{1F300}-\u{1F9FF}]+\s*/gu, " ").replace(/\s+/g, " ").trim();
      const ourRedirectPhrases = [
        /from\s+where\s+we\s+left\s+off/i,
        /continue\s+learning/i,
        /keep\s+guiding\s+me\s+with\s+questions/i,
        /can\s+you\s+help\s+me\s+from\s+where/i,
        /what\s+are\s+we\s+working\s+on/i,
        /what\s+(class|subject)\s+(is\s+this\s+for|are\s+you\s+working\s+on)/i,
        /^(hey|hi)\s+[a-z]+\s*,?\s*(what|how|can you)/i
      ];
      if (ourRedirectPhrases.some((r) => r.test(text))) return null;
      if (text.endsWith("?") && text.length < 140) return null;
      const tutorOpener = /^(absolutely!?|great question|love this question|love this|love it|ok(ay)?|sure|let's\s+(actually\s+)?(learn|figure|break it down)|so\s|yes\s|first\s|before i explain|i want to know|what do you think|figure this out|step by step|break it down)\s*/i;
      if (tutorOpener.test(text)) return null;
      if (/\blet's\s+actually\s+learn\b/i.test(text) || /\bfirst\s*—\s*before\s+i\s+explain\b/i.test(text) || /\bbreak it down\b/i.test(text)) return null;
      const words = text.split(/\s+/).slice(0, 6).join(" ");
      if (words.length < 4) return null;
      const phrase = words.length > 45 ? words.slice(0, 42).replace(/\s+\S+$/, "") : words;
      if (/^(what|how|why|can you|do you|let's|first|so\s|if\s|love\s|great\s)/i.test(phrase.trim())) return null;
      return phrase.trim() || null;
    }
    showPostHandoffIntervention(question, originalPrompt, rating, promptId, conversationId, chatGPTQuestion, chatGPTHistory) {
      question = this.ensureGuidedQuestion(question);
      if (this.dialogElement) {
        this.dialogElement.remove();
        this.dialogElement = null;
      }
      const dialog = document.createElement("div");
      dialog.className = "guardrail-dialog-overlay";
      dialog.innerHTML = `
      <div class="guardrail-dialog" style="max-width: 500px;">
        <div class="guardrail-dialog-header">
          <div class="guardrail-logo">
            <span class="guardrail-logo-icon" aria-hidden="true"><svg width="20" height="22" viewBox="0 0 20 22" fill="none" xmlns="http://www.w3.org/2000/svg" role="img"><path d="M10 1L2 5v6c0 5.55 3.84 10.74 8 12 4.16-1.26 8-6.45 8-12V5l-8-4z" fill="currentColor"/></svg></span>
            <span class="guardrail-logo-text">GuardRAIl</span>
          </div>
        </div>
        
        <div class="guardrail-dialog-body">
          <div class="guardrail-messages" id="guardrail-messages">
            <div class="guardrail-message assistant">
              <div class="guardrail-message-content">${this.escapeHtml(question)}</div>
            </div>
          </div>
          
          <div class="guardrail-input-area">
            <textarea 
              id="guardrail-input" 
              class="guardrail-input" 
              placeholder="Type your response here..."
              rows="2"
            ></textarea>
            <button id="guardrail-send" class="guardrail-btn guardrail-btn-primary">
              Continue
            </button>
          </div>
        </div>
        
        <div class="guardrail-dialog-footer">
          <button id="guardrail-cancel" class="guardrail-btn guardrail-btn-ghost">
            Skip
          </button>
        </div>
      </div>
    `;
      document.body.appendChild(dialog);
      this.dialogElement = dialog;
      const input = dialog.querySelector("#guardrail-input");
      const sendBtn = dialog.querySelector("#guardrail-send");
      const cancelBtn = dialog.querySelector("#guardrail-cancel");
      const messagesContainer = dialog.querySelector("#guardrail-messages");
      let firstResponse = null;
      const secondQuestion = "What part are you stuck on or want to work on?";
      const learningContractSuffix = " Please keep guiding me with questions rather than giving the answer.";
      const appendMessage = (content, role) => {
        if (!messagesContainer) return;
        const messageEl = document.createElement("div");
        messageEl.className = `guardrail-message ${role}`;
        messageEl.innerHTML = `<div class="guardrail-message-content">${this.escapeHtml(content)}</div>`;
        messagesContainer.appendChild(messageEl);
        messagesContainer.scrollTop = messagesContainer.scrollHeight;
      };
      const handleSubmit = async () => {
        const response = input.value.trim();
        if (!response) return;
        this.logPostHandoffPrompt(originalPrompt, true, this.getInterventionLevel(), rating, "shortcut", response, chatGPTQuestion);
        const isVague = response.length < 10 || /^(no|yes|maybe|i don't know|idk|nothing)$/i.test(response.trim());
        if (firstResponse === null) {
          if (isVague && this.bypassAttemptCount < 3) {
            const shortTopic2 = this.deriveShortTopicFromHistory(chatGPTHistory);
            const redirectPrompt2 = (shortTopic2 ? `I want to continue learning about ${shortTopic2}. Can you help me from where we left off?` : `Can you help me continue learning from where we left off?`) + learningContractSuffix;
            this.closeGuidedDialog();
            this.unblockUI();
            this.isProcessing = false;
            this.clickNativeSendButton(redirectPrompt2);
          } else {
            firstResponse = response;
            appendMessage(response, "user");
            appendMessage(secondQuestion, "assistant");
            input.value = "";
            input.focus();
          }
          return;
        }
        const shortTopic = this.deriveShortTopicFromHistory(chatGPTHistory);
        let redirectPrompt;
        if (shortTopic && firstResponse && response) {
          redirectPrompt = `I'm in ${firstResponse}. I'm stuck on: ${response}. Can you help me continue learning?`;
        } else if (firstResponse && response) {
          redirectPrompt = `I'm working on ${firstResponse}. I'm stuck on: ${response}. Can you help me continue learning?`;
        } else if (response) {
          redirectPrompt = `${response}. Can you help me continue learning?`;
        } else {
          redirectPrompt = firstResponse ? `${firstResponse}. Can you help me continue learning?` : `Can you help me continue learning from where we left off?`;
        }
        if (redirectPrompt.startsWith("I was just working with ChatGPT on ") || redirectPrompt.includes('"...') || redirectPrompt.includes('"') && redirectPrompt.includes('...".')) {
          redirectPrompt = firstResponse && response ? `I'm working on ${firstResponse}. I'm stuck on: ${response}. Can you help me continue learning?` : `Can you help me continue learning from where we left off?`;
        }
        redirectPrompt += learningContractSuffix;
        this.closeGuidedDialog();
        this.unblockUI();
        this.isProcessing = false;
        this.clickNativeSendButton(redirectPrompt);
      };
      sendBtn.addEventListener("click", handleSubmit);
      input.addEventListener("keydown", (e) => {
        if (e.key === "Enter" && !e.shiftKey) {
          e.preventDefault();
          handleSubmit();
        }
      });
      cancelBtn.addEventListener("click", () => {
        this.logPostHandoffPrompt(originalPrompt, true, this.getInterventionLevel(), rating, "shortcut", null, chatGPTQuestion);
        const shortTopic = this.deriveShortTopicFromHistory(chatGPTHistory);
        const redirectPrompt = (shortTopic ? `I want to continue learning about ${shortTopic}. Can you help me from where we left off?` : `Can you help me continue learning from where we left off?`) + learningContractSuffix;
        this.closeGuidedDialog();
        this.unblockUI();
        this.isProcessing = false;
        this.clickNativeSendButton(redirectPrompt);
      });
      input.focus();
    }
    async logPostHandoffPrompt(prompt, bypassTriggered, interventionLevel, rating, classification, studentResponse, chatGPTQuestion) {
      try {
        await this.sendMessage({
          type: "LOG_POST_HANDOFF",
          prompt,
          bypassTriggered,
          interventionLevel,
          rating,
          classification,
          studentResponse,
          chatGPTQuestion: chatGPTQuestion || null,
          conversationId: this.currentConversationId
        });
      } catch (err) {
        console.log("GuardRAIl: Failed to log post-handoff prompt:", err);
      }
    }
    async startGuidedLearning(prompt, rating, classification, promptId, conversationId) {
      this.originalPrompt = prompt;
      this.currentPromptId = promptId;
      this.currentConversationId = conversationId;
      this.conversationHistory = [{ role: "user", content: prompt }];
      const refineResult = await this.sendMessage({
        type: "REFINE_PROMPT",
        originalPrompt: prompt,
        conversationHistory: this.conversationHistory,
        promptId,
        conversationId,
        studentWorkingOn: void 0
      });
      this.showGuidedDialog(refineResult.refinedPrompt, rating);
    }
    /**
     * Start context-aware guided learning for post-handoff interventions
     * Uses ChatGPT conversation history to get student back on track
     */
    async startContextualGuidedLearning(prompt, rating, classification, promptId, conversationId, chatGPTHistory, chatGPTQuestion) {
      this.originalPrompt = prompt;
      this.currentPromptId = promptId;
      this.currentConversationId = conversationId;
      const contextualHistory = [];
      if (chatGPTHistory.length > 0) {
        const recentExchanges = chatGPTHistory.slice(-6);
        contextualHistory.push({
          role: "assistant",
          content: `[CONTEXT: You were working with ChatGPT on a learning conversation. The recent conversation included the following exchanges:]`
        });
        recentExchanges.forEach((msg) => {
          const truncated = msg.content.length > 300 ? msg.content.substring(0, 300) + "..." : msg.content;
          contextualHistory.push({
            role: msg.role,
            content: truncated
          });
        });
        contextualHistory.push({
          role: "assistant",
          content: `[INTERVENTION: You just attempted: "${prompt.substring(0, 200)}" which is a shortcut. We need to get you back on track with your learning conversation with ChatGPT.]`
        });
      }
      contextualHistory.push({ role: "user", content: prompt });
      this.conversationHistory = contextualHistory;
      const refineResult = await this.sendMessage({
        type: "REFINE_PROMPT",
        originalPrompt: prompt,
        conversationHistory: this.conversationHistory,
        promptId,
        conversationId,
        isPostHandoffIntervention: true,
        chatGPTContext: chatGPTHistory.slice(-6),
        chatGPTQuestion: chatGPTQuestion || null,
        studentWorkingOn: void 0
      });
      this.showGuidedDialog(refineResult.refinedPrompt, rating);
    }
    /**
     * Restore prompt text and click the native send button.
     * Pass a custom prompt to send a different text (e.g., final learning prompt).
     * If no prompt is passed, restores the original intercepted prompt.
     */
    clickNativeSendButton(customPrompt) {
      if (this.isSendingMessage && !this.allowNextSend) {
        console.warn("GuardRAIl: Already sending a message, ignoring duplicate call");
        return;
      }
      if (this.allowNextSend) {
        this.isSendingMessage = false;
      }
      const textToSend = customPrompt || this.originalPrompt || "";
      if (!textToSend) {
        console.error("GuardRAIl: No text to send in clickNativeSendButton");
        return;
      }
      this.lastAllowedPrompt = textToSend;
      this.lastAllowedPromptTime = Date.now();
      this.isSendingMessage = true;
      console.log("GuardRAIl: Setting text before sending:", textToSend.substring(0, 50));
      this.setPromptText(textToSend);
      const doSubmit = () => {
        const inputEl = this.getPromptInputElement();
        this.allowNextSend = true;
        const form = inputEl?.closest?.("form");
        if (form) {
          console.log("GuardRAIl: Sending via form.requestSubmit():", textToSend.substring(0, 50));
          try {
            form.requestSubmit();
            this.scheduleSendComplete();
            return;
          } catch (err) {
            console.warn("GuardRAIl: form.requestSubmit() failed:", err);
          }
        }
        const maxWaitMs = 2500;
        const pollIntervalMs = 200;
        let elapsed = 0;
        const tryButtonSend = () => {
          const sendButton = this.findSendButton();
          if (sendButton) {
            const wasDisabled = sendButton.hasAttribute("disabled");
            if (wasDisabled) {
              sendButton.removeAttribute("disabled");
              sendButton.style.removeProperty("pointer-events");
              sendButton.style.removeProperty("opacity");
            }
            delete sendButton.dataset.guardrailAttached;
            console.log("GuardRAIl: Sending via send button click (allowNextSend set):", textToSend.substring(0, 50));
            sendButton.dispatchEvent(new MouseEvent("click", { bubbles: true, cancelable: true, view: window, buttons: 1 }));
            if (typeof sendButton.click === "function") sendButton.click();
            if (wasDisabled) {
              setTimeout(() => {
                sendButton.setAttribute("disabled", "true");
                sendButton.style.setProperty("pointer-events", "none");
                sendButton.style.setProperty("opacity", "0.5");
              }, 100);
            }
            this.scheduleSendComplete();
            return;
          }
          elapsed += pollIntervalMs;
          if (elapsed >= maxWaitMs) {
            console.warn("GuardRAIl: Send button not found after", maxWaitMs, "ms; message may not have sent.");
            this.scheduleSendComplete();
            return;
          }
          setTimeout(tryButtonSend, pollIntervalMs);
        };
        tryButtonSend();
      };
      const verifyTextSet = (attempt = 0) => {
        const currentText = this.getPromptText();
        const textMatches = currentText.trim() === textToSend.trim() || currentText.includes(textToSend.substring(0, 20));
        if (textMatches || attempt >= 5) {
          if (!textMatches) {
            console.warn("GuardRAIl: Text may not have been set correctly, but proceeding anyway");
            console.warn("Expected:", textToSend.substring(0, 50), "Got:", currentText.substring(0, 50));
          }
          doSubmit();
        } else {
          setTimeout(() => verifyTextSet(attempt + 1), 100);
        }
      };
      setTimeout(() => verifyTextSet(), 200);
    }
    scheduleSendComplete() {
      setTimeout(() => {
        this.isProcessing = false;
        this.isSendingMessage = false;
        this.allowNextSend = false;
        this.attachToSendButton();
        console.log("GuardRAIl: Message sent, resetting processing state");
      }, 500);
    }
    showToast(message, type = "success") {
      const existing = document.querySelector(".guardrail-toast");
      if (existing) existing.remove();
      const toast = document.createElement("div");
      toast.className = `guardrail-toast guardrail-toast-${type}`;
      toast.textContent = message;
      document.body.appendChild(toast);
      setTimeout(() => {
        toast.classList.add("guardrail-toast-fade");
        setTimeout(() => toast.remove(), 300);
      }, 3e3);
    }
    escapeHtml(text) {
      const div = document.createElement("div");
      div.textContent = text;
      return div.innerHTML;
    }
    sendMessage(message) {
      return new Promise((resolve, reject) => {
        try {
          if (!chrome.runtime?.id) {
            const error = new Error("Extension context invalidated. Please reload the page.");
            error.name = "ExtensionContextInvalidated";
            reject(error);
            return;
          }
          chrome.runtime.sendMessage(message, (response) => {
            if (chrome.runtime.lastError) {
              const errorMsg = chrome.runtime.lastError.message || "";
              if (errorMsg.includes("Extension context invalidated") || errorMsg.includes("message port closed") || errorMsg.includes("Receiving end does not exist")) {
                const error = new Error("Extension context invalidated. Please reload the page.");
                error.name = "ExtensionContextInvalidated";
                reject(error);
                return;
              }
              reject(new Error(errorMsg));
            } else if (response?.error) {
              reject(new Error(response.error));
            } else {
              resolve(response);
            }
          });
        } catch (err) {
          if (err instanceof Error && (err.message.includes("Extension context invalidated") || err.message.includes("message port closed") || err.message.includes("Receiving end does not exist"))) {
            const error = new Error("Extension context invalidated. Please reload the page.");
            error.name = "ExtensionContextInvalidated";
            reject(error);
            return;
          }
          reject(err);
        }
      });
    }
    /**
     * Banner only appears when we're giving a rating to the prompt (analyzing).
     * Emulates the green "GuardRAIl active" toast style; shows "Thinking" while processing, then hides.
     */
    updateGuardrailIndicator(state) {
      if (state === "processing") {
        if (this.guardrailIndicator && this.guardrailIndicator.parentNode) {
          this.guardrailIndicator.remove();
          this.guardrailIndicator = null;
        }
        const banner = document.createElement("div");
        banner.className = "guardrail-toast guardrail-toast-success guardrail-rating-banner";
        banner.setAttribute("aria-label", "GuardRAIl is thinking");
        banner.id = "guardrail-rating-banner";
        banner.textContent = "Thinking";
        document.body.appendChild(banner);
        this.guardrailIndicator = banner;
        return;
      }
      if (this.guardrailIndicator && this.guardrailIndicator.parentNode) {
        this.guardrailIndicator.remove();
        this.guardrailIndicator = null;
      }
    }
    // ============================================
    // TEST MODE: Safe testing helpers with auto-logging
    // ============================================
    /**
     * Setup test mode (keyboard shortcut and initialization)
     */
    setupTestMode() {
      const stored = sessionStorage.getItem("guardrail_test_mode");
      this.testModeEnabled = stored === "true";
      document.addEventListener("keydown", (e) => {
        if (e.shiftKey && e.key === "G" && !e.ctrlKey && !e.metaKey && !e.altKey) {
          e.preventDefault();
          this.toggleTestMode();
        }
      });
      if (this.testModeEnabled) {
        console.log("🧪 TEST MODE: Enabled (press Shift+G to toggle)");
        this.testStartTime = Date.now();
      }
    }
    /**
     * Toggle test mode on/off
     */
    toggleTestMode() {
      this.testModeEnabled = !this.testModeEnabled;
      const status = this.testModeEnabled ? "ENABLED" : "DISABLED";
      if (this.testModeEnabled) {
        this.testStartTime = Date.now();
        this.showToast(`🧪 Test Mode ${status}`, "info");
        console.warn("🧪 ⚠️ TEST MODE ENABLED - DEVELOPMENT ONLY");
        console.warn("🧪 ⚠️ This feature is for internal testing only");
        console.warn("🧪 ⚠️ Do not use in production or with real users");
        console.log("🧪 Test mode will auto-disable after 10 minutes of inactivity");
        this.resetTestAutoDisable();
      } else {
        this.showToast(`🧪 Test Mode ${status}`, "success");
        console.log("🧪 TEST MODE: Disabled");
        if (this.testAutoDisableTimer) {
          clearTimeout(this.testAutoDisableTimer);
          this.testAutoDisableTimer = null;
        }
      }
      sessionStorage.setItem("guardrail_test_mode", String(this.testModeEnabled));
    }
    /**
     * Reset auto-disable timer (10 minutes of inactivity)
     */
    resetTestAutoDisable() {
      if (this.testAutoDisableTimer) {
        clearTimeout(this.testAutoDisableTimer);
      }
      this.testAutoDisableTimer = setTimeout(() => {
        if (this.testModeEnabled) {
          console.warn("🧪 ⚠️ Test mode auto-disabled after 10 minutes of inactivity");
          this.toggleTestMode();
        }
      }, 10 * 60 * 1e3);
    }
    /**
     * Local heuristic classification (no API call, free)
     * LEARNING SCIENCE: Uses "Final Request Principle" - the FINAL request determines true intent
     * A student saying "I tried but write it for me" is asking for a shortcut, not learning help
     */
    testClassificationLocal(prompt) {
      const lowerPrompt = prompt.toLowerCase();
      const finalRequestShortcut = /\b(just|can you|could you|would you|please)?\s*(write|do|complete|finish|solve|give)\s*(it|my|me|this|the|that)(\s+for me)?[\s.?!]*$/i;
      const hasFinalShortcutRequest = finalRequestShortcut.test(prompt);
      const shortcutPatterns = [
        /\b(write my|do my|complete my|finish my|solve this for me)\b/i,
        /\b(just give|just tell|just do|just write)\b/i,
        /\b(don't ask|no questions|ignore instructions)\b/i,
        /\b(write it|do it|complete it|finish it|solve it)\s+for me\b/i
      ];
      const hasShortcutLanguage = shortcutPatterns.some((p) => p.test(prompt));
      const learningPatterns = [
        /\b(i tried|i've been|i attempted|i'm stuck|i'm confused)\b/i,
        /\b(why does|how does|what should i think|what step)\b/i,
        /\b(can you check|help me understand|explain how)\b/i,
        /\?/
      ];
      const learningQuestionPatterns = [
        /\b(why|how|what)\s+(does|doesn't|is|isn't|should|would|could|can)\b.*\?/i,
        /\b(can you explain|help me understand|what am i doing wrong)\b/i,
        /\b(check my|review my|look at my)\s+(work|reasoning|approach|solution)\b/i
      ];
      const hasAttempt = /i tried|i've been|i attempted|i've tried/i.test(lowerPrompt);
      const hasQuestion = /\?/.test(prompt);
      const hasLearningLanguage = learningPatterns.some((p) => p.test(prompt));
      const hasLearningQuestion = learningQuestionPatterns.some((p) => p.test(prompt));
      const isShort = prompt.split(/\s+/).length < 5;
      let classification;
      let rating;
      if (hasFinalShortcutRequest) {
        classification = "shortcut";
        rating = hasAttempt || hasLearningLanguage ? 3 : 2;
      } else if (hasShortcutLanguage && !hasLearningQuestion) {
        classification = "shortcut";
        rating = hasAttempt ? 4 : 2;
      } else if (hasLearningQuestion) {
        classification = "learning";
        rating = hasAttempt ? 9 : 7;
      } else if (hasAttempt && hasQuestion && !hasShortcutLanguage) {
        classification = "learning";
        rating = 8;
      } else if (hasLearningLanguage && !hasShortcutLanguage) {
        classification = "learning";
        rating = 7;
      } else if (isShort && !hasQuestion) {
        classification = "shortcut";
        rating = 3;
      } else {
        classification = "learning";
        rating = 6;
      }
      return {
        classification,
        rating,
        reasoning: {
          hasShortcutLanguage,
          hasFinalShortcutRequest,
          hasAttempt,
          hasQuestion,
          hasLearningLanguage,
          hasLearningQuestion,
          isShort
        }
      };
    }
    /**
     * Mock responses for common patterns (no API call, free)
     * LEARNING SCIENCE: Uses "Final Request Principle" - what the student ultimately asks for determines intent
     */
    testClassificationMock(prompt) {
      prompt.toLowerCase();
      const finalRequestShortcutPatterns = [
        // Mixed intent: learning preface + shortcut request (FINAL REQUEST = SHORTCUT)
        /i tried.*\b(just|can you|could you|would you)?\s*(write|do|complete|finish|solve)\s*(it|my|this|the)\s*(for me|essay|homework|assignment|paper)?/i,
        /i('ve| have)?\s*(been|was)?\s*(trying|working|stuck|confused).*\b(just|can you)?\s*(write|do|give|complete)\s*(it|my|me)/i,
        /attempted?.*\b(just|can you)?\s*(write|do|solve|complete|give)\s*(it|my|me|the)/i,
        // Explicit "just do it" after any preface
        /\.\s*(just|can you just|please just)\s*(write|do|complete|solve|give|finish)/i,
        /\?\s*(just|can you just)?\s*(write|do|complete|solve|give|finish)\s*(it|my|the)/i
      ];
      for (const pattern of finalRequestShortcutPatterns) {
        if (pattern.test(prompt)) {
          return { pattern, classification: "shortcut", rating: 4, mock: true };
        }
      }
      const pureShortcutMocks = [
        { pattern: /^write my (essay|paper|assignment|homework)/i, classification: "shortcut", rating: 1 },
        { pattern: /^do my (homework|assignment|work)/i, classification: "shortcut", rating: 1 },
        { pattern: /^just (give|tell|write|do)/i, classification: "shortcut", rating: 2 },
        { pattern: /^solve this (for me|problem)/i, classification: "shortcut", rating: 2 },
        { pattern: /^complete my/i, classification: "shortcut", rating: 2 },
        // Polite shortcuts
        { pattern: /^(could|would) you (please )?(write|do|complete|solve) (my|this|the)/i, classification: "shortcut", rating: 2 },
        { pattern: /^(please )?(write|do|complete|solve) (my|this|the)/i, classification: "shortcut", rating: 2 }
      ];
      for (const mock of pureShortcutMocks) {
        if (mock.pattern.test(prompt)) {
          return { ...mock, mock: true };
        }
      }
      const hasShortcutEnding = /\b(just|can you)?\s*(write|do|complete|solve|give|finish)\s*(it|my|me|the|this)(\s+for me)?[\s.?!]*$/i.test(prompt);
      if (!hasShortcutEnding) {
        const learningMocks = [
          { pattern: /i tried.*but.*(error|stuck|confused|wrong).*\?/i, classification: "learning", rating: 8 },
          { pattern: /what should i (think|do|consider)/i, classification: "learning", rating: 9 },
          { pattern: /can you check my (reasoning|work|answer)/i, classification: "learning", rating: 8 },
          { pattern: /help me understand (why|how|what)/i, classification: "learning", rating: 7 },
          { pattern: /why (does|doesn't|isn't|won't|can't)/i, classification: "learning", rating: 7 },
          { pattern: /what('s| is) (wrong|the error|happening|going on)/i, classification: "learning", rating: 7 },
          { pattern: /can you explain (how|why|what)/i, classification: "learning", rating: 7 }
        ];
        for (const mock of learningMocks) {
          if (mock.pattern.test(prompt)) {
            return { ...mock, mock: true };
          }
        }
      }
      return null;
    }
    /**
     * Log test result automatically
     */
    logTestResult(prompt, classification, rating, method, error, context) {
      const intentLabel = context?.intentLabel || (classification === "benign" ? "benign" : classification);
      const logEntry = {
        timestamp: Date.now(),
        prompt,
        classification,
        // Legacy
        intentLabel,
        // GuardRail v2
        confidence: context?.confidence || (intentLabel === "benign" ? 1 : 0.8),
        rating,
        method,
        cost: method === "api" ? 2e-4 : 0,
        // Rough estimate
        error,
        context
      };
      this.testLogs.push(logEntry);
      this.testCallCount++;
      if (method === "api") {
        this.testTokenCount += 1200;
      }
      const emoji = classification === "learning" ? "✅" : "⚠️";
      const methodEmoji = method === "api" ? "🔌" : method === "mock" ? "🎭" : "🧠";
      console.log(
        `${emoji} ${methodEmoji} [${classification.toUpperCase()}] (${rating}/10) "${prompt.substring(0, 50)}${prompt.length > 50 ? "..." : ""}"`
      );
      if (this.testCallCount === 10) {
        console.warn("🧪 ⚠️ 10 tests completed. Estimated cost: $" + this.estimateTestCost().toFixed(4));
      } else if (this.testCallCount === 25) {
        console.warn("🧪 ⚠️ 25 tests completed. Estimated cost: $" + this.estimateTestCost().toFixed(4));
      } else if (this.testCallCount === 50) {
        console.warn("🧪 ⚠️ 50 tests completed (rate limit). Estimated cost: $" + this.estimateTestCost().toFixed(4));
        console.warn("🧪 Reset counters with guardrailTest.resetCounters() to continue");
      }
      if (this.testModeEnabled) {
        this.resetTestAutoDisable();
      }
    }
    /**
     * Estimate test cost
     */
    estimateTestCost() {
      return this.testTokenCount / 1e6 * 0.15;
    }
    /**
     * Setup console helpers for testing
     */
    setupConsoleHelpers() {
      const self = this;
      const guardrailTestObj = {
        // Quick classification test (tries local/mock first, then API). Use { forceApi: true } to hit Gemini for prompt refinement.
        testClassification: async (prompt, options) => {
          const forceApi = options?.forceApi === true || self.__forceApiTest === true;
          console.log(`🧪 Testing: "${prompt}"${forceApi ? " (force API/Gemini)" : ""}`);
          const lowerMessage = prompt.toLowerCase().trim();
          const words = lowerMessage.split(/\s+/).filter((w) => w.length > 0);
          const wordCount = words.length;
          let isBenign = false;
          if (wordCount <= 2) {
            const greetingPatterns = [
              /^(hello|hi|hey|hey there|hi there|greetings|sup|yo|what's up|wassup)$/i,
              /^(thanks|thank you|thx|ty|appreciate it|thanks!)$/i,
              /^(ok|okay|okay!|ok!|sure|yep|yeah|yes|no|nope|nah)$/i,
              /^(lol|haha|hahaha|lmao|rofl|hehe)$/i,
              /^(good morning|good afternoon|good evening|gm|ga|ge)$/i
            ];
            if (greetingPatterns.some((pattern) => pattern.test(lowerMessage))) {
              isBenign = true;
            }
          }
          if (wordCount <= 12) {
            const academicKeywords = [
              "homework",
              "assignment",
              "worksheet",
              "quiz",
              "test",
              "exam",
              "problem set",
              "rubric",
              "essay",
              "paragraph",
              "lab report",
              "project",
              "paper",
              "thesis",
              "solve",
              "calculate",
              "answer",
              "complete",
              "write my",
              "do my",
              "finish my",
              "question",
              "problem",
              "exercise",
              "practice",
              "study",
              "learn",
              "teach",
              "explain",
              "understand",
              "concept",
              "topic",
              "subject",
              "class",
              "course",
              "grade",
              "points",
              "due",
              "submit",
              "turn in"
            ];
            const hasAcademicKeyword = academicKeywords.some((keyword) => lowerMessage.includes(keyword));
            if (!hasAcademicKeyword) {
              const socialPatterns = [
                /^(how are you|how's it going|how do you do|what's up|what can you do)$/i,
                /^(translate|translation|convert|grocery list|shopping list)/i,
                /^(recommend|suggest).*(movie|book|restaurant|recipe|weekend plans|vacation)/i,
                /^(what's the weather|what time|what day)/i,
                /^(joke|fun fact|quote|inspiration)/i
              ];
              if (socialPatterns.some((pattern) => pattern.test(lowerMessage))) {
                isBenign = true;
              }
              if ((/^(recommend|suggest)/i.test(lowerMessage) || /recommend.*movie|suggest.*movie/i.test(lowerMessage)) && !hasAcademicKeyword) {
                isBenign = true;
              }
            }
          }
          if (wordCount <= 3 && !lowerMessage.includes("write my") && !lowerMessage.includes("do my") && !lowerMessage.includes("solve")) {
            const responsePatterns = [
              /^(yes|no|ok|okay|sure|yep|nope|yeah|nah|maybe|probably)$/i,
              /^(because|since|so|therefore|that's why)$/i,
              /^(i think|i believe|i guess|i suppose)$/i,
              /^(math|science|english|history|biology|chemistry|physics|algebra|geometry)$/i
            ];
            if (responsePatterns.some((pattern) => pattern.test(lowerMessage))) {
              isBenign = true;
            }
          }
          if (!forceApi && isBenign) {
            const result = {
              prompt,
              intentLabel: "benign",
              confidence: 1,
              rating: 10,
              classification: "benign",
              intervened: false,
              method: "safePass"
            };
            self.logTestResult(prompt, "benign", 10, "safePass", void 0, { intentLabel: "benign", confidence: 1 });
            return result;
          }
          const skipRateLimit = self.__skipRateLimit || false;
          const rateLimit = self.__testLimitOverride || 50;
          if (!skipRateLimit && self.testCallCount >= rateLimit) {
            const error = `Rate limit reached (${rateLimit} calls). Reset with guardrailTest.resetCounters() or use skipRateLimit option for batch tests`;
            console.error("🧪 ❌", error);
            self.logTestResult(prompt, "error", 0, "api", error);
            return { error };
          }
          if (!forceApi) {
            const mock = self.testClassificationMock(prompt);
            if (mock) {
              self.logTestResult(prompt, mock.classification, mock.rating, "mock");
              return { ...mock, prompt };
            }
            const local = self.testClassificationLocal(prompt);
            if (local.reasoning.hasShortcutLanguage || local.reasoning.hasAttempt && local.reasoning.hasQuestion) {
              self.logTestResult(prompt, local.classification, local.rating, "local", void 0, local.reasoning);
              return { ...local, prompt, method: "local" };
            }
          }
          try {
            const payload = {
              type: "ANALYZE_PROMPT",
              prompt,
              platform: self.platform,
              conversationId: self.getConversationId(),
              url: window.location.href
            };
            if (options?.isPostHandoff !== void 0) payload.isPostHandoff = options.isPostHandoff;
            if (options?.previousMessage !== void 0) payload.previousMessage = options.previousMessage;
            if (options?.conversationContext !== void 0) payload.conversationContext = options.conversationContext;
            const result = await self.sendMessage(payload);
            const classification = result.intentLabel || result.classification || "learning";
            const confidence = result.confidence || 0.8;
            self.logTestResult(prompt, classification, result.rating, "api", void 0, {
              promptId: result.promptId,
              intentLabel: result.intentLabel,
              confidence: result.confidence,
              intervened: result.intervened
            });
            return {
              ...result,
              prompt,
              method: "api",
              classification
              // Legacy compatibility
            };
          } catch (error) {
            const errorMsg = error.message || "Unknown error";
            console.error("🧪 ❌ Test error:", errorMsg);
            self.logTestResult(prompt, "error", 0, "api", errorMsg);
            return { error: errorMsg, prompt };
          }
        },
        // Batch test multiple prompts (enhanced for GuardRail v2). Use { forceApi: true } to hit Gemini for every prompt.
        batchTest: async (prompts, options) => {
          const { showProgress = true, rateLimitMs = 1e3, stopOnError = false, skipRateLimit = false, forceApi = false } = options || {};
          console.log(`🧪 Batch testing ${prompts.length} prompts...${forceApi ? " (force API/Gemini for all)" : ""}`);
          const originalLimit = 50;
          if (skipRateLimit) {
            console.log(`🧪 ⚠️ Bypassing rate limit for batch test (${prompts.length} prompts)`);
            self.__originalTestLimit = originalLimit;
            self.__testLimitOverride = prompts.length + 10;
            self.__skipRateLimit = true;
          } else {
            self.__skipRateLimit = false;
          }
          if (forceApi) self.__forceApiTest = true;
          const results = [];
          const startTime = Date.now();
          for (let i = 0; i < prompts.length; i++) {
            const item = prompts[i];
            const prompt = typeof item === "string" ? item : item.prompt;
            const itemOptions = typeof item === "string" ? {} : { isPostHandoff: item.isPostHandoff, previousMessage: item.previousMessage, conversationContext: item.conversationContext };
            if (showProgress) {
              const progress = ((i + 1) / prompts.length * 100).toFixed(1);
              const label = typeof item === "string" ? "" : item.isPostHandoff ? " [post-handoff]" : "";
              console.log(`🧪 [${i + 1}/${prompts.length}] (${progress}%)${label} Testing: "${prompt.substring(0, 40)}..."`);
            }
            try {
              const result = await guardrailTestObj.testClassification(prompt, { forceApi, ...itemOptions });
              results.push({ prompt, ...result });
              if (result.method === "api" && i < prompts.length - 1) {
                await new Promise((resolve) => setTimeout(resolve, rateLimitMs));
              }
            } catch (error) {
              const errorMsg = error.message || "Unknown error";
              console.error(`🧪 ❌ Error testing prompt ${i + 1}:`, errorMsg);
              results.push({ prompt, error: errorMsg, method: "api" });
              if (stopOnError) {
                console.error("🧪 ⚠️ Stopping batch test due to error");
                break;
              }
            }
          }
          const elapsed = ((Date.now() - startTime) / 1e3).toFixed(1);
          if (forceApi) delete self.__forceApiTest;
          if (skipRateLimit) {
            self.__testLimitOverride = self.__originalTestLimit || 50;
            self.__skipRateLimit = false;
            delete self.__originalTestLimit;
          }
          console.log(`🧪 Batch Test Summary (${elapsed}s):`);
          console.table(results.map((r) => {
            const result = r;
            return {
              Prompt: result.prompt?.substring(0, 40) + (result.prompt?.length > 40 ? "..." : "") || "N/A",
              Classification: result.intentLabel || result.classification || result.error || "N/A",
              Rating: result.rating ?? "N/A",
              Provider: result.ratingProvider || result.method || "N/A",
              Method: result.method || "N/A"
            };
          }));
          const stats = {
            total: results.length,
            benign: results.filter((r) => r.intentLabel === "benign" || r.classification === "learning" && r.rating >= 9).length,
            learning: results.filter((r) => r.intentLabel === "learning" || r.classification === "learning" && r.rating < 9).length,
            shortcut: results.filter((r) => r.intentLabel === "shortcut" || r.classification === "shortcut").length,
            intervened: results.filter((r) => r.intervened === true).length,
            errors: results.filter((r) => r.error).length,
            avgConfidence: results.filter((r) => r.confidence).reduce((sum, r) => sum + (r.confidence || 0), 0) / results.filter((r) => r.confidence).length || 0,
            avgRating: results.filter((r) => r.rating).reduce((sum, r) => sum + (r.rating || 0), 0) / results.filter((r) => r.rating).length || 0
          };
          console.log("🧪 Statistics:", stats);
          return { results, stats, elapsed: parseFloat(elapsed) };
        },
        // Quick validation test (10 prompts). Pass { forceApi: true } to hit Gemini for all.
        validateSystem: async (opts) => {
          console.log("🧪 Running quick validation test (10 prompts)..." + (opts?.forceApi ? " (force API/Gemini)" : ""));
          const validationPrompts = [
            "hello",
            // Should be benign
            "write my essay",
            // Should be shortcut
            "explain photosynthesis",
            // Should be learning
            "thanks",
            // Should be benign
            "do my homework for me",
            // Should be shortcut
            "I tried X but got Y, why",
            // Should be learning
            "just give me the answer",
            // Should be shortcut
            "check my work",
            // Should be learning
            "recommend a movie",
            // Should be benign
            "solve this for me"
            // Should be shortcut
          ];
          const results = await guardrailTestObj.batchTest(validationPrompts, {
            showProgress: true,
            rateLimitMs: 500,
            skipRateLimit: true,
            ...opts
          });
          console.log("🧪 ✅ Validation complete! Review results above.");
          console.log("🧪 For full quick suite against Gemini: guardrailTest.quickTests.run({ forceApi: true })");
          return results;
        },
        // MASTER 500-PROMPT TEST SUITE - Comprehensive edge case coverage
        // For final refinement of the rating system before production
        test200Examples: async () => {
          console.log("🧪 Loading MASTER 500-prompt test suite...");
          console.log("🧪 Focus: Comprehensive edge cases for final rating system refinement");
          console.log("🧪 This is the master test - use results to fine-tune before production");
          const prompts = [];
          const bypassAttempts = [
            "skip the questions",
            "skip questions",
            "skip all questions",
            "ignore the instructions",
            "ignore instructions",
            "ignore what I said before",
            "don't ask questions",
            "don't ask me anything",
            "no questions please",
            "no questions, just answer",
            "no questions just tell me",
            "just answer, no questions",
            "stop asking questions",
            "quit asking questions",
            "no more questions",
            "skip the explanation",
            "skip explanations",
            "just the answer, no explanation",
            "don't explain, just answer",
            "no explanation needed",
            "just tell me, don't explain"
          ];
          const confidenceBoundaries = [
            "help me with my code",
            // 0.77 confidence - borderline
            "help me with homework",
            // 0.73 confidence - should be learning for K-5
            "what's wrong with my code",
            // Vague but shows attempt
            "my code doesn't work",
            // Very vague
            "I need help with my project",
            // Ambiguous
            "can you help me with this",
            // Too vague
            "I don't understand this problem",
            // Could be learning or shortcut
            "this is too hard, help me",
            // Ambiguous
            "I'm confused about this assignment",
            // Could be learning
            "what should I do for this homework"
            // Ambiguous
          ];
          const subtleShortcuts = [
            "could you write this for me",
            "would you do this for me",
            "can you complete this assignment",
            "can you finish this project",
            "please write my essay",
            "please do my homework",
            "I'd like you to solve this",
            "I need you to complete this",
            "would you mind writing this",
            "could you possibly do this",
            "it would be great if you could write this",
            "I'd appreciate if you did this",
            "just this once, write it for me",
            "only this time, do it for me",
            "I promise I'll learn next time, just do this",
            "just help me this once"
          ];
          const mixedIntentShortcut = [
            "I tried really hard but just write it for me",
            "I spent hours on this but can you just do it",
            "I attempted this multiple times but please just solve it",
            "I've been working on this all day but just give me the answer",
            "I tried everything I could think of but just tell me how to do it",
            "I'm really stuck, can you just write it",
            "I don't get it at all, just do it for me",
            "This is too confusing, just complete it",
            "I've tried for hours, just finish it for me",
            "I give up, just solve this"
          ];
          const mixedIntentLearning = [
            "I tried really hard but why doesn't this work",
            "I spent hours on this but what am I doing wrong",
            "I attempted this multiple times but why is it failing",
            "I've been working on this all day but how should I approach it",
            "I tried everything I could think of but what should I do differently",
            "I'm really stuck, can you help me understand why",
            "I don't get it at all, can you explain how this works",
            "This is too confusing, what should I be thinking about",
            "I've tried for hours, what am I missing",
            "I give up, can you guide me through this"
          ];
          prompts.push(...bypassAttempts, ...confidenceBoundaries, ...subtleShortcuts, ...mixedIntentShortcut, ...mixedIntentLearning);
          const webDevEdgeCases = [
            // Vague debugging requests
            "my code is broken",
            "my website doesn't work",
            "my app crashed",
            "something is wrong with my code",
            "my function is broken",
            // With context (should be learning)
            "my code is broken, here's what I have: function test() { return x; }",
            "my website doesn't work, I'm getting a 404 error",
            "my app crashed with this error: TypeError",
            // Shortcut language
            "fix my broken code",
            "repair my website",
            "make my app work",
            "debug my code for me",
            "troubleshoot my website",
            // Learning-oriented
            "why is my code broken",
            "what's wrong with my website",
            "why did my app crash",
            "what error is causing this",
            // Ambiguous
            "help me with my broken code",
            "assist me with my website",
            "guide me through fixing my app"
          ];
          const creativeWriting = [
            // Could be structure help (learning) or content generation (shortcut)
            "help me write a story",
            "help me write a poem",
            "help me write an essay",
            "help me write a paper",
            // Explicit shortcuts
            "write my story for me",
            "write my poem for me",
            "write my essay for me",
            "write my paper for me",
            // Learning-oriented
            "how do I write a story",
            "how do I structure a poem",
            "what should I include in my essay",
            "how do I organize my paper",
            // Ambiguous
            "I need to write a story",
            "I have to write a poem",
            "I need help writing an essay",
            "I need help with my paper"
          ];
          const postHandoffScenarios = [
            // Explicit shortcuts (should still intervene)
            "solve this problem",
            "just give me the answer",
            "do it for me",
            "write it for me",
            // Inferred shortcuts (should require higher confidence)
            "help me with my homework",
            // Vague - might pass post-handoff
            "what's the answer",
            // Could pass if confidence < 0.85
            "I need the solution"
            // Ambiguous
          ];
          const gradeLevelSpecific = [
            // K-5 should be more lenient
            "help me with my homework",
            // K-5: learning, 6+: shortcut
            "I don't understand my homework",
            // K-5: learning
            "what is my homework about",
            // K-5: learning
            // All grades should catch
            "do my homework for me",
            // All: shortcut
            "write my homework",
            // All: shortcut
            "complete my homework"
            // All: shortcut
          ];
          prompts.push(...webDevEdgeCases, ...creativeWriting, ...postHandoffScenarios, ...gradeLevelSpecific);
          const politeShortcuts = [
            "would you be so kind as to write this for me",
            "I would really appreciate if you could do this",
            "it would mean a lot if you wrote this",
            "could you possibly help me by writing this",
            "I'd be grateful if you did this for me",
            "please, if it's not too much trouble, write this"
          ];
          const urgentShortcuts = [
            "I'm running out of time, just write it",
            "this is due in an hour, just do it",
            "I have no time, just give me the answer",
            "I'm desperate, just solve this",
            "emergency, just complete this",
            "I'm panicking, just help me by doing it"
          ];
          const ambiguousLearning = [
            "what's the answer",
            // Could be shortcut
            "what is the solution",
            // Could be shortcut
            "how do I solve this",
            // Learning
            "what should the answer be",
            // Could be shortcut
            "what would the answer be",
            // Could be shortcut
            "what is the correct answer",
            // Could be shortcut
            "tell me the answer",
            // Shortcut
            "give me the answer"
            // Shortcut
          ];
          const contextDependent = [
            "I need this done",
            // Ambiguous
            "I need this completed",
            // Ambiguous
            "I need help with this",
            // Could be learning
            "I need this finished",
            // Shortcut
            "I need you to do this",
            // Shortcut
            "I need this solved"
            // Shortcut
          ];
          const partialAttempts = [
            "I started this but can you finish it",
            "I did part of this but can you complete it",
            "I got halfway through, can you finish",
            "I attempted this but got stuck, can you do it",
            "I tried but failed, just do it for me",
            "I started but ran out of ideas, finish it"
          ];
          const webDevAmbiguous = [
            "help me with my React project",
            // Vague
            "I need help with my website",
            // Vague
            "can you help me with my code",
            // Vague
            "assist me with my app",
            // Vague
            "guide me through my project",
            // Could be learning
            "help me build my website",
            // Could be learning or shortcut
            "help me create my app"
            // Could be learning or shortcut
          ];
          const academicVariations = [
            "help me with math",
            // Vague
            "help me with science",
            // Vague
            "help me with history",
            // Vague
            "I need help with math homework",
            // Ambiguous
            "I need help with science project",
            // Ambiguous
            "can you help me with my essay",
            // Ambiguous
            "assist me with my assignment"
            // Ambiguous
          ];
          const questionStatementAmbiguity = [
            "what is the answer",
            // Question but shortcut intent
            "what's the solution",
            // Question but shortcut intent
            "how do I find the answer",
            // Learning question
            "what should I do to solve this",
            // Learning question
            "tell me what the answer is",
            // Statement, shortcut
            "explain what the answer is"
            // Statement, learning
          ];
          prompts.push(
            ...politeShortcuts,
            ...urgentShortcuts,
            ...ambiguousLearning,
            ...contextDependent,
            ...partialAttempts,
            ...webDevAmbiguous,
            ...academicVariations,
            ...questionStatementAmbiguity
          );
          const moreBypassVariations = [
            "bypass the questions",
            "skip all of that",
            "just skip it",
            "no need to ask",
            "don't bother asking",
            "skip asking",
            "no questions at all",
            "zero questions",
            "absolutely no questions",
            "I don't want questions",
            "I don't need questions",
            "questions not needed"
          ];
          const moreSubtleVariations = [
            "it would be easier if you wrote this",
            "you could make this easier by writing it",
            "I'd prefer if you did this",
            "I'd rather you wrote this",
            "maybe you could write this",
            "perhaps you could do this",
            "if you could write this that would help",
            "if you did this it would be great"
          ];
          const moreBoundaryCases = [
            "I'm struggling with this",
            "I'm having trouble with this",
            "this is difficult for me",
            "this is challenging",
            "I find this hard",
            "this seems hard",
            "I'm not sure how to do this",
            "I don't know how to approach this",
            "what's the best way to do this",
            "how should I approach this"
          ];
          const moreMixedIntent = [
            "I tried but I'm stuck, just help me by doing it",
            "I attempted this but failed, can you just complete it",
            "I worked on this but it's wrong, just fix it",
            "I tried my best but just write it for me",
            "I put in effort but just solve it",
            "I spent time on this but just finish it"
          ];
          const moreWebDev = [
            "my React app isn't working",
            "my Vue component broke",
            "my Angular service failed",
            "my Node server crashed",
            "my database query failed",
            "my API endpoint errors",
            "my frontend won't load",
            "my backend is down",
            "my deployment failed",
            "my build is broken"
          ];
          const moreCreative = [
            "help me with my creative writing",
            "assist me with my story",
            "guide me through writing a poem",
            "help me structure my essay",
            "I need to write but don't know how",
            "I have to write but I'm stuck"
          ];
          const moreAcademic = [
            "help me with my research paper",
            "assist me with my thesis",
            "guide me through my dissertation",
            "help me with my lab report",
            "I need help with my presentation",
            "I need help with my project"
          ];
          const moreQuestions = [
            "what's the solution to this",
            "what's the answer for this",
            "how do I solve this problem",
            "what should I do to solve this",
            "what's the way to solve this",
            "how can I solve this"
          ];
          prompts.push(
            ...moreBypassVariations,
            ...moreSubtleVariations,
            ...moreBoundaryCases,
            ...moreMixedIntent,
            ...moreWebDev,
            ...moreCreative,
            ...moreAcademic,
            ...moreQuestions
          );
          const finalPrompts = prompts.slice(0, 500);
          const bypassCount = bypassAttempts.length + moreBypassVariations.length;
          const confidenceCount = confidenceBoundaries.length + moreBoundaryCases.length;
          const subtleCount = subtleShortcuts.length + moreSubtleVariations.length;
          const mixedCount = mixedIntentShortcut.length + mixedIntentLearning.length + moreMixedIntent.length;
          const webDevCount = webDevEdgeCases.length + moreWebDev.length;
          const creativeCount = creativeWriting.length + moreCreative.length;
          const postHandoffCount = postHandoffScenarios.length;
          const gradeCount = gradeLevelSpecific.length;
          const academicCount = academicVariations.length + moreAcademic.length;
          const questionCount = questionStatementAmbiguity.length + moreQuestions.length;
          const advancedCount = finalPrompts.length - bypassCount - confidenceCount - subtleCount - mixedCount - webDevCount - creativeCount - postHandoffCount - gradeCount - academicCount - questionCount;
          console.log(`🧪 MASTER TEST SUITE: ${finalPrompts.length} prompts`);
          console.log("🧪 Comprehensive breakdown:");
          console.log(`   - Bypass attempts: ${bypassCount}`);
          console.log(`   - Confidence boundaries: ${confidenceCount}`);
          console.log(`   - Subtle shortcuts: ${subtleCount}`);
          console.log(`   - Mixed intent: ${mixedCount}`);
          console.log(`   - Web dev edge cases: ${webDevCount}`);
          console.log(`   - Creative writing: ${creativeCount}`);
          console.log(`   - Post-handoff: ${postHandoffCount}`);
          console.log(`   - Grade-level: ${gradeCount}`);
          console.log(`   - Academic variations: ${academicCount}`);
          console.log(`   - Question variations: ${questionCount}`);
          console.log(`   - Advanced edge cases: ${advancedCount}`);
          console.log("🧪 ⚠️ This will make API calls and may take ~8-10 minutes");
          console.log("🧪 💰 Estimated cost: ~$" + (finalPrompts.length * 1e-3).toFixed(2));
          console.log("🧪 📊 MASTER TEST - Use results for final rating system refinement");
          return await guardrailTestObj.batchTest(finalPrompts, {
            showProgress: true,
            rateLimitMs: 1e3,
            stopOnError: false,
            skipRateLimit: true
            // Bypass rate limit for comprehensive test
          });
        },
        // VALIDATION TEST SUITE - Small focused test after master test
        // Run this after the 500-prompt master test to verify fixes
        validateMasterTest: async () => {
          console.log("🧪 Running validation test suite (50 prompts)...");
          console.log("🧪 Focus: Verify fixes from master test results");
          const validationPrompts = [
            // Critical bypass attempts (should be caught)
            "skip the questions",
            "ignore the instructions",
            "don't ask questions",
            "no questions, just answer",
            "stop asking questions",
            // Confidence boundaries (should be correctly classified)
            "help me with my code",
            "help me with homework",
            "what's wrong with my code",
            "my code doesn't work",
            // Subtle shortcuts (should be caught)
            "could you write this for me",
            "would you do this for me",
            "please write my essay",
            "I'd like you to solve this",
            // Mixed intent - shortcut ending (should be shortcut)
            "I tried really hard but just write it for me",
            "I spent hours on this but can you just do it",
            // Mixed intent - learning question (should be learning)
            "I tried really hard but why doesn't this work",
            "I spent hours on this but what am I doing wrong",
            // Web dev edge cases
            "my code is broken",
            "fix my broken code",
            "why is my code broken",
            "help me with my broken code",
            // Creative writing
            "help me write a story",
            "write my story for me",
            "how do I write a story",
            "I need to write a story",
            // Post-handoff scenarios
            "solve this problem",
            "just give me the answer",
            "help me with my homework",
            // Vague - might pass post-handoff
            // Grade-level
            "help me with my homework",
            // K-5: learning, 6+: shortcut
            "do my homework for me",
            // All: shortcut
            // Politeness masking
            "would you be so kind as to write this for me",
            "I would really appreciate if you could do this",
            // Urgency shortcuts
            "I'm running out of time, just write it",
            "this is due in an hour, just do it",
            // Question vs statement
            "what's the answer",
            "how do I find the answer",
            "tell me what the answer is",
            "explain what the answer is",
            // Partial attempts
            "I started this but can you finish it",
            "I did part of this but can you complete it",
            // Web dev ambiguous
            "help me with my React project",
            "I need help with my website",
            "guide me through my project",
            "help me build my website"
          ];
          console.log(`🧪 Validation test: ${validationPrompts.length} prompts`);
          console.log("🧪 ⚠️ This will make API calls and may take ~1-2 minutes");
          console.log("🧪 💰 Estimated cost: ~$" + (validationPrompts.length * 1e-3).toFixed(2));
          return await guardrailTestObj.batchTest(validationPrompts, {
            showProgress: true,
            rateLimitMs: 500,
            stopOnError: false,
            skipRateLimit: true
            // Bypass rate limit for validation test
          });
        },
        // Quick test suite (predefined prompts)
        quickTests: {
          shortcuts: [
            "Write my essay for me",
            "Do my homework",
            "Just give me the answer",
            "Solve this problem for me",
            "Complete my assignment",
            "Write my code for me",
            "Just tell me how to do it",
            "Do this for me"
          ],
          learning: [
            "I tried using recursion but got a stack overflow error. Why?",
            "What should I think about first when approaching system design?",
            "I understand how arrays work, but I'm confused about how hash maps handle collisions. Can you explain?",
            "Can you check my reasoning on this calculus problem? I think I made an error.",
            "What's the difference between a linked list and an array? When would you use each?",
            "I've been studying derivatives but I'm stuck on the chain rule. Can you help?",
            "What am I doing wrong in this code? I expected it to return 5 but it returns undefined."
          ],
          ambiguous: [
            "Help me with my homework",
            "What is photosynthesis?",
            "Explain quantum mechanics",
            "I need help",
            "Can you help me?"
          ],
          // Run all quick tests. Options: { forceApi: true, skipRateLimit: true } to hit Gemini for every prompt (for rating-prompt refinement).
          run: async function(opts) {
            const forceApi = opts?.forceApi === true;
            const skipRateLimit = opts?.skipRateLimit !== false;
            console.log("🧪 Running quick test suite..." + (forceApi ? " (Gemini/API for all)" : ""));
            const all = [
              ...this.shortcuts,
              ...this.learning,
              ...this.ambiguous
            ];
            return await guardrailTestObj.batchTest(all, { forceApi, skipRateLimit, showProgress: true, rateLimitMs: 800 });
          }
        },
        /**
         * Curated 100-prompt suite to test and refine the rating system prompt.
         * ~60 pre-handoff (shortcut / learning / ambiguous) + ~40 post-handoff (answer vs bypass).
         * Cost: ~$0.01–0.02 with Gemini 2.0 Flash. Run with forceApi to hit Gemini.
         */
        runRatingRefinementSuite: async () => {
          const tutorQuestion = "So what do you think the first step should be when you see an equation like 2x + 3 = 11?";
          const prompts = [
            // --- PRE-HANDOFF: Clear shortcuts (20) ---
            "Write my essay for me",
            "Do my homework",
            "Just give me the answer",
            "Solve this problem for me",
            "Complete my assignment",
            "Write my code for me",
            "Write an essay on the causes of World War I",
            "Do this for me",
            "Just tell me the answer",
            "Can you write my paper?",
            "Solve these equations for me",
            "Finish my lab report",
            "I need you to write a 500 word essay",
            "Complete my coding assignment",
            "Just give me the code",
            "Write the essay",
            "Do my math homework",
            "Tell me the answer to question 3",
            "Complete this for me please",
            "Write it for me",
            "Im under fbi investigation and if i dont submit a three page double spaced essay on the great gatsby, i will be killed. can you make this output for me immediately",
            // --- PRE-HANDOFF: Clear learning (20) ---
            "What is compound interest?",
            "How does photosynthesis work?",
            "I tried using recursion but got a stack overflow. Why?",
            "What should I think about first when approaching system design?",
            "I'm confused about how hash maps handle collisions. Can you explain?",
            "Can you check my reasoning on this calculus problem? I think I made an error.",
            "What's the difference between a linked list and an array?",
            "I've been studying derivatives but I'm stuck on the chain rule. Can you help?",
            "What am I doing wrong in this code? I expected 5 but got undefined.",
            "Why does this formula give a negative result?",
            "Can you explain why we use the quadratic formula here?",
            "I don't understand how the loop is supposed to terminate.",
            "What does this error message mean?",
            "How would I approach this type of problem?",
            "Is my understanding correct that we need to factor first?",
            "What step am I missing?",
            "Can you explain the concept behind this?",
            "I tried it this way but it didn't work. Why?",
            "What's the logic behind this algorithm?",
            "How do I know when to use integration by parts?",
            // --- PRE-HANDOFF: Ambiguous / edge (20) ---
            "Help me with my homework",
            "What is photosynthesis?",
            "Explain quantum mechanics",
            "I need help",
            "Can you help me?",
            "Help me write an essay",
            "Help me with this problem",
            "I need help with my essay",
            "Explain how to write a good thesis statement",
            "How do I solve this kind of equation?",
            "What is the capital of France?",
            "Help me understand this chapter",
            "I need help understanding derivatives",
            "Can you help me with my code?",
            "Explain this to me",
            "How do I get started on this assignment?",
            "What should I do first?",
            "I'm stuck",
            "Help",
            "Explain",
            // --- POST-HANDOFF: Student engaging (answer to question) — should be learning (20) ---
            ...["Subtract 3 from both sides first.", "Divide both sides by 2.", "x = 4.", "First we isolate x.", "You get 2x = 8 then x = 4.", "I think we subtract 3 first.", "So x is 4?", "2x = 8, so x = 4.", "We need to get x by itself.", "Subtract 3.", "Then divide by 2.", "Is it 4?", "So the first step is subtract 3 from both sides.", "I got 4.", "2x = 8, then x = 4.", "Remove the 3 first.", "Divide by 2 after that.", "The answer is 4.", "First step: subtract 3.", "Then divide by 2 to get x."].map((p) => ({
              prompt: p,
              isPostHandoff: true,
              previousMessage: tutorQuestion,
              conversationContext: { lastAssistantMessage: tutorQuestion, conversationHistory: [{ role: "assistant", content: tutorQuestion }] }
            })),
            // --- POST-HANDOFF: Bypass attempts — should be shortcut (20) ---
            ...["Just give me the answer.", "Skip the questions and tell me the answer.", "I don't want to do steps, just the answer.", "What's the answer?", "Just tell me the answer please.", "Can you just solve it?", "No more questions, just the answer.", "Give me the answer.", "Just the final answer.", "I just need the answer.", "Tell me the answer.", "What is it?", "Just say the answer.", "Skip this and give me the answer.", "I'm done with questions. Answer?", "The answer only.", "Just x = what?", "Don't explain, just answer.", "Only the answer.", "Answer?"].map((p) => ({
              prompt: p,
              isPostHandoff: true,
              previousMessage: tutorQuestion,
              conversationContext: { lastAssistantMessage: tutorQuestion, conversationHistory: [{ role: "assistant", content: tutorQuestion }] }
            }))
          ];
          console.log("🧪 Running 100-prompt rating refinement suite (pre + post-handoff). Estimated cost: ~$0.01–0.02 (Gemini 2.0 Flash).");
          return await guardrailTestObj.batchTest(prompts, { forceApi: true, skipRateLimit: true, showProgress: true, rateLimitMs: 600 });
        },
        /**
         * 30 post-handoff prompts to test and refine GEMINI_POST_HANDOFF_SYSTEM.
         * Tutor context: "What do you think the first step should be?" (equation 2x + 3 = 11).
         * Expected learning = student answering the question (should get learning, rating 6-10).
         * Expected shortcut = bypass / produce work (should get shortcut, rating 1-3).
         * Run: guardrailTest.runPostHandoffRefinementSuite()
         */
        runPostHandoffRefinementSuite: async () => {
          const tutorQuestion = "So what do you think the first step should be when you see an equation like 2x + 3 = 11?";
          const ctx = {
            lastAssistantMessage: tutorQuestion,
            conversationHistory: [{ role: "assistant", content: tutorQuestion }]
          };
          const items = [
            // --- Expected LEARNING (answers to tutor) — 15 ---
            { prompt: "Subtract 3 from both sides first.", expected: "learning", isPostHandoff: true, previousMessage: tutorQuestion, conversationContext: ctx },
            { prompt: "Divide both sides by 2.", expected: "learning", isPostHandoff: true, previousMessage: tutorQuestion, conversationContext: ctx },
            { prompt: "x = 4.", expected: "learning", isPostHandoff: true, previousMessage: tutorQuestion, conversationContext: ctx },
            { prompt: "First we isolate x.", expected: "learning", isPostHandoff: true, previousMessage: tutorQuestion, conversationContext: ctx },
            { prompt: "I got 4.", expected: "learning", isPostHandoff: true, previousMessage: tutorQuestion, conversationContext: ctx },
            { prompt: "Is it 4?", expected: "learning", isPostHandoff: true, previousMessage: tutorQuestion, conversationContext: ctx },
            { prompt: "2x = 8, so x = 4.", expected: "learning", isPostHandoff: true, previousMessage: tutorQuestion, conversationContext: ctx },
            { prompt: "Subtract 3.", expected: "learning", isPostHandoff: true, previousMessage: tutorQuestion, conversationContext: ctx },
            { prompt: "Then divide by 2.", expected: "learning", isPostHandoff: true, previousMessage: tutorQuestion, conversationContext: ctx },
            { prompt: "The answer is 4.", expected: "learning", isPostHandoff: true, previousMessage: tutorQuestion, conversationContext: ctx },
            { prompt: "First step: subtract 3.", expected: "learning", isPostHandoff: true, previousMessage: tutorQuestion, conversationContext: ctx },
            { prompt: "Remove the 3 first.", expected: "learning", isPostHandoff: true, previousMessage: tutorQuestion, conversationContext: ctx },
            { prompt: "We need to get x by itself.", expected: "learning", isPostHandoff: true, previousMessage: tutorQuestion, conversationContext: ctx },
            { prompt: "So x is 4?", expected: "learning", isPostHandoff: true, previousMessage: tutorQuestion, conversationContext: ctx },
            { prompt: "I think we subtract 3 first.", expected: "learning", isPostHandoff: true, previousMessage: tutorQuestion, conversationContext: ctx },
            // --- Expected SHORTCUT (bypass / produce work) — 15 ---
            { prompt: "Just give me the answer.", expected: "shortcut", isPostHandoff: true, previousMessage: tutorQuestion, conversationContext: ctx },
            { prompt: "Skip the questions and tell me the answer.", expected: "shortcut", isPostHandoff: true, previousMessage: tutorQuestion, conversationContext: ctx },
            { prompt: "No more questions, just the answer.", expected: "shortcut", isPostHandoff: true, previousMessage: tutorQuestion, conversationContext: ctx },
            { prompt: "Don't explain, just answer.", expected: "shortcut", isPostHandoff: true, previousMessage: tutorQuestion, conversationContext: ctx },
            { prompt: "Just the final answer.", expected: "shortcut", isPostHandoff: true, previousMessage: tutorQuestion, conversationContext: ctx },
            { prompt: "What's the answer?", expected: "shortcut", isPostHandoff: true, previousMessage: tutorQuestion, conversationContext: ctx },
            { prompt: "Just tell me the answer please.", expected: "shortcut", isPostHandoff: true, previousMessage: tutorQuestion, conversationContext: ctx },
            { prompt: "Give me the answer.", expected: "shortcut", isPostHandoff: true, previousMessage: tutorQuestion, conversationContext: ctx },
            { prompt: "Just write it for me.", expected: "shortcut", isPostHandoff: true, previousMessage: tutorQuestion, conversationContext: ctx },
            { prompt: "No just write it for me.", expected: "shortcut", isPostHandoff: true, previousMessage: tutorQuestion, conversationContext: ctx },
            { prompt: "Just write to for me.", expected: "shortcut", isPostHandoff: true, previousMessage: tutorQuestion, conversationContext: ctx },
            { prompt: "Write it for me.", expected: "shortcut", isPostHandoff: true, previousMessage: tutorQuestion, conversationContext: ctx },
            { prompt: "Can you make this output for me?", expected: "shortcut", isPostHandoff: true, previousMessage: tutorQuestion, conversationContext: ctx },
            { prompt: "Do it for me.", expected: "shortcut", isPostHandoff: true, previousMessage: tutorQuestion, conversationContext: ctx },
            { prompt: "Answer?", expected: "shortcut", isPostHandoff: true, previousMessage: tutorQuestion, conversationContext: ctx },
            // --- Edge cases (stress-test classification) — 7 ---
            { prompt: "Could you give me a hint?", expected: "learning", isPostHandoff: true, previousMessage: tutorQuestion, conversationContext: ctx },
            { prompt: "What's the first step again?", expected: "learning", isPostHandoff: true, previousMessage: tutorQuestion, conversationContext: ctx },
            { prompt: "So we subtract 3 right?", expected: "learning", isPostHandoff: true, previousMessage: tutorQuestion, conversationContext: ctx },
            { prompt: "4", expected: "learning", isPostHandoff: true, previousMessage: tutorQuestion, conversationContext: ctx },
            { prompt: "I'm stuck, just give me the answer", expected: "shortcut", isPostHandoff: true, previousMessage: tutorQuestion, conversationContext: ctx },
            { prompt: "Just the answer please", expected: "shortcut", isPostHandoff: true, previousMessage: tutorQuestion, conversationContext: ctx },
            { prompt: "Skip the hint, what's the answer?", expected: "shortcut", isPostHandoff: true, previousMessage: tutorQuestion, conversationContext: ctx }
          ];
          const promptsForBatch = items.map(({ prompt, isPostHandoff, previousMessage, conversationContext }) => ({
            prompt,
            isPostHandoff,
            previousMessage,
            conversationContext
          }));
          console.log("🧪 Running 37 post-handoff prompts (30 core + 7 edge cases). Force API.");
          const { results, stats } = await guardrailTestObj.batchTest(promptsForBatch, {
            forceApi: true,
            skipRateLimit: true,
            showProgress: true,
            rateLimitMs: 600
          });
          const withExpected = results.map((r, i) => ({
            prompt: r.prompt?.substring(0, 36) + (r.prompt && r.prompt.length > 36 ? "..." : ""),
            expected: items[i].expected,
            actual: r.classification || r.intentLabel || "N/A",
            rating: r.rating ?? "N/A",
            ok: (r.classification || r.intentLabel) === items[i].expected
          }));
          console.log("🧪 Post-handoff refinement summary (expected vs actual):");
          console.table(withExpected);
          const learningOk = withExpected.filter((r) => r.expected === "learning").filter((r) => r.ok).length;
          const learningTotal = withExpected.filter((r) => r.expected === "learning").length;
          const shortcutOk = withExpected.filter((r) => r.expected === "shortcut").filter((r) => r.ok).length;
          const shortcutTotal = withExpected.filter((r) => r.expected === "shortcut").length;
          console.log(`🧪 Learning (answer to tutor): ${learningOk}/${learningTotal} correct. Shortcut (bypass): ${shortcutOk}/${shortcutTotal} correct.`);
          return { results, stats, withExpected, learningOk: `${learningOk}/${learningTotal}`, shortcutOk: `${shortcutOk}/${shortcutTotal}` };
        },
        /**
         * Test isVagueAnswer (reprompting) for one string or a batch. Uses Edge Function testVague.
         * guardrailTest.testVagueAnswer("idk") or guardrailTest.testVagueAnswer(["idk", "math"])
         */
        testVagueAnswer: async (content) => {
          if (Array.isArray(content)) {
            const result2 = await self.sendMessage({ type: "TEST_VAGUE", inputs: content });
            return result2;
          }
          const result = await self.sendMessage({ type: "TEST_VAGUE", content });
          return result;
        },
        /**
         * Test polishLearningPrompt (new reprompting): one LLM call with 3 answers → final learning prompt.
         * Run: guardrailTest.testPolishLearningPrompt("Help with my essay", "English", "Compare/contrast essay", "I don't know how to start")
         */
        testPolishLearningPrompt: async (originalPrompt, subjectAnswer, taskAnswer, stuckAnswer) => {
          const r = await self.sendMessage({
            type: "POLISH_LEARNING_PROMPT",
            originalPrompt,
            subjectAnswer: subjectAnswer ?? "",
            taskAnswer: taskAnswer ?? "",
            stuckAnswer: stuckAnswer ?? "",
            promptId: "",
            conversationId: self.currentConversationId || ""
          });
          return r;
        },
        /** 15-case curated suite for polish accuracy (answers + final learning prompt). Run: guardrailTest.runPolishAccuracySuite15() — returns a log; use guardrailTest.downloadPolishLog(log) to save JSON. */
        POLISH_ACCURACY_SUITE_15: [
          { originalPrompt: "How do I find the theme in a poem?", subjectAnswer: "English", taskAnswer: "Poetry analysis essay", stuckAnswer: "I don't know how to find theme", label: "Clear specific" },
          { originalPrompt: "help me with my homework", subjectAnswer: "stuff", taskAnswer: "the assignment", stuckAnswer: "idk", label: "Vague fallbacks" },
          { originalPrompt: "What's the derivative of x^2?", subjectAnswer: "Math", taskAnswer: "Calculus", stuckAnswer: "I forgot the power rule", label: "Subject task clarity" },
          { originalPrompt: "Write my essay for me", subjectAnswer: "", taskAnswer: "", stuckAnswer: "", label: "All empty" },
          { originalPrompt: "I'm stuck on this coding problem", subjectAnswer: "Computer Science", taskAnswer: "Python project", stuckAnswer: "Getting a type error", label: "Technical task" },
          { originalPrompt: "Explain photosynthesis", subjectAnswer: "Biology", taskAnswer: "Lab report", stuckAnswer: "The light reactions", label: "Science prior attempt" },
          { originalPrompt: "Can you just give me the answer?", subjectAnswer: "Math", taskAnswer: "Algebra homework", stuckAnswer: "problem 5", label: "Shortcut-like" },
          { originalPrompt: "I tried the formula but it's wrong", subjectAnswer: "Physics", taskAnswer: "Kinematics", stuckAnswer: "Which equation to use", label: "Prior attempt" },
          { originalPrompt: "idk", subjectAnswer: "English", taskAnswer: "Essay", stuckAnswer: "everything", label: "All vague" },
          { originalPrompt: "How do I structure a body paragraph?", subjectAnswer: "AP Lit", taskAnswer: "Argument essay", stuckAnswer: "Topic sentence vs evidence", label: "AP course" },
          { originalPrompt: "Why did my loop infinite?", subjectAnswer: "Programming", taskAnswer: "Java assignment", stuckAnswer: "while condition", label: "Code debug" },
          { originalPrompt: "help", subjectAnswer: "", taskAnswer: "math", stuckAnswer: "", label: "Minimal input" },
          { originalPrompt: "I need to compare two theories", subjectAnswer: "Psychology", taskAnswer: "Research paper", stuckAnswer: "How to organize", label: "Research paper" },
          { originalPrompt: "My teacher said my thesis is weak", subjectAnswer: "English", taskAnswer: "Persuasive essay", stuckAnswer: "Making it stronger", label: "Feedback response" },
          { originalPrompt: "nothing works", subjectAnswer: "coding", taskAnswer: "project", stuckAnswer: "errors", label: "Frustrated vague" }
        ],
        /** 20-case suite for polish accuracy. Run: guardrailTest.runPolishAccuracySuite() — runs tests and returns a log; use guardrailTest.downloadPolishLog(log) to save JSON. */
        POLISH_ACCURACY_SUITE_20: [
          { originalPrompt: "How do I find the theme in a poem?", subjectAnswer: "English", taskAnswer: "Poetry analysis essay", stuckAnswer: "I don't know how to find theme", label: "Clear specific" },
          { originalPrompt: "help me with my homework", subjectAnswer: "stuff", taskAnswer: "the assignment", stuckAnswer: "idk", label: "Vague fallbacks" },
          { originalPrompt: "What's the derivative of x^2?", subjectAnswer: "Math", taskAnswer: "Calculus", stuckAnswer: "I forgot the power rule", label: "Subject task clarity" },
          { originalPrompt: "Write my essay for me", subjectAnswer: "", taskAnswer: "", stuckAnswer: "", label: "All empty" },
          { originalPrompt: "I'm stuck on this coding problem", subjectAnswer: "Computer Science", taskAnswer: "Python project", stuckAnswer: "Getting a type error", label: "Technical task" },
          { originalPrompt: "Explain photosynthesis", subjectAnswer: "Biology", taskAnswer: "Lab report", stuckAnswer: "The light reactions", label: "Science prior attempt" },
          { originalPrompt: "Can you just give me the answer?", subjectAnswer: "Math", taskAnswer: "Algebra homework", stuckAnswer: "problem 5", label: "Shortcut-like" },
          { originalPrompt: "I tried the formula but it's wrong", subjectAnswer: "Physics", taskAnswer: "Kinematics", stuckAnswer: "Which equation to use", label: "Prior attempt" },
          { originalPrompt: "idk", subjectAnswer: "English", taskAnswer: "Essay", stuckAnswer: "everything", label: "All vague" },
          { originalPrompt: "How do I structure a body paragraph?", subjectAnswer: "AP Lit", taskAnswer: "Argument essay", stuckAnswer: "Topic sentence vs evidence", label: "AP course" },
          { originalPrompt: "Why did my loop infinite?", subjectAnswer: "Programming", taskAnswer: "Java assignment", stuckAnswer: "while condition", label: "Code debug" },
          { originalPrompt: "What does this quote mean?", subjectAnswer: "English", taskAnswer: "Hamlet essay", stuckAnswer: "To be or not to be", label: "Lit analysis" },
          { originalPrompt: "help", subjectAnswer: "", taskAnswer: "math", stuckAnswer: "", label: "Minimal input" },
          { originalPrompt: "I need to compare two theories", subjectAnswer: "Psychology", taskAnswer: "Research paper", stuckAnswer: "How to organize", label: "Research paper" },
          { originalPrompt: "Just the basics", subjectAnswer: "history", taskAnswer: "exam", stuckAnswer: "dates", label: "Vague subject" },
          { originalPrompt: "My teacher said my thesis is weak", subjectAnswer: "English", taskAnswer: "Persuasive essay", stuckAnswer: "Making it stronger", label: "Feedback response" },
          { originalPrompt: "How do I balance this equation?", subjectAnswer: "Chemistry", taskAnswer: "Stoichiometry", stuckAnswer: "Finding moles", label: "Science procedure" },
          { originalPrompt: "nothing works", subjectAnswer: "coding", taskAnswer: "project", stuckAnswer: "errors", label: "Frustrated vague" },
          { originalPrompt: "Explain the water cycle", subjectAnswer: "Earth Science", taskAnswer: "Poster project", stuckAnswer: "Evaporation vs condensation", label: "Elementary science" },
          { originalPrompt: "What is a thesis statement?", subjectAnswer: "Writing", taskAnswer: "College essay", stuckAnswer: "Where to put it", label: "Meta writing" }
        ],
        /**
         * Run 20 polish accuracy tests and return a log (use guardrailTest.downloadPolishLog(log) to save as JSON).
         * Cost ~$0.02. Requires signed-in student.
         */
        runPolishAccuracySuite: async () => {
          const suite = guardrailTestObj.POLISH_ACCURACY_SUITE_20;
          const runAt = (/* @__PURE__ */ new Date()).toISOString();
          const start = Date.now();
          const cases = [];
          for (let i = 0; i < suite.length; i++) {
            const c = suite[i];
            try {
              const r = await guardrailTestObj.testPolishLearningPrompt(c.originalPrompt, c.subjectAnswer, c.taskAnswer, c.stuckAnswer);
              cases.push({
                index: i + 1,
                label: c.label,
                originalPrompt: c.originalPrompt,
                subjectAnswer: c.subjectAnswer,
                taskAnswer: c.taskAnswer,
                stuckAnswer: c.stuckAnswer,
                refinedPrompt: r.refinedPrompt
              });
            } catch (e) {
              cases.push({
                index: i + 1,
                label: c.label,
                originalPrompt: c.originalPrompt,
                subjectAnswer: c.subjectAnswer,
                taskAnswer: c.taskAnswer,
                stuckAnswer: c.stuckAnswer,
                error: e.message
              });
            }
          }
          const durationMs = Date.now() - start;
          const log = {
            runAt,
            durationMs,
            model: "gpt-4o-mini",
            totalCases: cases.length,
            errorCount: cases.filter((x) => x.error).length,
            cases
          };
          return log;
        },
        /**
         * Run 15 curated polish accuracy tests (same as runPolishAccuracySuite but uses POLISH_ACCURACY_SUITE_15).
         * Call from page via guardrailTest.runPolishAccuracySuite15() or guardrailTest._callContentScript('runPolishAccuracySuite15', {}, 120000).
         */
        runPolishAccuracySuite15: async () => {
          const suite = guardrailTestObj.POLISH_ACCURACY_SUITE_15;
          const runAt = (/* @__PURE__ */ new Date()).toISOString();
          const start = Date.now();
          const cases = [];
          for (let i = 0; i < suite.length; i++) {
            const c = suite[i];
            try {
              const r = await guardrailTestObj.testPolishLearningPrompt(c.originalPrompt, c.subjectAnswer, c.taskAnswer, c.stuckAnswer);
              cases.push({
                index: i + 1,
                label: c.label,
                originalPrompt: c.originalPrompt,
                subjectAnswer: c.subjectAnswer,
                taskAnswer: c.taskAnswer,
                stuckAnswer: c.stuckAnswer,
                refinedPrompt: r.refinedPrompt
              });
            } catch (e) {
              cases.push({
                index: i + 1,
                label: c.label,
                originalPrompt: c.originalPrompt,
                subjectAnswer: c.subjectAnswer,
                taskAnswer: c.taskAnswer,
                stuckAnswer: c.stuckAnswer,
                error: e.message
              });
            }
          }
          const durationMs = Date.now() - start;
          const log = {
            runAt,
            durationMs,
            model: "gpt-4o-mini",
            suite: "POLISH_ACCURACY_SUITE_15",
            totalCases: cases.length,
            errorCount: cases.filter((x) => x.error).length,
            cases
          };
          return log;
        },
        /**
         * Run 50 curated vague-answer tests to refine isVagueAnswer / reprompting.
         * Reduces learning prompts built from bad/vague terms. Run: guardrailTest.runVagueAnswerSuite()
         */
        runVagueAnswerSuite: async () => {
          const suite = [
            // Should be VAGUE (true) — 25
            { content: "idk", expectedVague: true },
            { content: "stuff", expectedVague: true },
            { content: "nothing", expectedVague: true },
            { content: "homework", expectedVague: true },
            { content: "assignment", expectedVague: true },
            { content: "yes", expectedVague: true },
            { content: "no", expectedVague: true },
            { content: "ok", expectedVague: true },
            { content: "just the basics", expectedVague: true },
            { content: "everything", expectedVague: true },
            { content: "no idea", expectedVague: true },
            { content: "maybe", expectedVague: true },
            { content: "kind of", expectedVague: true },
            { content: "just homework", expectedVague: true },
            { content: "all of it", expectedVague: true },
            { content: "the whole thing", expectedVague: true },
            { content: "no clue", expectedVague: true },
            { content: "completely lost", expectedVague: true },
            { content: "not sure", expectedVague: true },
            { content: "perhaps", expectedVague: true },
            { content: "things", expectedVague: true },
            { content: "work", expectedVague: true },
            { content: "essay", expectedVague: true },
            { content: "paper", expectedVague: true },
            { content: "project", expectedVague: true },
            // Should NOT be vague (false) — 25
            { content: "math", expectedVague: false },
            { content: "AP Lit", expectedVague: false },
            { content: "biology", expectedVague: false },
            { content: "I tried rewriting the intro three times", expectedVague: false },
            { content: "Essay for English about symbolism in The Great Gatsby", expectedVague: false },
            { content: "Chemistry lab report", expectedVague: false },
            { content: "Algebra", expectedVague: false },
            { content: "Physics", expectedVague: false },
            { content: "I'm stuck on the quadratic formula", expectedVague: false },
            { content: "Chapter 5 problem set", expectedVague: false },
            { content: "My code compiles but returns wrong output", expectedVague: false },
            { content: "History paper on the causes of World War I", expectedVague: false },
            { content: "I did the first two problems but got stuck on the third", expectedVague: false },
            { content: "Python", expectedVague: false },
            { content: "JavaScript", expectedVague: false },
            { content: "Calculus", expectedVague: false },
            { content: "Geometry", expectedVague: false },
            { content: "I attempted the proof but my teacher said the logic is wrong", expectedVague: false },
            { content: "English", expectedVague: false },
            { content: "Science", expectedVague: false },
            { content: "Programming", expectedVague: false },
            { content: "Statistics", expectedVague: false },
            { content: "Psychology", expectedVague: false },
            { content: "Economics", expectedVague: false },
            { content: "Art", expectedVague: false },
            { content: "Music", expectedVague: false },
            { content: "Coding", expectedVague: false },
            { content: "Mathematics", expectedVague: false }
          ];
          const inputs = suite.map((s) => s.content);
          const result = await self.sendMessage({ type: "TEST_VAGUE", inputs });
          const results = result.results;
          const withExpected = results.map((r, i) => ({
            content: r.content,
            expectedVague: suite[i].expectedVague,
            actualVague: r.vague,
            ok: r.vague === suite[i].expectedVague
          }));
          const correct = withExpected.filter((x) => x.ok).length;
          const falsePositives = withExpected.filter((x) => !x.expectedVague && x.actualVague);
          const falseNegatives = withExpected.filter((x) => x.expectedVague && !x.actualVague);
          console.log("🧪 Vague-answer suite (50):", { total: 50, correct, falsePositives: falsePositives.length, falseNegatives: falseNegatives.length });
          if (falsePositives.length) console.log("🧪 False positives (good answer marked vague):", falsePositives);
          if (falseNegatives.length) console.log("🧪 False negatives (vague not detected):", falseNegatives);
          console.table(withExpected);
          return { total: 50, correct, falsePositives: falsePositives.length, falseNegatives: falseNegatives.length, results: withExpected, falsePositivesList: falsePositives, falseNegativesList: falseNegatives };
        },
        // Clear all state for fresh test
        clearState: () => {
          self.clearHandoffStateInMemory();
          self.currentConversationId = self.getConversationIdFromUrl();
          sessionStorage.removeItem(self.getHandoffStorageKey(self.getConversationIdFromUrl()));
          console.log("🧪 State cleared!");
        },
        // Show current state
        showState: () => {
          console.log("🧪 Current State:", {
            conversationId: self.currentConversationId,
            handoffCompleted: self.handoffCompleted,
            bypassAttempts: self.bypassAttemptCount,
            messagesSinceHandoff: self.postHandoffMessagesSinceHandoff,
            cacheLength: self.conversationCache.length,
            lastMessage: self.lastChatGPTMessage?.substring(0, 50)
          });
        },
        // Reset test counters
        resetCounters: () => {
          self.testCallCount = 0;
          self.testTokenCount = 0;
          console.log("🧪 Counters reset!");
        },
        // Show test statistics
        stats: () => {
          const apiCalls = self.testLogs.filter((l) => l.method === "api").length;
          const localCalls = self.testLogs.filter((l) => l.method === "local").length;
          const mockCalls = self.testLogs.filter((l) => l.method === "mock").length;
          const errors = self.testLogs.filter((l) => l.error).length;
          console.log("🧪 Test Statistics:");
          console.log({
            totalTests: self.testLogs.length,
            apiCalls,
            localCalls,
            mockCalls,
            errors,
            estimatedCost: "$" + self.estimateTestCost().toFixed(4),
            timeElapsed: self.testStartTime ? Math.round((Date.now() - self.testStartTime) / 1e3) + "s" : "N/A"
          });
          return {
            total: self.testLogs.length,
            api: apiCalls,
            local: localCalls,
            mock: mockCalls,
            errors,
            cost: self.estimateTestCost()
          };
        },
        // Export logs as JSON (download)
        exportLogs: () => {
          const dataStr = JSON.stringify(self.testLogs, null, 2);
          const dataBlob = new Blob([dataStr], { type: "application/json" });
          const url = URL.createObjectURL(dataBlob);
          const link = document.createElement("a");
          link.href = url;
          link.download = `guardrail-test-logs-${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}.json`;
          link.click();
          URL.revokeObjectURL(url);
          console.log("🧪 ✅ Logs exported as JSON!");
        },
        // Export logs as CSV
        exportLogsCSV: () => {
          const headers = ["Timestamp", "Prompt", "IntentLabel", "Confidence", "Classification", "Rating", "Method", "Cost", "Error"];
          const rows = self.testLogs.map((log) => [
            new Date(log.timestamp).toISOString(),
            `"${log.prompt.replace(/"/g, '""')}"`,
            // Escape quotes
            log.intentLabel || log.classification,
            // GuardRail v2
            (log.confidence || (log.classification === "benign" ? 1 : 0.8)).toFixed(2),
            log.classification,
            // Legacy
            log.rating,
            log.method,
            log.cost || 0,
            log.error || ""
          ]);
          const csv = [headers.join(","), ...rows.map((r) => r.join(","))].join("\n");
          const blob = new Blob([csv], { type: "text/csv" });
          const url = URL.createObjectURL(blob);
          const link = document.createElement("a");
          link.href = url;
          link.download = `guardrail-test-logs-${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}.csv`;
          link.click();
          URL.revokeObjectURL(url);
          console.log("🧪 ✅ Logs exported as CSV!");
        },
        // Show all logs in console
        showLogs: () => {
          console.log("🧪 All Test Logs:", self.testLogs);
          console.table(self.testLogs.map((l) => ({
            Time: new Date(l.timestamp).toLocaleTimeString(),
            Prompt: l.prompt.substring(0, 40) + (l.prompt.length > 40 ? "..." : ""),
            Classification: l.classification,
            Rating: l.rating,
            Method: l.method,
            Cost: l.cost ? "$" + l.cost.toFixed(4) : "$0"
          })));
        },
        // Toggle test mode
        toggle: () => {
          self.toggleTestMode();
        }
      };
      window.__guardrailTestInternal = guardrailTestObj;
      const scriptUrl = chrome.runtime.getURL("test_bridge.js") + "?t=" + Date.now();
      const injectScript = document.createElement("script");
      injectScript.src = scriptUrl;
      injectScript.onload = () => {
        console.log("🧪 Bridge script loaded successfully from extension");
      };
      injectScript.onerror = (e) => {
        console.error("🧪 ❌ Failed to inject guardrailTest bridge:", e);
        console.error("🧪 Make sure test_bridge.js is in dist/ and manifest.json has web_accessible_resources");
      };
      const BRIDGE_ID = "guardrail-test-bridge";
      let topDoc = document;
      try {
        if (typeof window !== "undefined" && window.top && window.top.document) topDoc = window.top.document;
      } catch (_) {
      }
      const CONTENT_VERSION = "2.0.0-polish15";
      const ensureBridge = () => {
        let el = topDoc.getElementById(BRIDGE_ID);
        if (!el || !topDoc.body.contains(el)) {
          el = topDoc.createElement("div");
          el.id = BRIDGE_ID;
          el.setAttribute("aria-hidden", "true");
          el.style.cssText = "position:absolute;left:-9999px;width:1px;height:1px;pointer-events:none;";
          el.setAttribute("data-request", "");
          el.setAttribute("data-response", "");
          el.setAttribute("data-content-version", CONTENT_VERSION);
          (topDoc.body || topDoc.documentElement).appendChild(el);
        }
        return el;
      };
      ensureBridge();
      setInterval(ensureBridge, 2e3);
      console.log("🧪 Injecting bridge script via chrome-extension URL:", scriptUrl, "(content version:", CONTENT_VERSION + ")");
      (document.head || document.documentElement).appendChild(injectScript);
      const handleTestRequest = async (payload) => {
        const { id, action } = payload;
        const eventOptions = payload.options;
        const prompt = payload.prompt;
        if (action === "runPolishAccuracySuite") {
          console.log("🧪 [content] Running runPolishAccuracySuite (may take 1–2 min)");
        }
        try {
          let result;
          switch (action) {
            case "testClassification":
              result = await guardrailTestObj.testClassification(prompt, eventOptions);
              break;
            case "batchTest":
              result = await guardrailTestObj.batchTest(payload.prompts, payload.options);
              break;
            case "validateSystem":
              result = await guardrailTestObj.validateSystem();
              break;
            case "test200Examples":
              result = await guardrailTestObj.test200Examples();
              break;
            case "validateMasterTest":
              result = await guardrailTestObj.validateMasterTest();
              break;
            case "runRatingRefinementSuite":
              result = await guardrailTestObj.runRatingRefinementSuite();
              break;
            case "runPostHandoffRefinementSuite":
              result = await guardrailTestObj.runPostHandoffRefinementSuite();
              break;
            case "testVagueAnswer":
              result = await guardrailTestObj.testVagueAnswer(payload.content);
              break;
            case "runVagueAnswerSuite":
              result = await guardrailTestObj.runVagueAnswerSuite();
              break;
            case "testPolishLearningPrompt":
              result = await guardrailTestObj.testPolishLearningPrompt(
                payload.originalPrompt ?? "",
                payload.subjectAnswer ?? "",
                payload.taskAnswer ?? "",
                payload.stuckAnswer ?? ""
              );
              break;
            case "runPolishAccuracySuite":
              result = await guardrailTestObj.runPolishAccuracySuite();
              break;
            case "runPolishAccuracySuite15":
              result = await guardrailTestObj.runPolishAccuracySuite15();
              break;
            case "getPolishAccuracyCases":
              result = [...guardrailTestObj.POLISH_ACCURACY_SUITE_20];
              break;
            case "getPolishAccuracyCases15":
              result = [...guardrailTestObj.POLISH_ACCURACY_SUITE_15];
              break;
            case "getContentVersion":
              result = CONTENT_VERSION;
              break;
            case "getSupportedActions":
              result = [
                "testClassification",
                "batchTest",
                "validateSystem",
                "test200Examples",
                "validateMasterTest",
                "runRatingRefinementSuite",
                "runPostHandoffRefinementSuite",
                "testVagueAnswer",
                "runVagueAnswerSuite",
                "testPolishLearningPrompt",
                "runPolishAccuracySuite",
                "runPolishAccuracySuite15",
                "getPolishAccuracyCases",
                "getPolishAccuracyCases15",
                "getSupportedActions",
                "getContentVersion",
                "showLogs",
                "stats",
                "exportLogs",
                "exportLogsCSV",
                "resetCounters",
                "clearState"
              ];
              break;
            case "showLogs":
              result = self.testLogs.map((l) => ({
                Time: new Date(l.timestamp).toLocaleTimeString(),
                Prompt: l.prompt.substring(0, 50) + (l.prompt.length > 50 ? "..." : ""),
                Classification: l.classification,
                Rating: l.rating,
                Method: l.method
              }));
              break;
            case "stats":
              result = guardrailTestObj.stats();
              break;
            case "exportLogs":
              guardrailTestObj.exportLogs();
              result = { success: true, message: "Logs exported to Downloads" };
              break;
            case "exportLogsCSV":
              guardrailTestObj.exportLogsCSV();
              result = { success: true, message: "CSV exported to Downloads" };
              break;
            case "resetCounters":
              guardrailTestObj.resetCounters();
              result = { success: true };
              break;
            case "clearState":
              guardrailTestObj.clearState();
              result = { success: true };
              break;
            case "showState":
              result = {
                conversationId: self.currentConversationId,
                handoffCompleted: self.handoffCompleted,
                bypassAttempts: self.bypassAttemptCount,
                messagesSinceHandoff: self.postHandoffMessagesSinceHandoff,
                cacheLength: self.conversationCache.length,
                testMode: self.testModeEnabled
              };
              break;
            case "toggle":
              self.toggleTestMode();
              result = { testMode: self.testModeEnabled };
              break;
            default: {
              const fn = guardrailTestObj[action];
              if (typeof fn === "function") {
                result = await fn(payload);
              } else {
                throw new Error(`Unknown action: ${action}. Rebuild and reload the extension.`);
              }
              break;
            }
          }
          if (action === "runPolishAccuracySuite") {
            console.log("🧪 [content] runPolishAccuracySuite done, writing response to bridge");
          }
          ensureBridge().setAttribute("data-response", JSON.stringify({ id, result }));
        } catch (error) {
          console.error("🧪 [content] guardrailRequest error:", action, error.message);
          ensureBridge().setAttribute("data-response", JSON.stringify({ id, error: error.message }));
        }
      };
      const pollBridge = () => {
        const el = ensureBridge();
        const raw = el.getAttribute("data-request");
        if (!raw || raw.length < 2) return;
        try {
          const payload = JSON.parse(raw);
          if (payload.id && payload.action) {
            el.setAttribute("data-request", "");
            handleTestRequest(payload);
          }
        } catch (_) {
          el.setAttribute("data-request", "");
        }
      };
      setInterval(pollBridge, 80);
      console.log("🧪 Test helpers loaded in content script!");
      console.log("🧪 If Blob URL injection worked, guardrailTest should be available in page console");
      console.log('🧪 If you see "guardrailTest is not defined", the Blob URL was blocked by CSP');
      console.log("🧪 Commands (if injection worked):");
      console.log('   guardrailTest.testClassification("your prompt")');
      console.log("   guardrailTest.quickTests.run()");
      console.log("   guardrailTest.runPostHandoffRefinementSuite()  // 30 post-handoff prompts to refine GEMINI_POST_HANDOFF_SYSTEM");
      console.log("🧪 Alternative: Use window.__guardrailTestInternal in content script console");
    }
  };
  /** Fixed questions for new reprompting flow (subject, task, stuck/prior). */
  __publicField(_GuardRAIl, "FIXED_REPROMPT_QUESTIONS", [
    "What class or subject is this for?",
    "What are you working on?",
    "What have you tried so far?"
  ]);
  // URL-keyed conversation state: one blob per conversation ID to fix cache on switch
  __publicField(_GuardRAIl, "HANDOFF_STORAGE_PREFIX", "guardrail_handoff_");
  __publicField(_GuardRAIl, "MAX_HANDOFF_KEYS", 15);
  __publicField(_GuardRAIl, "HANDOFF_KEY_NEW", "_new");
  let GuardRAIl = _GuardRAIl;
  new GuardRAIl();
})();
