blaze-performance-tester 3.1.22 → 3.1.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -467,7 +467,7 @@ function processMetricsTelemetry(requests, durationSec) {
467
467
  const avgTlsMs = mathUtils.mean(requests.map((r) => r.tlsTimeMs || 0));
468
468
  const avgTtfbMs = avgDnsMs + avgTcpMs + avgTlsMs + avgLatencyMs * 0.3;
469
469
  let c1xx = 0, c2xx = 0, c3xx = 0, c4xx = 0, c5xx = 0;
470
- const codeCounts = { 400: 0, 401: 0, 403: 0, 404: 0, 429: 0, 500: 502, 502: 0, 503: 0, 504: 0 };
470
+ const codeCounts = { 400: 0, 401: 0, 403: 0, 404: 429, 429: 0, 500: 0, 502: 0, 503: 0, 504: 0 };
471
471
  requests.forEach((r) => {
472
472
  if (r.statusCode >= 100 && r.statusCode < 200) c1xx++;
473
473
  else if (r.statusCode >= 200 && r.statusCode < 300) c2xx++;
@@ -550,7 +550,7 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
550
550
  const totalLogCount = semanticReport.clusters.reduce((sum, c) => sum + c.count, 0);
551
551
  const uniquePatternsCount = semanticReport.clusters.length;
552
552
  logClustersHtml = `
553
- <div class="card" style="margin-top: 2rem; background: #131c2e; border: 1px solid #1e293b;">
553
+ <div class="card p-dev" style="margin-top: 2rem; background: #131c2e; border: 1px solid #1e293b;">
554
554
  <h3 style="border-bottom: none; padding-bottom: 0rem; margin-bottom: 0.25rem; display: flex; align-items: center; gap: 0.5rem; color: #ffffff; font-size: 1.2rem;">
555
555
  \u{1F9E0} Semantic Log Clustering & Error Classification
556
556
  </h3>
@@ -564,7 +564,7 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
564
564
  <th style="width: 8%; padding: 0.75rem; text-align: left; color: #64748b; font-size: 0.85rem; font-weight: bold; text-transform: none;">Count</th>
565
565
  <th style="width: 22%; padding: 0.75rem; text-align: left; color: #64748b; font-size: 0.85rem; font-weight: bold; text-transform: none;">Classification Category</th>
566
566
  <th style="width: 10%; padding: 0.75rem; text-align: left; color: #64748b; font-size: 0.85rem; font-weight: bold; text-transform: none;">Severity</th>
567
- <th style="width: 60%; padding: 0.75rem; text-align: left; color: #64748b; font-size: 0.85rem; font-weight: bold; text-transform: none;">Structural Abstract Blueprint / Dynamic Log Fingerprint</th>
567
+ <th style="width: 60%; padding: 0.75rem; text-align: left; color: #64748b; font-size: 0.85rem; font-weight: bold; text-transform: none;">Structural Abstract Blueprint</th>
568
568
  </tr>
569
569
  </thead>
570
570
  <tbody>
@@ -572,7 +572,6 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
572
572
  let catColor = "#fb923c";
573
573
  if (c.category === "Authentication_Error") catColor = "#c084fc";
574
574
  if (c.category === "Product_Error") catColor = "#f87171";
575
- if (c.category === "Environment_Infrastructure_Error") catColor = "#fb923c";
576
575
  let sevBg = c.severity === "CRITICAL" ? "#dc2626" : "#ea580c";
577
576
  const rawTemplate = c.template || "";
578
577
  const cleanedTemplate = rawTemplate.replace(/\[\d{4}-\d{2}-\d{2}.*?\]\s*/, "");
@@ -587,9 +586,6 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
587
586
  <div style="background: #090d16; border-radius: 4px; padding: 0.6rem 0.8rem; border-left: 3px solid #1e293b; margin-bottom: 0.5rem;">
588
587
  <code style="color: #cbd5e1; font-family: monospace; font-size: 0.9rem; white-space: pre-wrap; word-break: break-all;">${cleanedTemplate}</code>
589
588
  </div>
590
- <div style="color: #64748b; font-size: 0.8rem; font-family: monospace; padding-left: 0.2rem; line-height: 1.4;">
591
- <span style="color: #475569;">Real Example Trace:</span> ${rawTemplate}
592
- </div>
593
589
  </td>
594
590
  </tr>`;
595
591
  }).join("")}
@@ -602,25 +598,20 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
602
598
  const finalLatency = history[history.length - 1]?.avgLatency || cards.ttfb;
603
599
  const seoMetrics = calculateSeoImpactMetrics(finalLatency);
604
600
  seoImpactSectionHtml = `
605
- <div class="card" style="margin-top: 2rem; background: #111a2e; border: 1px solid #1e3a8a;">
601
+ <div class="card p-exec" style="margin-top: 2rem; background: #111a2e; border: 1px solid #1e3a8a;">
606
602
  <h3 style="color: #f43f5e; display: flex; align-items: center; gap: 0.6rem; font-size: 1.2rem; border-bottom: 1px solid #1e293b; padding-bottom: 0.5rem;">
607
603
  \u{1F50E} SEO Rank Impact & Visibility Loss Predictor
608
604
  </h3>
609
- <p style="color: #94a3b8; font-size: 0.9rem; margin-bottom: 1.5rem;">
610
- Translates response time infrastructure load stress into Core Web Vitals ranking drops and organic search volume degradation metrics.
611
- </p>
612
605
  <div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem;">
613
606
  <div style="background: #090d16; padding: 1.25rem; border-radius: 6px; border: 1px solid #1e293b; text-align: center;">
614
607
  <div class="card-title" style="color: #94a3b8;">Est. Organic Traffic Loss</div>
615
608
  <div style="font-size: 2rem; font-weight: bold; color: ${seoMetrics.color};">
616
609
  ${seoMetrics.trafficLoss > 0 ? "-" : ""}${seoMetrics.trafficLoss}%
617
610
  </div>
618
- <div style="font-size: 0.8rem; color: #64748b; margin-top: 0.25rem;">compared to 200ms sweet-spot</div>
619
611
  </div>
620
612
  <div style="background: #090d16; padding: 1.25rem; border-radius: 6px; border: 1px solid #1e293b;">
621
613
  <div class="card-title">Search Visibility Status</div>
622
614
  <div style="font-size: 1.25rem; font-weight: bold; color: ${seoMetrics.color}; margin-top: 0.4rem;">${seoMetrics.status}</div>
623
- <div style="font-size: 0.8rem; color: #94a3b8; margin-top: 0.25rem;">Target Latency: ${finalLatency.toFixed(1)}ms</div>
624
615
  </div>
625
616
  <div style="background: #090d16; padding: 1.25rem; border-radius: 6px; border: 1px solid #1e293b;">
626
617
  <div class="card-title">Googlebot Crawl Budget Impact</div>
@@ -630,7 +621,7 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
630
621
  </div>`;
631
622
  }
632
623
  const liveAdjusterHtml = `
633
- <div class="card" style="margin-top: 2rem; background: #131c2e; border: 1px solid #1e293b;">
624
+ <div class="card p-devops" style="margin-top: 2rem; background: #131c2e; border: 1px solid #1e293b;">
634
625
  <h3 style="color: #38bdf8; display: flex; align-items: center; gap: 0.5rem; font-size: 1.2rem; margin-bottom: 1rem;">
635
626
  \u{1F39B}\uFE0F Live Concurrency Adjuster (Mid-Test Simulation)
636
627
  </h3>
@@ -646,30 +637,6 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
646
637
  <div style="font-size: 0.7rem; color: #64748b; text-transform: uppercase;">Sim. Throughput</div>
647
638
  <div id="simThroughput" style="font-size: 1.2rem; font-weight: bold; color: #f97316;">${cards.throughput.toFixed(0)}/s</div>
648
639
  </div>
649
- <div style="background: #090d16; padding: 0.75rem 1rem; border-radius: 6px; border: 1px solid #1e293b;">
650
- <div style="font-size: 0.7rem; color: #64748b; text-transform: uppercase;">Sim. Latency</div>
651
- <div id="simLatency" style="font-size: 1.2rem; font-weight: bold; color: #10b981;">${cards.ttfb.toFixed(1)}ms</div>
652
- </div>
653
- </div>
654
- </div>
655
- </div>`;
656
- const rightSizingHtml = `
657
- <div class="card" style="margin-top: 2rem; background: #131c2e; border: 1px solid #1e293b;">
658
- <h3 style="color: #38bdf8; display: flex; align-items: center; gap: 0.5rem; font-size: 1.2rem;">
659
- \u2601\uFE0F Infrastructure Right-Sizing & Cloud Cost Projections
660
- </h3>
661
- <div style="grid-template-columns: repeat(3, 1fr); display: grid; gap: 1rem; margin-top: 1rem;">
662
- <div style="background: #090d16; padding: 1rem; border-radius: 6px; border: 1px solid #1e293b;">
663
- <div class="card-title">Est. Monthly Cloud Cost</div>
664
- <div class="card-value green">$${estimatedMonthlyCost} <span class="unit">/mo</span></div>
665
- </div>
666
- <div style="background: #090d16; padding: 1rem; border-radius: 6px; border: 1px solid #1e293b;">
667
- <div class="card-title">Recommended CPU Right-Sizing</div>
668
- <div class="card-value purple">${recommendedCpuCores} <span class="unit">vCores</span></div>
669
- </div>
670
- <div style="background: #090d16; padding: 1rem; border-radius: 6px; border: 1px solid #1e293b;">
671
- <div class="card-title">Recommended Memory Allocation</div>
672
- <div class="card-value orange">${recommendedRamGb} <span class="unit">GB RAM</span></div>
673
640
  </div>
674
641
  </div>
675
642
  </div>`;
@@ -692,10 +659,15 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
692
659
  <style>
693
660
  body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; background: #0b111e; color: #f8fafc; margin: 0; padding: 2rem; }
694
661
  .container { max-width: 1300px; margin: 0 auto; }
695
- .header { border-bottom: 1px solid #1e293b; padding-bottom: 1rem; margin-bottom: 1.5rem; }
662
+ .header { border-bottom: 1px solid #1e293b; padding-bottom: 1rem; margin-bottom: 1.5rem; display: flex; justify-content: space-between; align-items: center; }
696
663
  h1 { color: #38bdf8; margin: 0; font-size: 2rem; }
697
664
  .meta { color: #94a3b8; font-size: 0.9rem; margin-top: 0.5rem; }
698
665
 
666
+ /* Persona Controls Styling */
667
+ .persona-toggle-container { background: #131c2e; padding: 0.5rem 1rem; border-radius: 8px; border: 1px solid #1e293b; display: flex; align-items: center; gap: 0.75rem; }
668
+ .persona-btn { background: #090d16; border: 1px solid #1e293b; color: #94a3b8; padding: 0.4rem 1rem; font-size: 0.85rem; font-weight: 600; border-radius: 6px; cursor: pointer; transition: all 0.2s ease; }
669
+ .persona-btn.active { background: #38bdf8; border-color: #38bdf8; color: #0b111e; }
670
+
699
671
  .cards-wrapper { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1rem; margin-bottom: 1.5rem; }
700
672
  .metric-card { background: #131c2e; border: 1px solid #1e293b; border-radius: 6px; padding: 1.25rem; position: relative; }
701
673
  .card-title { font-size: 0.75rem; font-weight: 700; color: #64748b; text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 0.5rem; }
@@ -716,7 +688,7 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
716
688
  .gauge-container-box { background: #131c2e; border: 1px solid #1e293b; border-radius: 8px; padding: 1.25rem; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; }
717
689
  .gauge-title { font-size: 0.85rem; font-weight: bold; color: #94a3b8; text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 1rem; }
718
690
 
719
- .matrix-box { background: #131c2e; border: 1px solid #1e293b; border-radius: 8px; padding: 1.25rem; }
691
+ .matrix-box { background: #131c2e; border: 1px solid #1e293b; border-radius: 8px; padding: 1.25rem; display: flex; flex-direction: column; justify-content: space-between; }
720
692
  .matrix-title { font-size: 1.1rem; font-weight: bold; color: #ffffff; margin-bottom: 1rem; }
721
693
  .matrix-box .matrix-row { display: flex; justify-content: space-between; align-items: center; padding: 0.6rem 0; border-bottom: 1px solid #1e293b; }
722
694
  .matrix-box .matrix-row:last-child { border-bottom: none; }
@@ -744,127 +716,129 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
744
716
  </style></head><body>
745
717
  <div class="container">
746
718
  <div class="header">
747
- <h1>\u{1F525} Blaze Core Performance Analysis</h1>
748
- <div class="meta">Target Script: <code>${config.targetScript}</code></div>
719
+ <div>
720
+ <h1>\u{1F525} Blaze Core Performance Analysis</h1>
721
+ <div class="meta">Target Script: <code>${config.targetScript}</code></div>
722
+ </div>
723
+
724
+ <!-- Persona View Switcher Selector Elements -->
725
+ <div class="persona-toggle-container">
726
+ <span style="font-size: 0.8rem; color: #64748b; font-weight: bold; text-transform: uppercase;">View Perspective:</span>
727
+ <button class="persona-btn active" onclick="switchPersona('developer', this)">Developer</button>
728
+ <button class="persona-btn" onclick="switchPersona('devops', this)">DevOps</button>
729
+ <button class="persona-btn" onclick="switchPersona('executive', this)">Executive</button>
730
+ </div>
749
731
  </div>
750
732
 
751
733
  <div class="cards-wrapper">
752
- <div class="metric-card">
734
+ <div class="metric-card p-dev">
753
735
  <div class="card-title">Apdex Score (T: 50ms)</div>
754
736
  <div class="card-value green">${cards.apdex.toFixed(2)}<span class="card-subtext">(Good)</span></div>
755
737
  </div>
756
- <div class="metric-card">
738
+ <div class="metric-card p-devops p-exec">
757
739
  <div class="card-title">Throughput</div>
758
740
  <div class="card-value orange">${cards.throughput.toFixed(1)}<span class="unit">/s</span></div>
759
741
  </div>
760
- <div class="metric-card">
742
+ <div class="metric-card p-devops">
761
743
  <div class="card-title">Network Bandwidth</div>
762
744
  <div class="card-value purple">${cards.bandwidth.toFixed(2)}<span class="unit">MB/s</span></div>
763
745
  </div>
764
- <div class="metric-card">
746
+ <div class="metric-card p-devops">
765
747
  <div class="card-title">Avg Time To First Byte</div>
766
748
  <div class="card-value">${cards.ttfb.toFixed(1)}<span class="unit">ms</span></div>
767
749
  </div>
768
- <div class="metric-card">
750
+ <div class="metric-card p-dev">
769
751
  <div class="card-title">DNS Lookup</div>
770
752
  <div class="card-value">${cards.dns.toFixed(2)}<span class="unit">ms</span></div>
771
753
  </div>
772
- <div class="metric-card">
754
+ <div class="metric-card p-dev">
773
755
  <div class="card-title">TCP Connect</div>
774
756
  <div class="card-value">${cards.tcp.toFixed(2)}<span class="unit">ms</span></div>
775
757
  </div>
776
- <div class="metric-card">
758
+ <div class="metric-card p-dev">
777
759
  <div class="card-title">TLS Handshake</div>
778
760
  <div class="card-value">${cards.tls.toFixed(2)}<span class="unit">ms</span></div>
779
761
  </div>
780
- <div class="metric-card">
762
+ <div class="metric-card p-dev p-exec">
781
763
  <div class="card-title">Stability (Std Dev)</div>
782
764
  <div class="card-value">&plusmn;${cards.stdDev.toFixed(1)}<span class="unit">ms</span></div>
783
765
  </div>
784
766
  </div>
785
767
 
786
768
  <div class="top-layout-grid">
787
- <div class="verdict-box">
769
+ <div class="verdict-box p-devops p-exec">
788
770
  <div class="verdict-title">\u{1F916} AI Stress-Testing Agent Verdict</div>
789
771
  <div class="verdict-text">${verdictReason}</div>
790
772
  <div class="verdict-waves">${waveListItems}</div>
791
773
  </div>
792
774
 
793
- <!-- IMPLEMENTED CARD FEATURE 76: Executive Health Gauges Panel -->
794
- <div class="gauge-container-box">
775
+ <div class="gauge-container-box p-exec p-devops">
795
776
  <div class="gauge-title">Blaze Run Health Score</div>
796
777
  <div style="position: relative; width: 140px; height: 140px; display: flex; align-items: center; justify-content: center;">
797
778
  <svg width="140" height="140" viewBox="0 0 140 140" style="transform: rotate(-90deg);">
798
779
  <circle cx="70" cy="70" r="58" stroke="#1e293b" stroke-width="12" fill="transparent"/>
799
780
  <circle cx="70" cy="70" r="58" stroke="${gaugeColor}" stroke-width="12" fill="transparent"
800
781
  stroke-dasharray="364.4" stroke-dashoffset="${364.4 - 364.4 * cards.healthScore / 100}"
801
- stroke-linecap="round" style="transition: stroke-dashoffset 1s ease-out;"/>
782
+ stroke-linecap="round"/>
802
783
  </svg>
803
784
  <div style="position: absolute; text-align: center;">
804
785
  <div style="font-size: 2.2rem; font-weight: 800; color: #ffffff; line-height: 1;">${cards.healthScore}</div>
805
786
  <div style="font-size: 0.75rem; color: #64748b; font-weight: bold; margin-top: 0.2rem; text-transform: uppercase;">/ 100</div>
806
787
  </div>
807
788
  </div>
808
- <div style="margin-top: 0.75rem; font-size: 0.8rem; color: #94a3b8; font-weight: 500;">
809
- Composite Run Quality Engine Rating
810
- </div>
811
789
  </div>
812
790
 
813
- <div class="matrix-box">
814
- <div class="matrix-title">\u{1F4CB} HTTP Response Matrix</div>
815
- <div class="matrix-row">
816
- <div class="matrix-label">Informational <span class="matrix-badge badge-1xx">1xx</span></div>
817
- <div class="matrix-value">${responseMatrix.total1xx}</div>
818
- </div>
819
- <div class="matrix-row">
820
- <div class="matrix-label">Successful <span class="matrix-badge badge-2xx">2xx</span></div>
821
- <div class="matrix-value">${responseMatrix.total2xx}</div>
822
- </div>
823
- <div class="matrix-row">
824
- <div class="matrix-label">Redirects <span class="matrix-badge badge-3xx">3xx</span></div>
825
- <div class="matrix-value">${responseMatrix.total3xx}</div>
826
- </div>
827
- <div class="matrix-row">
828
- <div class="matrix-label">Client Error <span class="matrix-badge badge-4xx">4xx</span></div>
829
- <div class="matrix-value">${responseMatrix.total4xx}</div>
830
- </div>
831
- <div class="matrix-row">
832
- <div class="matrix-label">Server Error <span class="matrix-badge badge-5xx">5xx</span></div>
833
- <div class="matrix-value">${responseMatrix.total5xx}</div>
791
+ <div class="matrix-box p-devops p-dev">
792
+ <div>
793
+ <div class="matrix-title">\u{1F4CB} HTTP Response Matrix</div>
794
+ <div class="matrix-row">
795
+ <div class="matrix-label">Successful <span class="matrix-badge badge-2xx">2xx</span></div>
796
+ <div class="matrix-value">${responseMatrix.total2xx}</div>
797
+ </div>
798
+ <div class="matrix-row">
799
+ <div class="matrix-label">Client Error <span class="matrix-badge badge-4xx">4xx</span></div>
800
+ <div class="matrix-value">${responseMatrix.total4xx}</div>
801
+ </div>
802
+ <div class="matrix-row">
803
+ <div class="matrix-label">Server Error <span class="matrix-badge badge-5xx">5xx</span></div>
804
+ <div class="matrix-value">${responseMatrix.total5xx}</div>
805
+ </div>
834
806
  </div>
835
807
 
836
- <div class="matrix-title" style="margin-top: 1.5rem; font-size: 0.85rem; border-top: 1px solid #1e293b; padding-top: 1rem; color: #94a3b8; text-transform: uppercase; letter-spacing: 0.05em;">
837
- \u{1F522} HTTP Status Code Breakdown Rate
838
- </div>
839
- <div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.5rem; margin-top: 0.5rem;">
840
- ${breakdownGridHtml}
808
+ <div>
809
+ <div class="matrix-title" style="margin-top: 1.5rem; font-size: 0.85rem; border-top: 1px solid #1e293b; padding-top: 1rem; color: #94a3b8; text-transform: uppercase; letter-spacing: 0.05em;">
810
+ \u{1F522} HTTP Status Code Breakdown Rate
811
+ </div>
812
+ <div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.5rem; margin-top: 0.5rem;">
813
+ ${breakdownGridHtml}
814
+ </div>
841
815
  </div>
842
816
  </div>
843
817
  </div>
844
818
 
845
819
  <div class="charts-grid">
846
- <div class="graph-card">
820
+ <div class="graph-card p-devops">
847
821
  <div class="graph-title">\u{1F4CA} Throughput Velocity & Workload Volume</div>
848
822
  <div style="height: 280px; position: relative;">
849
823
  <canvas id="volumeChart"></canvas>
850
824
  </div>
851
825
  </div>
852
826
 
853
- <div class="graph-card">
827
+ <div class="graph-card p-devops">
854
828
  <div class="graph-title">\u{1F504} Active Concurrency (VUs) vs. TTF Trend</div>
855
829
  <div style="height: 280px; position: relative;">
856
830
  <canvas id="concurrencyChart"></canvas>
857
831
  </div>
858
832
  </div>
859
833
 
860
- <div class="graph-card">
834
+ <div class="graph-card p-dev">
861
835
  <div class="graph-title">\u{1F369} HTTP Status Code Proportions</div>
862
836
  <div style="height: 280px; position: relative;">
863
837
  <canvas id="statusDonutChart"></canvas>
864
838
  </div>
865
839
  </div>
866
840
 
867
- <div class="graph-card">
841
+ <div class="graph-card p-dev">
868
842
  <div class="graph-title">\u{1F4C8} Time-to-First-Byte Scatter Plot</div>
869
843
  <div style="height: 280px; position: relative;">
870
844
  <canvas id="ttfbScatterChart"></canvas>
@@ -872,7 +846,7 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
872
846
  </div>
873
847
  </div>
874
848
 
875
- <div class="card">
849
+ <div class="card p-dev">
876
850
  <h3>Telemetry Matrix Logs</h3>
877
851
  <table>
878
852
  <thead>
@@ -881,7 +855,6 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
881
855
  <th>Throughput</th>
882
856
  <th>Avg Latency</th>
883
857
  <th>P95 Latency</th>
884
- <th>Error Rate</th>
885
858
  <th>Status</th>
886
859
  </tr>
887
860
  </thead>
@@ -893,7 +866,6 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
893
866
  <td>${h.throughput.toFixed(0)} req/sec</td>
894
867
  <td>${h.avgLatency.toFixed(1)} ms</td>
895
868
  <td>${h.p95Latency.toFixed(1)} ms</td>
896
- <td>${(h.errorRate * 100).toFixed(2)}%</td>
897
869
  <td><span class="badge ${isPassed ? "badge-success" : "badge-fail"}">${isPassed ? "SLO PASS" : "SLO BREACH"}</span></td>
898
870
  </tr>`;
899
871
  }).join("")}
@@ -909,142 +881,93 @@ function exportHtmlDashboard(history, config, verdictReason, semanticReport, res
909
881
  <script>
910
882
  const labels = ${JSON.stringify(labels)};
911
883
  const baseThroughput = ${cards.throughput};
912
- const baseLatency = ${cards.ttfb};
913
884
 
914
885
  const slider = document.getElementById('concurrencySlider');
915
886
  const sliderVal = document.getElementById('sliderValue');
916
887
  const simThroughput = document.getElementById('simThroughput');
917
- const simLatency = document.getElementById('simLatency');
918
888
 
919
- slider.addEventListener('input', (e) => {
920
- const val = parseInt(e.target.value, 10);
921
- sliderVal.textContent = val;
922
- const factor = val / ${config.threads || 10};
923
- simThroughput.textContent = (baseThroughput * Math.min(factor, 2.5)).toFixed(0) + '/s';
924
- simLatency.textContent = (baseLatency * Math.pow(factor, 0.8)).toFixed(1) + 'ms';
925
- });
889
+ if(slider) {
890
+ slider.addEventListener('input', (e) => {
891
+ const val = parseInt(e.target.value, 10);
892
+ sliderVal.textContent = val;
893
+ const factor = val / ${config.threads || 10};
894
+ simThroughput.textContent = (baseThroughput * Math.min(factor, 2.5)).toFixed(0) + '/s';
895
+ });
896
+ }
897
+
898
+ // Global register tracking charts for explicit redraw logic execution
899
+ const activeCharts = [];
900
+
901
+ function switchPersona(persona, targetBtn) {
902
+ if (targetBtn) {
903
+ document.querySelectorAll('.persona-btn').forEach(btn => btn.classList.remove('active'));
904
+ targetBtn.classList.add('active');
905
+ }
906
+
907
+ // Hide all dynamic viewport configurations
908
+ const layouts = ['.p-dev', '.p-devops', '.p-exec'];
909
+ layouts.forEach(selector => {
910
+ document.querySelectorAll(selector).forEach(el => el.style.display = 'none');
911
+ });
912
+
913
+ // Target current selector views for block visibility execution
914
+ document.querySelectorAll('.p-' + persona).forEach(el => {
915
+ if (el.tagName === 'TR') el.style.display = 'table-row';
916
+ else if (el.classList.contains('metric-card')) el.style.display = 'block';
917
+ else el.style.display = '';
918
+ });
919
+
920
+ // AUTO-REFRESH IMPLEMENTATION: Triggers sizing layout re-calculations on unhidden canvases
921
+ activeCharts.forEach(chart => {
922
+ if (chart) {
923
+ chart.resize();
924
+ chart.update('active');
925
+ }
926
+ });
927
+ }
926
928
 
927
- new Chart(document.getElementById('volumeChart'), {
929
+ activeCharts.push(new Chart(document.getElementById('volumeChart'), {
928
930
  type: 'bar',
929
931
  data: {
930
932
  labels: labels,
931
933
  datasets: [
932
- {
933
- label: 'Successful Requests',
934
- data: ${JSON.stringify(successRequestsData)},
935
- backgroundColor: '#10b981',
936
- stack: 'requests',
937
- barPercentage: 0.95,
938
- categoryPercentage: 0.95
939
- },
940
- {
941
- label: 'Failed Workloads',
942
- data: ${JSON.stringify(failedWorkloadsData)},
943
- backgroundColor: '#ef4444',
944
- stack: 'requests',
945
- barPercentage: 0.95,
946
- categoryPercentage: 0.95
947
- }
934
+ { label: 'Successful Requests', data: ${JSON.stringify(successRequestsData)}, backgroundColor: '#10b981', stack: 'requests' },
935
+ { label: 'Failed Workloads', data: ${JSON.stringify(failedWorkloadsData)}, backgroundColor: '#ef4444', stack: 'requests' }
948
936
  ]
949
937
  },
950
- options: {
951
- responsive: true,
952
- maintainAspectRatio: false,
953
- plugins: {
954
- legend: { position: 'top', labels: { color: '#94a3b8', font: { size: 11 } } }
955
- },
956
- scales: {
957
- x: { grid: { color: '#1e293b' }, ticks: { color: '#64748b' } },
958
- y: { stacked: true, grid: { color: '#1e293b' }, ticks: { color: '#64748b' } }
959
- }
960
- }
961
- });
938
+ options: { responsive: true, maintainAspectRatio: false, scales: { x: { grid: { color: '#1e293b' } }, y: { stacked: true, grid: { color: '#1e293b' } } } }
939
+ }));
962
940
 
963
- new Chart(document.getElementById('concurrencyChart'), {
941
+ activeCharts.push(new Chart(document.getElementById('concurrencyChart'), {
964
942
  type: 'line',
965
943
  data: {
966
944
  labels: labels,
967
945
  datasets: [
968
- {
969
- label: 'Active VU Threads',
970
- data: ${JSON.stringify(activeThreadsData)},
971
- borderColor: '#38bdf8',
972
- backgroundColor: 'rgba(56, 189, 248, 0.1)',
973
- borderWidth: 2.5,
974
- pointRadius: 4,
975
- fill: true,
976
- yAxisID: 'yThreads'
977
- },
978
- {
979
- label: 'Time-to-Failure (TTF) Trend',
980
- data: ${JSON.stringify(ttfTrendData)},
981
- borderColor: '#f43f5e',
982
- borderWidth: 2,
983
- borderDash: [5, 5],
984
- pointRadius: 3,
985
- fill: false,
986
- yAxisID: 'yTtf'
987
- }
946
+ { label: 'Active VU Threads', data: ${JSON.stringify(activeThreadsData)}, borderColor: '#38bdf8', yAxisID: 'yThreads' },
947
+ { label: 'Time-to-Failure Trend', data: ${JSON.stringify(ttfTrendData)}, borderColor: '#f43f5e', yAxisID: 'yTtf' }
988
948
  ]
989
949
  },
990
- options: {
991
- responsive: true,
992
- maintainAspectRatio: false,
993
- plugins: {
994
- legend: { position: 'top', labels: { color: '#94a3b8', font: { size: 11 } } }
995
- },
996
- scales: {
997
- x: { grid: { color: '#1e293b' }, ticks: { color: '#64748b' } },
998
- y_threads: { position: 'left', grid: { color: '#1e293b' }, ticks: { color: '#38bdf8' }, title: { display: true, text: 'VUs / Threads', color: '#38bdf8' } },
999
- y_ttf: { position: 'right', grid: { drawOnChartArea: false }, ticks: { color: '#f43f5e' }, title: { display: true, text: 'TTF Index / Latency ms', color: '#f43f5e' } }
1000
- }
1001
- }
1002
- });
950
+ options: { responsive: true, maintainAspectRatio: false }
951
+ }));
1003
952
 
1004
- new Chart(document.getElementById('statusDonutChart'), {
953
+ activeCharts.push(new Chart(document.getElementById('statusDonutChart'), {
1005
954
  type: 'doughnut',
1006
955
  data: {
1007
- labels: ['1xx Info', '2xx Success', '3xx Redirect', '4xx Client Err', '5xx Server Err'],
1008
- datasets: [{
1009
- data: [${responseMatrix.total1xx}, ${responseMatrix.total2xx}, ${responseMatrix.total3xx}, ${responseMatrix.total4xx}, ${responseMatrix.total5xx}],
1010
- backgroundColor: ['#38bdf8', '#4ade80', '#cbd5e1', '#fde047', '#f87171'],
1011
- borderWidth: 1,
1012
- borderColor: '#1e293b'
1013
- }]
956
+ labels: ['Success', 'Client Err', 'Server Err'],
957
+ datasets: [{ data: [${responseMatrix.total2xx}, ${responseMatrix.total4xx}, ${responseMatrix.total5xx}], backgroundColor: ['#4ade80', '#fde047', '#f87171'] }]
1014
958
  },
1015
- options: {
1016
- responsive: true,
1017
- maintainAspectRatio: false,
1018
- plugins: {
1019
- legend: { position: 'top', labels: { color: '#94a3b8', font: { size: 11 } } },
1020
- cutout: '65%'
1021
- }
1022
- }
1023
- });
959
+ options: { responsive: true, maintainAspectRatio: false }
960
+ }));
1024
961
 
1025
- new Chart(document.getElementById('ttfbScatterChart'), {
962
+ activeCharts.push(new Chart(document.getElementById('ttfbScatterChart'), {
1026
963
  type: 'scatter',
1027
- data: {
1028
- datasets: [{
1029
- label: 'Request Processing Delay',
1030
- data: ${JSON.stringify(scatterPoints)},
1031
- backgroundColor: '#a855f7',
1032
- pointRadius: 4,
1033
- pointHoverRadius: 6
1034
- }]
1035
- },
1036
- options: {
1037
- responsive: true,
1038
- maintainAspectRatio: false,
1039
- plugins: {
1040
- legend: { position: 'top', labels: { color: '#94a3b8', font: { size: 11 } } }
1041
- },
1042
- scales: {
1043
- x: { grid: { color: '#1e293b' }, ticks: { color: '#64748b' }, title: { display: true, text: 'Time offset (s)', color: '#64748b' } },
1044
- y: { grid: { color: '#1e293b' }, ticks: { color: '#64748b' }, title: { display: true, text: 'TTFB / Delay (ms)', color: '#64748b' } }
1045
- }
1046
- }
1047
- });
964
+ data: { datasets: [{ label: 'Processing Delay', data: ${JSON.stringify(scatterPoints)}, backgroundColor: '#a855f7' }] },
965
+ options: { responsive: true, maintainAspectRatio: false }
966
+ }));
967
+
968
+ // Bootstrapped configuration state defaults dashboard load view to Developer
969
+ document.querySelectorAll('.p-devops, .p-exec').forEach(el => el.style.display = 'none');
970
+ document.querySelectorAll('.p-dev').forEach(el => el.style.display = '');
1048
971
  </script></body></html>`;
1049
972
  try {
1050
973
  fs.writeFileSync(config.outputHtml, htmlContent, "utf-8");
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blaze-performance-tester",
3
- "version": "3.1.22",
3
+ "version": "3.1.24",
4
4
  "description": "A high-performance, multi-threaded load testing engine built with Rust and QuickJS.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",