diff --git a/backend/app/services/paper_processor.py b/backend/app/services/paper_processor.py
index 86dc4e2..aed6397 100644
--- a/backend/app/services/paper_processor.py
+++ b/backend/app/services/paper_processor.py
@@ -144,6 +144,7 @@ Solution requirements:
- Mark common mistakes with
...
KaTeX formula rules:
+- CRITICAL: ALL math expressions MUST use LaTeX inside $ or $$. NEVER use Unicode symbols like ⁿ, ≥, ≠, ², ×, ∑, ∈. Use $n$, $\geq$, $\neq$, $^2$, $\times$, $\sum$, $\in$ instead.
- Block formula: $$ on its own line, with blank lines before and after
- Inline formula: $x^2$ no line break
- Matrix: \\begin{{bmatrix}} ... \\end{{bmatrix}}
@@ -174,6 +175,7 @@ Rules:
- Keep each item matched to the same question_number
- All text must be in English
- HTML only, KaTeX compatible
+- CRITICAL LaTeX requirement: ALL mathematical expressions MUST use LaTeX notation wrapped in $ (inline) or $$ (display block). NEVER use Unicode math symbols like ⁿ, ≥, ≠, ², ×, ∑, ∈, ⊆, etc. Instead use $n$, $\geq$, $\neq$, $^2$, $\times$, $\sum$, $\in$, $\subseteq$, etc. Every variable, number in a formula, operator, and equation must be inside $ delimiters.
- For MC questions, explain why the correct option is right and why the others are wrong
- For long questions, show a complete derivation or reasoning chain
- Use or numbered steps in solution when appropriate
diff --git a/backend/regen_comp2711h_trio.py b/backend/regen_comp2711h_trio.py
new file mode 100644
index 0000000..1aa8d51
--- /dev/null
+++ b/backend/regen_comp2711h_trio.py
@@ -0,0 +1,47 @@
+"""
+One-off script: clear AI trio for COMP2711H paper and regenerate with LaTeX-enforced prompt.
+Run inside the backend Docker container or locally with .env loaded.
+"""
+import asyncio
+import json
+import sys
+import os
+
+sys.path.insert(0, os.path.dirname(__file__))
+
+from dotenv import load_dotenv
+load_dotenv(os.path.join(os.path.dirname(__file__), "..", ".env"))
+
+from app.services.supabase_client import get_supabase
+from app.services.paper_processor import _resume_ai_trio
+
+PAPER_ID = "5ee87a62-65bf-4952-be40-fcdf9ba7ca63" # COMP2711H 2025 fall final
+
+
+async def main():
+ sb = get_supabase()
+
+ # 1. Clear existing AI trio fields so _resume_ai_trio will regenerate them
+ questions = sb.table("paper_questions").select("id, question_number, solution").eq("paper_id", PAPER_ID).execute().data
+ print(f"Found {len(questions)} questions for paper {PAPER_ID[:8]}")
+
+ cleared = 0
+ for q in questions:
+ if q.get("solution"):
+ sb.table("paper_questions").update({
+ "knowledge_reminder": "",
+ "ai_hint": "",
+ "solution": "",
+ }).eq("id", q["id"]).execute()
+ cleared += 1
+ q["solution"] = None # so _resume_ai_trio picks it up
+
+ print(f"Cleared AI trio for {cleared} questions. Regenerating...")
+
+ # 2. Regenerate
+ await _resume_ai_trio(sb, PAPER_ID, questions)
+ print("Done! AI trio regenerated with LaTeX-enforced prompt.")
+
+
+if __name__ == "__main__":
+ asyncio.run(main())
diff --git a/frontend/src/components/layout/Header.tsx b/frontend/src/components/layout/Header.tsx
index 44b0b7d..080d5dd 100644
--- a/frontend/src/components/layout/Header.tsx
+++ b/frontend/src/components/layout/Header.tsx
@@ -1,5 +1,7 @@
+import { useState } from "react";
import { Link } from "react-router-dom";
import { useAuth } from "@/contexts/AuthContext";
+import PricingModal from "@/components/shared/PricingModal";
export default function Header({
courseCode,
@@ -9,8 +11,10 @@ export default function Header({
paperTitle?: string;
}) {
const { user, signOut } = useAuth();
+ const [showPricing, setShowPricing] = useState(false);
return (
+ <>
PastPaper Master
@@ -48,6 +52,15 @@ export default function Header({
{user ? (