{
  "$schema": "https://uipkge.dev/schema/registry-item.json",
  "name": "prompt-ab-testing-comparator",
  "title": "Prompt Ab Testing Comparator",
  "type": "registry:page",
  "files": [
    {
      "path": "packages/registry-angular/blocks/prompt-ab-testing-comparator/prompt-ab-testing-comparator.component.ts",
      "content": "// Side-by-side prompt variation comparison shootout: benchmark test payload, Prompt A\n// (baseline) vs Prompt B (challenger) arena with latency / cost / judge critique, plus an\n// aggregate win-rate scorecard with rubric matrix and golden runs. Port of the React block 1:1.\nimport { ChangeDetectionStrategy, Component, DestroyRef, Input, computed, inject, signal } from '@angular/core'\nimport {\n  AlertCircle,\n  Check,\n  CheckCircle2,\n  Clock,\n  Code2,\n  Coins,\n  Copy,\n  Cpu,\n  LucideAngularModule,\n  Play,\n  Rocket,\n  Scale,\n  ShieldCheck,\n  Sparkles,\n  Terminal,\n  Trophy,\n} from 'lucide-angular'\nimport { cn } from '@/lib/utils'\nimport { UiBadgeComponent } from '@/ui/badge/badge.component'\nimport { UiButtonComponent } from '@/ui/button/button.component'\nimport {\n  UiCardComponent,\n  UiCardContentComponent,\n  UiCardDescriptionComponent,\n  UiCardHeaderComponent,\n  UiCardTitleComponent,\n} from '@/ui/card/card.component'\nimport {\n  UiTableBodyComponent,\n  UiTableCellComponent,\n  UiTableComponent,\n  UiTableHeadComponent,\n  UiTableHeaderComponent,\n  UiTableRowComponent,\n} from '@/ui/table/table.component'\nimport {\n  UiTabsComponent,\n  UiTabsContentComponent,\n  UiTabsListComponent,\n  UiTabsTriggerComponent,\n} from '@/ui/tabs/tabs.component'\n\ninterface TestCase {\n  id: string\n  number: string\n  title: string\n  prompt: string\n  componentTarget: string\n  category: string\n}\n\nconst testCases: TestCase[] = [\n  {\n    id: 'test-18',\n    number: '#18',\n    title: 'Button Component with CVA Variants',\n    prompt: 'Generate a polymorphic Button component with cva variants in Vue 3.5 <script setup lang=\"ts\">',\n    componentTarget: 'Button.vue',\n    category: 'Control / Primitive',\n  },\n  {\n    id: 'test-24',\n    number: '#24',\n    title: 'Card Container with Header and Action',\n    prompt: 'Generate a compound Card component with CardHeader, CardTitle, and CardAction in Vue 3.5',\n    componentTarget: 'Card.vue',\n    category: 'Layout / Primitive',\n  },\n  {\n    id: 'test-31',\n    number: '#31',\n    title: 'Tabs Navigation with Animated Indicator',\n    prompt: 'Create a headless accessible Tabs component with horizontal/vertical orientation support in Vue 3.5',\n    componentTarget: 'Tabs.vue',\n    category: 'Navigation',\n  },\n  {\n    id: 'test-42',\n    number: '#42',\n    title: 'Semantic Status Badge Component',\n    prompt: 'Build a Badge component with success, warning, destructive, and outline variants in Tailwind v4',\n    componentTarget: 'Badge.vue',\n    category: 'Feedback / Tag',\n  },\n]\n\nconst promptAData = {\n  id: 'prompt-a',\n  label: 'Prompt A',\n  variantName: 'Baseline Control',\n  model: 'Claude 3.5 Sonnet',\n  temperature: '0.7',\n  maxTokens: 2048,\n  latency: '1.42s',\n  outputTokens: 340,\n  cost: '$0.0018',\n  judgeScore: 82,\n  judgeStatus: 'Baseline Control',\n  critique: 'Generated inline cva variants in index.ts causing potential SSR circular imports.',\n  systemPrompt: `You are a Vue 3 component generator. Generate standard Vue SFC components with Tailwind CSS and class-variance-authority for variants.`,\n  outputCode: `<script setup lang=\"ts\">\nimport { buttonVariants } from './index'\n\ninterface Props {\n  variant?: 'default' | 'destructive' | 'outline' | 'secondary' | 'ghost' | 'link'\n  size?: 'default' | 'sm' | 'lg' | 'icon'\n  asChild?: boolean\n  class?: string\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n  variant: 'default',\n  size: 'default',\n})\n</script>\n\n<template>\n  <button\n    :class=\"buttonVariants({ variant: props.variant, size: props.size, class: props.class })\"\n  >\n    <slot />\n  </button>\n</template>`,\n}\n\nconst promptBData = {\n  id: 'prompt-b',\n  label: 'Prompt B',\n  variantName: 'Challenger (With Rules)',\n  model: 'Claude 3.5 Sonnet',\n  temperature: '0.7',\n  maxTokens: 2048,\n  latency: '1.28s',\n  latencyDelta: '-0.14s (-9.8%)',\n  outputTokens: 320,\n  tokensDelta: '-20 tok (-5.9%)',\n  cost: '$0.0016',\n  costDelta: '-$0.0002 (-11.1%)',\n  judgeScore: 96,\n  judgeDelta: '+14 pts',\n  judgeStatus: 'Winner · +14 pts',\n  critique: 'Clean architectural separation with .variants.ts sidecar and strict 120-col Prettier formatting.',\n  systemPrompt: `You are a specialized Vue 3.5 SFC generator for UIPKGE. Adhere strictly to the sidecar variant architecture: 1) ALWAYS isolate CVA variant definitions into a standalone [name].variants.ts file to eliminate Vue SSR circular-import deadlocks, 2) Use <script setup lang=\"ts\"> with Primitive from reka-ui for polymorphic as/asChild rendering, 3) Follow 120-column Prettier formatting without semicolons.`,\n  outputCode: `<script setup lang=\"ts\">\nimport type { HTMLAttributes } from 'vue'\nimport { Primitive } from 'reka-ui'\nimport { cn } from '@/lib/utils'\nimport { buttonVariants, type ButtonVariants } from './button.variants'\n\ninterface Props {\n  as?: string\n  asChild?: boolean\n  variant?: ButtonVariants['variant']\n  size?: ButtonVariants['size']\n  class?: HTMLAttributes['class']\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n  as: 'button',\n})\n</script>\n\n<template>\n  <Primitive\n    data-slot=\"button\"\n    :data-variant=\"variant\"\n    :data-size=\"size\"\n    :as=\"as\"\n    :as-child=\"asChild\"\n    :class=\"cn(buttonVariants({ variant, size }), props.class)\"\n  >\n    <slot />\n  </Primitive>\n</template>`,\n}\n\nconst rubricDimensions = [\n  {\n    id: 'ssr-safety',\n    name: 'SSR Safety & Circular Import Guard',\n    promptAScore: '68 / 100',\n    promptBScore: '98 / 100',\n    delta: '+30 pts',\n    insight: 'Prompt B isolates variants into button.variants.ts, preventing component <-> index.ts SSR deadlocks.',\n  },\n  {\n    id: 'polymorphism',\n    name: 'Polymorphism & Reka UI Primitive',\n    promptAScore: '84 / 100',\n    promptBScore: '96 / 100',\n    delta: '+12 pts',\n    insight: 'Prompt B wraps Reka UI Primitive with asChild and data-slot attributes for full slot delegation.',\n  },\n  {\n    id: 'typescript-typing',\n    name: 'TypeScript HTMLAttributes & Variants',\n    promptAScore: '82 / 100',\n    promptBScore: '95 / 100',\n    delta: '+13 pts',\n    insight: \"Uses HTMLAttributes['class'] and ButtonVariants['variant'] instead of generic string props.\",\n  },\n  {\n    id: 'token-efficiency',\n    name: 'Token Generation Efficiency',\n    promptAScore: '88 / 100 (340 tok)',\n    promptBScore: '94 / 100 (320 tok)',\n    delta: '+6 pts (-5.9% tok)',\n    insight: 'Direct script setup syntax eliminates 20 tokens of redundant wrapper code per generation.',\n  },\n  {\n    id: 'style-conformance',\n    name: 'Prettier & 120-Col Print Width',\n    promptAScore: '88 / 100',\n    promptBScore: '97 / 100',\n    delta: '+9 pts',\n    insight: 'Strict adherence to single quotes, no semicolons, 2-space indentation, and sorted utility classes.',\n  },\n]\n\nconst summaryMetrics = [\n  {\n    id: 'win-rate',\n    label: 'Overall Win Rate',\n    value: '84.0%',\n    subvalue: '42 of 50 Tests Won',\n    badge: 'Dominant Win',\n    badgeVariant: 'success' as const,\n    description: 'Prompt B outperformed or matched Prompt A in 47 / 50 benchmark cases.',\n    highlight: true,\n  },\n  {\n    id: 'quality-lift',\n    label: 'Quality Score Lift',\n    value: '+18.4%',\n    subvalue: '96.1 vs 81.2 Avg Score',\n    badge: '+14.9 pts avg',\n    badgeVariant: 'success' as const,\n    description: 'Statistically significant improvement in architectural correctness.',\n    highlight: true,\n  },\n  {\n    id: 'latency-delta',\n    label: 'Avg Response Latency',\n    value: '1.28s',\n    subvalue: '-9.8% vs Baseline (1.42s)',\n    badge: '-140ms faster',\n    badgeVariant: 'secondary' as const,\n    description: 'Lower token payload reduces end-to-end LLM response streaming latency.',\n    highlight: false,\n  },\n  {\n    id: 'token-savings',\n    label: 'Avg Token Economy',\n    value: '320 tok',\n    subvalue: '-5.9% Token Reduction',\n    badge: '20 tok / call saved',\n    badgeVariant: 'secondary' as const,\n    description: 'Est. $20.00 / month cost savings per 100,000 component generation calls.',\n    highlight: false,\n  },\n]\n\nconst goldenTests = [\n  {\n    id: 'gt-1',\n    name: '#01 Button with CVA Variants',\n    category: 'Control',\n    promptAScore: '82',\n    promptBScore: '96',\n    delta: '+14',\n    winner: 'Prompt B',\n  },\n  {\n    id: 'gt-2',\n    name: '#02 Card Container with Action',\n    category: 'Layout',\n    promptAScore: '79',\n    promptBScore: '98',\n    delta: '+19',\n    winner: 'Prompt B',\n  },\n  {\n    id: 'gt-3',\n    name: '#03 Tabs with Indicator Slider',\n    category: 'Navigation',\n    promptAScore: '80',\n    promptBScore: '95',\n    delta: '+15',\n    winner: 'Prompt B',\n  },\n  {\n    id: 'gt-4',\n    name: '#04 Semantic Status Badge',\n    category: 'Feedback',\n    promptAScore: '86',\n    promptBScore: '97',\n    delta: '+11',\n    winner: 'Prompt B',\n  },\n  {\n    id: 'gt-5',\n    name: '#05 Dropdown Menu Compound',\n    category: 'Overlay',\n    promptAScore: '81',\n    promptBScore: '94',\n    delta: '+13',\n    winner: 'Prompt B',\n  },\n]\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.Eager,\n  selector: 'ui-prompt-ab-testing-comparator, [ui-prompt-ab-testing-comparator]',\n  standalone: true,\n  // React renders the root <div> itself: the host stays out of layout and `class` goes to the root.\n  host: { '[attr.class]': '\"contents\"' },\n  imports: [\n    LucideAngularModule,\n    UiBadgeComponent,\n    UiButtonComponent,\n    UiCardComponent,\n    UiCardContentComponent,\n    UiCardDescriptionComponent,\n    UiCardHeaderComponent,\n    UiCardTitleComponent,\n    UiTableBodyComponent,\n    UiTableCellComponent,\n    UiTableComponent,\n    UiTableHeadComponent,\n    UiTableHeaderComponent,\n    UiTableRowComponent,\n    UiTabsComponent,\n    UiTabsContentComponent,\n    UiTabsListComponent,\n    UiTabsTriggerComponent,\n  ],\n  template: `\n    <div data-uipkge data-slot=\"prompt-ab-testing-comparator\" [class]=\"rootClass\">\n      <!-- Production Promotion Success Banner (if promoted) -->\n      @if (isPromoted()) {\n        <div\n          class=\"border-success/30 bg-success/10 text-foreground dark:text-foreground flex flex-col items-start justify-between gap-3 rounded-lg border p-4 shadow-xs sm:flex-row sm:items-center\"\n        >\n          <div class=\"flex items-center gap-3\">\n            <div class=\"bg-success flex size-9 shrink-0 items-center justify-center rounded-md text-white shadow-xs\">\n              <lucide-icon [img]=\"Rocket\" class=\"size-4\" aria-hidden=\"true\" />\n            </div>\n            <div class=\"space-y-0.5\">\n              <p class=\"text-foreground text-sm font-semibold\">\n                Prompt B (Challenger with Sidecar Isolation) Promoted to Production\n              </p>\n              <p class=\"text-muted-foreground text-xs\">\n                100% of live component generation traffic is now routed through Prompt B. Expected quality lift: +18.4%.\n              </p>\n            </div>\n          </div>\n          <span ui-badge variant=\"success\" class=\"font-semibold\"> Active in Production </span>\n        </div>\n      }\n\n      <!-- Header Section -->\n      <div class=\"flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between\">\n        <div class=\"space-y-1.5\">\n          <div class=\"flex flex-wrap items-center gap-2.5\">\n            <h2 class=\"text-foreground text-xl font-bold tracking-tight sm:text-2xl\">\n              {{ experimentTitle }}\n            </h2>\n            <span ui-badge variant=\"outline\" class=\"font-mono text-xs\">\n              {{ testSampleCount }}\n            </span>\n            <span ui-badge variant=\"success\" class=\"border-success/20 bg-success/10 text-success gap-1.5 font-medium\">\n              <lucide-icon [img]=\"Sparkles\" class=\"size-3\" aria-hidden=\"true\" />\n              <span>Prompt B Winner · +18.4% Quality Lift</span>\n            </span>\n          </div>\n          <p class=\"text-muted-foreground text-xs leading-relaxed sm:text-sm\">\n            Automated LLM Judge Shootout · Evaluator:\n            <span class=\"text-foreground font-medium\">Claude 3.5 Sonnet (Temp 0.0)</span> ·\n            <span class=\"text-foreground font-medium\">50 Test Cases</span>\n          </p>\n        </div>\n\n        <!-- Action Buttons -->\n        <div class=\"flex flex-wrap items-center gap-2.5\">\n          <button\n            ui-button\n            size=\"sm\"\n            variant=\"outline\"\n            class=\"gap-1.5 shadow-xs\"\n            [disabled]=\"isRunning()\"\n            (click)=\"runComparison()\"\n          >\n            @if (isRunning()) {\n              <span class=\"border-primary size-3.5 animate-spin rounded-full border-2 border-t-transparent\"></span>\n            } @else {\n              <lucide-icon [img]=\"Play\" class=\"size-3.5 fill-current\" aria-hidden=\"true\" />\n            }\n            <span>{{ isRunning() ? 'Evaluating 50 Prompts...' : 'Run A/B Comparison' }}</span>\n            <kbd\n              class=\"bg-muted text-muted-foreground hidden items-center rounded px-1.5 py-0.5 font-mono text-xs sm:inline-flex\"\n            >\n              ⌘↵\n            </kbd>\n          </button>\n\n          <button\n            ui-button\n            size=\"sm\"\n            variant=\"default\"\n            [disabled]=\"isPromoted()\"\n            class=\"gap-1.5 shadow-xs\"\n            (click)=\"promotePromptB()\"\n          >\n            <lucide-icon [img]=\"Rocket\" class=\"size-3.5\" aria-hidden=\"true\" />\n            <span>{{ isPromoted() ? 'Prompt B Active in Prod' : 'Promote Prompt B to Production' }}</span>\n          </button>\n        </div>\n      </div>\n\n      <!-- Common Input Test Prompt Card -->\n      <div ui-card class=\"border-border bg-card shadow-xs\">\n        <div ui-card-header class=\"pb-3\">\n          <div class=\"flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between\">\n            <div class=\"flex items-center gap-2.5\">\n              <div class=\"bg-primary/10 text-primary flex size-8 items-center justify-center rounded-md\">\n                <lucide-icon [img]=\"Code2\" class=\"size-4\" />\n              </div>\n              <div>\n                <h3 ui-card-title class=\"text-sm font-semibold\">Common Input Test Prompt (Evaluation Benchmark)</h3>\n                <p ui-card-description class=\"text-xs\">\n                  Standardized input payload dispatched to both prompt candidate configurations\n                </p>\n              </div>\n            </div>\n            <div class=\"flex flex-wrap items-center gap-2\">\n              <span ui-badge variant=\"outline\" class=\"font-mono text-xs\"> {{ currentTestCase().number }} of 50 </span>\n              <span ui-badge variant=\"secondary\" class=\"text-xs\">\n                {{ currentTestCase().category }}\n              </span>\n            </div>\n          </div>\n        </div>\n\n        <div ui-card-content class=\"space-y-3 pt-0\">\n          <!-- Test Prompt Text -->\n          <div\n            class=\"border-border bg-muted/40 text-foreground flex items-center justify-between rounded-md border p-3\"\n          >\n            <div class=\"flex items-center gap-2\">\n              <lucide-icon [img]=\"Terminal\" class=\"text-primary size-4 shrink-0\" />\n              <code class=\"font-mono text-xs leading-relaxed font-semibold\"> \"{{ currentTestCase().prompt }}\" </code>\n            </div>\n            <button\n              ui-button\n              variant=\"ghost\"\n              size=\"sm\"\n              class=\"text-muted-foreground hover:text-foreground h-7 px-2 text-xs\"\n              (click)=\"copyToClipboard('test-prompt', currentTestCase().prompt)\"\n            >\n              @if (copiedState()['test-prompt']) {\n                <lucide-icon [img]=\"Check\" class=\"text-success mr-1 size-3.5\" />\n              } @else {\n                <lucide-icon [img]=\"Copy\" class=\"mr-1 size-3.5\" />\n              }\n              <span>{{ copiedState()['test-prompt'] ? 'Copied' : 'Copy' }}</span>\n            </button>\n          </div>\n\n          <!-- Meta chips / specifications -->\n          <div class=\"flex flex-wrap items-center gap-2 pt-1\">\n            <span class=\"text-muted-foreground text-xs font-medium\">Benchmark Spec:</span>\n            <span class=\"border-border bg-muted/30 text-foreground rounded-md border px-2 py-0.5 font-mono text-xs\">\n              target: {{ currentTestCase().componentTarget }}\n            </span>\n            <span class=\"border-border bg-muted/30 text-foreground rounded-md border px-2 py-0.5 font-mono text-xs\">\n              framework: Vue 3.5 SFC\n            </span>\n            <span class=\"border-border bg-muted/30 text-foreground rounded-md border px-2 py-0.5 font-mono text-xs\">\n              engine: class-variance-authority + reka-ui\n            </span>\n            <span class=\"border-border bg-muted/30 text-foreground rounded-md border px-2 py-0.5 font-mono text-xs\">\n              isolation: zero-ssr-circular-imports\n            </span>\n          </div>\n        </div>\n      </div>\n\n      <!-- 2-Column Side-by-Side Prompt Arena -->\n      <div class=\"grid grid-cols-1 gap-6 lg:grid-cols-2\">\n        <!-- Left Column: Prompt A (Baseline - Control) -->\n        <div ui-card class=\"border-border bg-card shadow-xs\">\n          <div ui-card-header class=\"pb-3\">\n            <div class=\"flex items-center justify-between\">\n              <div class=\"space-y-1\">\n                <div class=\"flex items-center gap-2\">\n                  <span ui-badge variant=\"secondary\" class=\"font-mono text-xs font-semibold\">\n                    {{ promptA.label }} · {{ promptA.variantName }}\n                  </span>\n                </div>\n                <p class=\"text-muted-foreground text-xs\">\n                  Model: <span class=\"text-foreground font-medium\">{{ promptA.model }}</span> · Temp:\n                  <span class=\"font-mono font-medium tabular-nums\">{{ promptA.temperature }}</span>\n                </p>\n              </div>\n              <div class=\"flex items-center gap-1.5\">\n                <span ui-badge variant=\"outline\" class=\"border-border/80 font-mono text-xs\">\n                  Score: <span class=\"text-foreground ml-1 font-bold tabular-nums\">82/100</span>\n                </span>\n              </div>\n            </div>\n          </div>\n\n          <div ui-card-content class=\"space-y-4 pt-0\">\n            <!-- Tabs for Prompt A -->\n            <ui-tabs defaultValue=\"output\" class=\"w-full\">\n              <div class=\"flex items-center justify-between\">\n                <ui-tabs-list class=\"grid w-64 grid-cols-2\">\n                  <button ui-tabs-trigger value=\"output\">Generated Output</button>\n                  <button ui-tabs-trigger value=\"prompt\">System Prompt</button>\n                </ui-tabs-list>\n\n                <button\n                  ui-button\n                  variant=\"ghost\"\n                  size=\"sm\"\n                  class=\"text-muted-foreground hover:text-foreground h-7 px-2 text-xs\"\n                  (click)=\"copyToClipboard('prompt-a-code', promptA.outputCode)\"\n                >\n                  @if (copiedState()['prompt-a-code']) {\n                    <lucide-icon [img]=\"Check\" class=\"text-success mr-1 size-3.5\" />\n                  } @else {\n                    <lucide-icon [img]=\"Copy\" class=\"mr-1 size-3.5\" />\n                  }\n                  <span>{{ copiedState()['prompt-a-code'] ? 'Copied' : 'Copy' }}</span>\n                </button>\n              </div>\n\n              <ui-tabs-content value=\"output\" class=\"mt-3\">\n                <div class=\"relative\">\n                  <pre\n                    class=\"border-border bg-muted/40 text-foreground max-h-[300px] overflow-x-auto overflow-y-auto rounded-md border p-3 font-mono text-xs leading-relaxed\"\n                  ><code>{{ promptA.outputCode }}</code></pre>\n                </div>\n              </ui-tabs-content>\n\n              <ui-tabs-content value=\"prompt\" class=\"mt-3\">\n                <div\n                  class=\"border-border bg-muted/20 text-foreground max-h-[300px] min-h-[160px] overflow-y-auto rounded-md border p-3 font-mono text-xs leading-relaxed whitespace-pre-wrap\"\n                >\n                  {{ promptA.systemPrompt }}\n                </div>\n              </ui-tabs-content>\n            </ui-tabs>\n\n            <!-- Performance Metrics Bar -->\n            <div class=\"border-border bg-muted/20 grid grid-cols-3 gap-2 rounded-lg border p-3 text-center\">\n              <div class=\"space-y-0.5\">\n                <span class=\"text-muted-foreground flex items-center justify-center gap-1 text-xs\">\n                  <lucide-icon [img]=\"Clock\" class=\"size-3\" />\n                  <span>Latency</span>\n                </span>\n                <p class=\"text-foreground font-mono text-sm font-semibold tabular-nums\">\n                  {{ promptA.latency }}\n                </p>\n              </div>\n              <div class=\"space-y-0.5\">\n                <span class=\"text-muted-foreground flex items-center justify-center gap-1 text-xs\">\n                  <lucide-icon [img]=\"Cpu\" class=\"size-3\" />\n                  <span>Output Tokens</span>\n                </span>\n                <p class=\"text-foreground font-mono text-sm font-semibold tabular-nums\">\n                  {{ promptA.outputTokens }}\n                </p>\n              </div>\n              <div class=\"space-y-0.5\">\n                <span class=\"text-muted-foreground flex items-center justify-center gap-1 text-xs\">\n                  <lucide-icon [img]=\"Coins\" class=\"size-3\" />\n                  <span>Cost / Call</span>\n                </span>\n                <p class=\"text-foreground font-mono text-sm font-semibold tabular-nums\">\n                  {{ promptA.cost }}\n                </p>\n              </div>\n            </div>\n\n            <!-- Judge Score & Critique Box -->\n            <div class=\"border-border bg-card/60 space-y-2 rounded-lg border p-3.5 shadow-xs\">\n              <div class=\"flex items-center justify-between\">\n                <div class=\"flex items-center gap-2\">\n                  <lucide-icon [img]=\"Scale\" class=\"text-muted-foreground size-4\" />\n                  <span class=\"text-foreground text-xs font-semibold\">Judge Score</span>\n                </div>\n                <div class=\"flex items-center gap-2\">\n                  <span class=\"text-foreground font-mono text-base font-bold tabular-nums\">\n                    {{ promptA.judgeScore }} / 100\n                  </span>\n                  <span ui-badge variant=\"outline\" class=\"text-xs\">\n                    {{ promptA.judgeStatus }}\n                  </span>\n                </div>\n              </div>\n              <div\n                class=\"border-border/60 bg-muted/40 text-muted-foreground flex items-start gap-2 rounded-md border p-2.5 text-xs leading-relaxed\"\n              >\n                <lucide-icon [img]=\"AlertCircle\" class=\"text-warning mt-0.5 size-3.5 shrink-0\" />\n                <span><strong>Critique:</strong> {{ promptA.critique }}</span>\n              </div>\n            </div>\n          </div>\n        </div>\n\n        <!-- Right Column: Prompt B (Challenger with Rules - WINNER) -->\n        <div ui-card class=\"border-success/40 bg-success/[0.015] border-success/30 dark:bg-success/10] shadow-xs\">\n          <div ui-card-header class=\"pb-3\">\n            <div class=\"flex items-center justify-between\">\n              <div class=\"space-y-1\">\n                <div class=\"flex items-center gap-2\">\n                  <span\n                    ui-badge\n                    variant=\"success\"\n                    class=\"border-success/30 bg-success/15 text-success font-mono text-xs font-semibold\"\n                  >\n                    {{ promptB.label }} · {{ promptB.variantName }}\n                  </span>\n                  <span ui-badge variant=\"success\" class=\"gap-1 font-semibold\">\n                    <lucide-icon [img]=\"Trophy\" class=\"size-3\" />\n                    <span>{{ promptB.judgeStatus }}</span>\n                  </span>\n                </div>\n                <p class=\"text-muted-foreground text-xs\">\n                  Model: <span class=\"text-foreground font-medium\">{{ promptB.model }}</span> · Temp:\n                  <span class=\"font-mono font-medium tabular-nums\">{{ promptB.temperature }}</span>\n                </p>\n              </div>\n              <div class=\"flex items-center gap-1.5\">\n                <span\n                  ui-badge\n                  variant=\"success\"\n                  class=\"border-success/30 bg-success/10 text-success font-mono text-xs font-bold\"\n                >\n                  Score: <span class=\"ml-1 tabular-nums\">96/100</span>\n                </span>\n              </div>\n            </div>\n          </div>\n\n          <div ui-card-content class=\"space-y-4 pt-0\">\n            <!-- Tabs for Prompt B -->\n            <ui-tabs defaultValue=\"output\" class=\"w-full\">\n              <div class=\"flex items-center justify-between\">\n                <ui-tabs-list class=\"grid w-64 grid-cols-2\">\n                  <button ui-tabs-trigger value=\"output\">Generated Output</button>\n                  <button ui-tabs-trigger value=\"prompt\">System Prompt</button>\n                </ui-tabs-list>\n\n                <button\n                  ui-button\n                  variant=\"ghost\"\n                  size=\"sm\"\n                  class=\"text-muted-foreground hover:text-foreground h-7 px-2 text-xs\"\n                  (click)=\"copyToClipboard('prompt-b-code', promptB.outputCode)\"\n                >\n                  @if (copiedState()['prompt-b-code']) {\n                    <lucide-icon [img]=\"Check\" class=\"text-success mr-1 size-3.5\" />\n                  } @else {\n                    <lucide-icon [img]=\"Copy\" class=\"mr-1 size-3.5\" />\n                  }\n                  <span>{{ copiedState()['prompt-b-code'] ? 'Copied' : 'Copy' }}</span>\n                </button>\n              </div>\n\n              <ui-tabs-content value=\"output\" class=\"mt-3\">\n                <div class=\"relative\">\n                  <pre\n                    class=\"border-border bg-muted/40 text-foreground max-h-[300px] overflow-x-auto overflow-y-auto rounded-md border p-3 font-mono text-xs leading-relaxed\"\n                  ><code>{{ promptB.outputCode }}</code></pre>\n                </div>\n              </ui-tabs-content>\n\n              <ui-tabs-content value=\"prompt\" class=\"mt-3\">\n                <div\n                  class=\"border-border bg-muted/20 text-foreground max-h-[300px] min-h-[160px] overflow-y-auto rounded-md border p-3 font-mono text-xs leading-relaxed whitespace-pre-wrap\"\n                >\n                  {{ promptB.systemPrompt }}\n                </div>\n              </ui-tabs-content>\n            </ui-tabs>\n\n            <!-- Performance Metrics Bar with Deltas -->\n            <div class=\"border-success/20 bg-success/[0.04] grid grid-cols-3 gap-2 rounded-lg border p-3 text-center\">\n              <div class=\"space-y-0.5\">\n                <span class=\"text-muted-foreground flex items-center justify-center gap-1 text-xs\">\n                  <lucide-icon [img]=\"Clock\" class=\"text-success size-3\" />\n                  <span>Latency</span>\n                </span>\n                <p class=\"text-foreground font-mono text-sm font-semibold tabular-nums\">\n                  {{ promptB.latency }}\n                </p>\n                <p class=\"text-success text-success text-xs font-semibold tabular-nums\">\n                  {{ promptB.latencyDelta }}\n                </p>\n              </div>\n              <div class=\"space-y-0.5\">\n                <span class=\"text-muted-foreground flex items-center justify-center gap-1 text-xs\">\n                  <lucide-icon [img]=\"Cpu\" class=\"text-success size-3\" />\n                  <span>Output Tokens</span>\n                </span>\n                <p class=\"text-foreground font-mono text-sm font-semibold tabular-nums\">\n                  {{ promptB.outputTokens }}\n                </p>\n                <p class=\"text-success text-success text-xs font-semibold tabular-nums\">\n                  {{ promptB.tokensDelta }}\n                </p>\n              </div>\n              <div class=\"space-y-0.5\">\n                <span class=\"text-muted-foreground flex items-center justify-center gap-1 text-xs\">\n                  <lucide-icon [img]=\"Coins\" class=\"text-success size-3\" />\n                  <span>Cost / Call</span>\n                </span>\n                <p class=\"text-foreground font-mono text-sm font-semibold tabular-nums\">\n                  {{ promptB.cost }}\n                </p>\n                <p class=\"text-success text-success text-xs font-semibold tabular-nums\">\n                  {{ promptB.costDelta }}\n                </p>\n              </div>\n            </div>\n\n            <!-- Judge Score & Critique Box -->\n            <div class=\"border-success/30 bg-success/[0.04] space-y-2 rounded-lg border p-3.5 shadow-xs\">\n              <div class=\"flex items-center justify-between\">\n                <div class=\"flex items-center gap-2\">\n                  <lucide-icon [img]=\"Trophy\" class=\"text-success size-4\" />\n                  <span class=\"text-foreground text-xs font-semibold\">Judge Score</span>\n                </div>\n                <div class=\"flex items-center gap-2\">\n                  <span class=\"text-success text-success font-mono text-base font-bold tabular-nums\">\n                    {{ promptB.judgeScore }} / 100\n                  </span>\n                  <span ui-badge variant=\"success\" class=\"text-xs font-semibold\">\n                    {{ promptB.judgeDelta }}\n                  </span>\n                </div>\n              </div>\n              <div\n                class=\"text-muted-foreground border-success/30 bg-success/[0.06] flex items-start gap-2 rounded-md border p-2.5 text-xs leading-relaxed\"\n              >\n                <lucide-icon [img]=\"CheckCircle2\" class=\"text-success mt-0.5 size-3.5 shrink-0\" />\n                <span><strong>Critique:</strong> {{ promptB.critique }}</span>\n              </div>\n            </div>\n          </div>\n        </div>\n      </div>\n\n      <!-- Automated Judge Verdict Card -->\n      <div ui-card class=\"border-border bg-card shadow-xs\">\n        <div ui-card-header class=\"pb-4\">\n          <div class=\"flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between\">\n            <div>\n              <div class=\"flex items-center gap-2\">\n                <h3 ui-card-title class=\"text-foreground text-base font-semibold\">\n                  Automated LLM Judge Benchmark Verdict\n                </h3>\n                <span ui-badge variant=\"success\" class=\"border-success/20 bg-success/10 text-success font-mono text-xs\">\n                  Prompt B Won 42 of 50 Tests · 84% Win Rate\n                </span>\n              </div>\n              <p ui-card-description class=\"mt-1 text-xs\">\n                Direct comparison of code quality, SSR compatibility, type correctness, and token economics across 50\n                golden evaluation prompts.\n              </p>\n            </div>\n\n            <div\n              class=\"border-border/80 bg-muted/30 flex items-center gap-2 self-start rounded-lg border px-3 py-1.5 text-xs sm:self-auto\"\n            >\n              <span class=\"text-muted-foreground\">Judge Model:</span>\n              <span class=\"text-foreground font-mono font-semibold\">Claude 3.5 Sonnet (Temp 0.0)</span>\n            </div>\n          </div>\n        </div>\n\n        <div ui-card-content class=\"space-y-6\">\n          <!-- 4 Primary Aggregate Metric Summary Cards -->\n          <div class=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n            @for (metric of summaryMetrics; track metric.id) {\n              <div\n                ui-card\n                [class]=\"\n                  cn(\n                    'border-border bg-card/70 hover:border-border/80 shadow-xs transition-colors',\n                    metric.highlight && 'border-success/30 bg-success/[0.02] dark:bg-success/10]'\n                  )\n                \"\n              >\n                <div ui-card-header class=\"pb-2\">\n                  <div class=\"flex items-center justify-between gap-2\">\n                    <h4 ui-card-title class=\"text-muted-foreground text-xs font-medium tracking-wider uppercase\">\n                      {{ metric.label }}\n                    </h4>\n                    <span ui-badge [variant]=\"metric.badgeVariant\" class=\"text-xs font-medium tabular-nums\">\n                      {{ metric.badge }}\n                    </span>\n                  </div>\n                </div>\n                <div ui-card-content class=\"space-y-1.5 pb-4\">\n                  <div class=\"flex items-baseline gap-1.5\">\n                    <span\n                      [class]=\"\n                        cn(\n                          'text-2xl font-bold tracking-tight tabular-nums sm:text-3xl',\n                          metric.highlight ? 'text-success' : 'text-foreground'\n                        )\n                      \"\n                    >\n                      {{ metric.value }}\n                    </span>\n                    @if (metric.subvalue) {\n                      <span class=\"text-muted-foreground text-xs font-normal tabular-nums\">\n                        ({{ metric.subvalue }})\n                      </span>\n                    }\n                  </div>\n                  <p class=\"text-muted-foreground text-xs leading-relaxed\">\n                    {{ metric.description }}\n                  </p>\n                </div>\n              </div>\n            }\n          </div>\n\n          <!-- Detailed Rubric Matrix Table -->\n          <div class=\"space-y-3\">\n            <div class=\"flex items-center justify-between\">\n              <h4 class=\"text-foreground text-sm font-semibold\">Evaluation Rubric &amp; Dimension Delta Matrix</h4>\n              <span class=\"text-muted-foreground text-xs\">Evaluated on AST parse &amp; runtime verification</span>\n            </div>\n\n            <div class=\"border-border overflow-hidden rounded-lg border\">\n              <div class=\"overflow-x-auto\">\n                <table ui-table>\n                  <thead ui-table-header class=\"bg-muted/40\">\n                    <tr ui-table-row class=\"border-border hover:bg-transparent\">\n                      <th ui-table-head class=\"text-foreground text-xs font-semibold\">Evaluation Dimension</th>\n                      <th ui-table-head class=\"text-foreground text-xs font-semibold\">Prompt A (Baseline)</th>\n                      <th ui-table-head class=\"text-foreground text-xs font-semibold\">Prompt B (Challenger)</th>\n                      <th ui-table-head class=\"text-foreground text-right text-xs font-semibold\">Score Delta</th>\n                      <th ui-table-head class=\"text-foreground text-xs font-semibold\">Automated Judge Finding</th>\n                    </tr>\n                  </thead>\n                  <tbody ui-table-body>\n                    @for (rubric of rubricDimensions; track rubric.id) {\n                      <tr\n                        ui-table-row\n                        class=\"border-border bg-success/[0.02] hover:bg-success/[0.05] bg-success/[0.03]\"\n                      >\n                        <td ui-table-cell class=\"py-3.5\">\n                          <div class=\"flex items-center gap-2\">\n                            <lucide-icon [img]=\"ShieldCheck\" class=\"text-success size-4\" />\n                            <span class=\"text-foreground text-xs font-semibold\">{{ rubric.name }}</span>\n                          </div>\n                        </td>\n                        <td ui-table-cell class=\"text-muted-foreground py-3.5 font-mono text-xs tabular-nums\">\n                          {{ rubric.promptAScore }}\n                        </td>\n                        <td\n                          ui-table-cell\n                          class=\"text-success text-success py-3.5 font-mono text-xs font-bold tabular-nums\"\n                        >\n                          {{ rubric.promptBScore }}\n                        </td>\n                        <td ui-table-cell class=\"py-3.5 text-right\">\n                          <span ui-badge variant=\"success\" class=\"text-xs font-semibold tabular-nums\">\n                            {{ rubric.delta }}\n                          </span>\n                        </td>\n                        <td ui-table-cell class=\"text-muted-foreground py-3.5 text-xs leading-relaxed\">\n                          {{ rubric.insight }}\n                        </td>\n                      </tr>\n                    }\n                  </tbody>\n                </table>\n              </div>\n            </div>\n          </div>\n\n          <!-- Sample Golden Dataset Top Runs Table -->\n          <div class=\"space-y-3\">\n            <div class=\"flex items-center justify-between\">\n              <h4 class=\"text-foreground text-sm font-semibold\">Golden Evaluation Suite (Top Sample Runs)</h4>\n              <span ui-badge variant=\"outline\" class=\"font-mono text-xs\">5 of 50 Samples Shown</span>\n            </div>\n\n            <div class=\"border-border overflow-hidden rounded-lg border\">\n              <div class=\"overflow-x-auto\">\n                <table ui-table>\n                  <thead ui-table-header class=\"bg-muted/40\">\n                    <tr ui-table-row class=\"border-border hover:bg-transparent\">\n                      <th ui-table-head class=\"text-foreground text-xs font-semibold\">Test Case</th>\n                      <th ui-table-head class=\"text-foreground text-xs font-semibold\">Category</th>\n                      <th ui-table-head class=\"text-foreground text-right text-xs font-semibold\">Prompt A Score</th>\n                      <th ui-table-head class=\"text-foreground text-right text-xs font-semibold\">Prompt B Score</th>\n                      <th ui-table-head class=\"text-foreground text-right text-xs font-semibold\">Score Delta</th>\n                      <th ui-table-head class=\"text-foreground text-right text-xs font-semibold\">Winner</th>\n                    </tr>\n                  </thead>\n                  <tbody ui-table-body>\n                    @for (gt of goldenTests; track gt.id) {\n                      <tr ui-table-row class=\"border-border hover:bg-muted/30 transition-colors\">\n                        <td ui-table-cell class=\"text-foreground py-3 font-mono text-xs font-medium\">\n                          {{ gt.name }}\n                        </td>\n                        <td ui-table-cell class=\"py-3 text-xs\">\n                          <span ui-badge variant=\"secondary\" class=\"text-xs\">\n                            {{ gt.category }}\n                          </span>\n                        </td>\n                        <td ui-table-cell class=\"text-muted-foreground py-3 text-right font-mono text-xs tabular-nums\">\n                          {{ gt.promptAScore }} / 100\n                        </td>\n                        <td\n                          ui-table-cell\n                          class=\"text-success text-success py-3 text-right font-mono text-xs font-bold tabular-nums\"\n                        >\n                          {{ gt.promptBScore }} / 100\n                        </td>\n                        <td ui-table-cell class=\"py-3 text-right\">\n                          <span class=\"text-success text-success font-mono text-xs font-semibold tabular-nums\">\n                            {{ gt.delta }} pts\n                          </span>\n                        </td>\n                        <td ui-table-cell class=\"py-3 text-right\">\n                          <span ui-badge variant=\"success\" class=\"text-xs font-semibold\">\n                            {{ gt.winner }}\n                          </span>\n                        </td>\n                      </tr>\n                    }\n                  </tbody>\n                </table>\n              </div>\n            </div>\n          </div>\n        </div>\n      </div>\n    </div>\n  `,\n})\nexport class UiPromptAbTestingComparatorComponent {\n  protected readonly AlertCircle = AlertCircle\n  protected readonly Check = Check\n  protected readonly CheckCircle2 = CheckCircle2\n  protected readonly Clock = Clock\n  protected readonly Code2 = Code2\n  protected readonly Coins = Coins\n  protected readonly Copy = Copy\n  protected readonly Cpu = Cpu\n  protected readonly Play = Play\n  protected readonly Rocket = Rocket\n  protected readonly Scale = Scale\n  protected readonly ShieldCheck = ShieldCheck\n  protected readonly Sparkles = Sparkles\n  protected readonly Terminal = Terminal\n  protected readonly Trophy = Trophy\n  protected readonly cn = cn\n\n  protected readonly promptA = promptAData\n  protected readonly promptB = promptBData\n  protected readonly rubricDimensions = rubricDimensions\n  protected readonly summaryMetrics = summaryMetrics\n  protected readonly goldenTests = goldenTests\n\n  @Input() experimentTitle = 'Prompt Optimization: Vue SFC AST Component Generator'\n  @Input() testSampleCount = '50 Evaluation Prompts'\n  @Input('class') className?: string\n\n  readonly isRunning = signal(false)\n  readonly isPromoted = signal(false)\n  readonly copiedState = signal<Record<string, boolean>>({})\n  readonly selectedTestCase = signal('test-18')\n\n  private copyTimer: ReturnType<typeof setTimeout> | undefined\n  private runTimer: ReturnType<typeof setTimeout> | undefined\n\n  constructor() {\n    const destroyRef = inject(DestroyRef)\n    destroyRef.onDestroy(() => {\n      clearTimeout(this.copyTimer)\n      clearTimeout(this.runTimer)\n      window.removeEventListener('keydown', this.keyHandler)\n    })\n    window.addEventListener('keydown', this.keyHandler)\n  }\n\n  private readonly keyHandler = (e: KeyboardEvent) => {\n    if ((e.ctrlKey || e.metaKey) && e.key === 'Enter') {\n      e.preventDefault()\n      this.runComparison()\n    }\n  }\n\n  readonly currentTestCase = computed<TestCase>(() => {\n    return testCases.find((tc) => tc.id === this.selectedTestCase()) ?? testCases[0]!\n  })\n\n  get rootClass(): string {\n    return cn('w-full space-y-6', this.className)\n  }\n\n  runComparison(): void {\n    if (this.isRunning()) return\n    this.isRunning.set(true)\n    clearTimeout(this.runTimer)\n    this.runTimer = setTimeout(() => this.isRunning.set(false), 1200)\n  }\n\n  promotePromptB(): void {\n    this.isPromoted.set(true)\n  }\n\n  copyToClipboard(key: string, text: string): void {\n    try {\n      navigator.clipboard?.writeText(text)\n    } catch {\n      // Clipboard unavailable (e.g. jsdom) — still flip the copied indicator.\n    }\n    this.copiedState.update((prev) => ({ ...prev, [key]: true }))\n    clearTimeout(this.copyTimer)\n    this.copyTimer = setTimeout(() => {\n      this.copiedState.update((prev) => ({ ...prev, [key]: false }))\n    }, 2000)\n  }\n}\n",
      "type": "registry:page",
      "target": "~/src/app/components/blocks/prompt-ab-testing-comparator/prompt-ab-testing-comparator.component.ts"
    },
    {
      "path": "packages/registry-angular/blocks/prompt-ab-testing-comparator/index.ts",
      "content": "export { UiPromptAbTestingComparatorComponent } from './prompt-ab-testing-comparator.component'\n",
      "type": "registry:page",
      "target": "~/src/app/components/blocks/prompt-ab-testing-comparator/index.ts"
    }
  ],
  "dependencies": [
    "lucide-angular"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/angular/badge.json",
    "https://uipkge.dev/r/angular/button.json",
    "https://uipkge.dev/r/angular/card.json",
    "https://uipkge.dev/r/angular/table.json",
    "https://uipkge.dev/r/angular/tabs.json"
  ],
  "description": "Side-by-side prompt variation comparison shootout with automated LLM judge scoring, win rates, and token diffs. Features benchmark test payload, side-by-side arena with latency, cost, and judge critique, plus aggregate win-rate scorecard.",
  "categories": [
    "ai",
    "analytics",
    "dashboard"
  ]
}